diff --git a/app/app.go b/app/app.go index 310b7bbc..3843469b 100644 --- a/app/app.go +++ b/app/app.go @@ -597,6 +597,17 @@ func NewApp( app.bankKeeper, &app.stakingKeeper, ) + earnKeeper := earnkeeper.NewKeeper( + appCodec, + keys[earntypes.StoreKey], + earnSubspace, + app.accountKeeper, + app.bankKeeper, + &app.liquidKeeper, + &hardKeeper, + &savingsKeeper, + ) + app.incentiveKeeper = incentivekeeper.NewKeeper( appCodec, keys[incentivetypes.StoreKey], @@ -608,16 +619,7 @@ func NewApp( app.stakingKeeper, &swapKeeper, &savingsKeeper, - ) - app.earnKeeper = earnkeeper.NewKeeper( - appCodec, - keys[earntypes.StoreKey], - earnSubspace, - app.accountKeeper, - app.bankKeeper, - app.liquidKeeper, - &hardKeeper, - &savingsKeeper, + &earnKeeper, ) // create committee keeper with router @@ -667,6 +669,7 @@ func NewApp( app.cdpKeeper = *cdpKeeper.SetHooks(cdptypes.NewMultiCDPHooks(app.incentiveKeeper.Hooks())) app.hardKeeper = *hardKeeper.SetHooks(hardtypes.NewMultiHARDHooks(app.incentiveKeeper.Hooks())) app.savingsKeeper = *savingsKeeper.SetHooks(savingstypes.NewMultiSavingsHooks(app.incentiveKeeper.Hooks())) + app.earnKeeper = *earnKeeper.SetHooks(app.incentiveKeeper.Hooks()) // create the module manager (Note: Any module instantiated in the module manager that is later modified // must be passed by reference here.) diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index 5ccc403c..3e8d03ad 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -302,6 +302,7 @@ - [BaseClaim](#kava.incentive.v1beta1.BaseClaim) - [BaseMultiClaim](#kava.incentive.v1beta1.BaseMultiClaim) - [DelegatorClaim](#kava.incentive.v1beta1.DelegatorClaim) + - [EarnClaim](#kava.incentive.v1beta1.EarnClaim) - [HardLiquidityProviderClaim](#kava.incentive.v1beta1.HardLiquidityProviderClaim) - [MultiRewardIndex](#kava.incentive.v1beta1.MultiRewardIndex) - [MultiRewardIndexesProto](#kava.incentive.v1beta1.MultiRewardIndexesProto) @@ -326,6 +327,8 @@ - [kava/incentive/v1beta1/tx.proto](#kava/incentive/v1beta1/tx.proto) - [MsgClaimDelegatorReward](#kava.incentive.v1beta1.MsgClaimDelegatorReward) - [MsgClaimDelegatorRewardResponse](#kava.incentive.v1beta1.MsgClaimDelegatorRewardResponse) + - [MsgClaimEarnReward](#kava.incentive.v1beta1.MsgClaimEarnReward) + - [MsgClaimEarnRewardResponse](#kava.incentive.v1beta1.MsgClaimEarnRewardResponse) - [MsgClaimHardReward](#kava.incentive.v1beta1.MsgClaimHardReward) - [MsgClaimHardRewardResponse](#kava.incentive.v1beta1.MsgClaimHardRewardResponse) - [MsgClaimSavingsReward](#kava.incentive.v1beta1.MsgClaimSavingsReward) @@ -4353,6 +4356,22 @@ DelegatorClaim stores delegation rewards that can be claimed by owner + + +### EarnClaim +EarnClaim stores the earn rewards that can be claimed by owner + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `base_claim` | [BaseMultiClaim](#kava.incentive.v1beta1.BaseMultiClaim) | | | +| `reward_indexes` | [MultiRewardIndex](#kava.incentive.v1beta1.MultiRewardIndex) | repeated | | + + + + + + ### HardLiquidityProviderClaim @@ -4564,6 +4583,7 @@ Params | `claim_multipliers` | [MultipliersPerDenom](#kava.incentive.v1beta1.MultipliersPerDenom) | repeated | | | `claim_end` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | | | `savings_reward_periods` | [MultiRewardPeriod](#kava.incentive.v1beta1.MultiRewardPeriod) | repeated | | +| `earn_reward_periods` | [MultiRewardPeriod](#kava.incentive.v1beta1.MultiRewardPeriod) | repeated | | @@ -4657,6 +4677,8 @@ GenesisState is the state that must be provided at genesis. | `swap_claims` | [SwapClaim](#kava.incentive.v1beta1.SwapClaim) | repeated | | | `savings_reward_state` | [GenesisRewardState](#kava.incentive.v1beta1.GenesisRewardState) | | | | `savings_claims` | [SavingsClaim](#kava.incentive.v1beta1.SavingsClaim) | repeated | | +| `earn_reward_state` | [GenesisRewardState](#kava.incentive.v1beta1.GenesisRewardState) | | | +| `earn_claims` | [EarnClaim](#kava.incentive.v1beta1.EarnClaim) | repeated | | @@ -4705,6 +4727,32 @@ MsgClaimDelegatorRewardResponse defines the Msg/ClaimDelegatorReward response ty + + +### MsgClaimEarnReward +MsgClaimEarnReward message type used to claim earn rewards + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `sender` | [string](#string) | | | +| `denoms_to_claim` | [Selection](#kava.incentive.v1beta1.Selection) | repeated | | + + + + + + + + +### MsgClaimEarnRewardResponse +MsgClaimEarnRewardResponse defines the Msg/ClaimEarnReward response type. + + + + + + ### MsgClaimHardReward @@ -4842,8 +4890,9 @@ Msg defines the incentive Msg service. | `ClaimUSDXMintingReward` | [MsgClaimUSDXMintingReward](#kava.incentive.v1beta1.MsgClaimUSDXMintingReward) | [MsgClaimUSDXMintingRewardResponse](#kava.incentive.v1beta1.MsgClaimUSDXMintingRewardResponse) | ClaimUSDXMintingReward is a message type used to claim USDX minting rewards | | | `ClaimHardReward` | [MsgClaimHardReward](#kava.incentive.v1beta1.MsgClaimHardReward) | [MsgClaimHardRewardResponse](#kava.incentive.v1beta1.MsgClaimHardRewardResponse) | ClaimHardReward is a message type used to claim Hard liquidity provider rewards | | | `ClaimDelegatorReward` | [MsgClaimDelegatorReward](#kava.incentive.v1beta1.MsgClaimDelegatorReward) | [MsgClaimDelegatorRewardResponse](#kava.incentive.v1beta1.MsgClaimDelegatorRewardResponse) | ClaimDelegatorReward is a message type used to claim delegator rewards | | -| `ClaimSwapReward` | [MsgClaimSwapReward](#kava.incentive.v1beta1.MsgClaimSwapReward) | [MsgClaimSwapRewardResponse](#kava.incentive.v1beta1.MsgClaimSwapRewardResponse) | ClaimSwapReward is a message type used to claim delegator rewards | | +| `ClaimSwapReward` | [MsgClaimSwapReward](#kava.incentive.v1beta1.MsgClaimSwapReward) | [MsgClaimSwapRewardResponse](#kava.incentive.v1beta1.MsgClaimSwapRewardResponse) | ClaimSwapReward is a message type used to claim swap rewards | | | `ClaimSavingsReward` | [MsgClaimSavingsReward](#kava.incentive.v1beta1.MsgClaimSavingsReward) | [MsgClaimSavingsRewardResponse](#kava.incentive.v1beta1.MsgClaimSavingsRewardResponse) | ClaimSavingsReward is a message type used to claim savings rewards | | +| `ClaimEarnReward` | [MsgClaimEarnReward](#kava.incentive.v1beta1.MsgClaimEarnReward) | [MsgClaimEarnRewardResponse](#kava.incentive.v1beta1.MsgClaimEarnRewardResponse) | ClaimEarnReward is a message type used to claim earn rewards | | diff --git a/proto/kava/incentive/v1beta1/claims.proto b/proto/kava/incentive/v1beta1/claims.proto index 31c956c8..df28d2cc 100644 --- a/proto/kava/incentive/v1beta1/claims.proto +++ b/proto/kava/incentive/v1beta1/claims.proto @@ -115,3 +115,13 @@ message SavingsClaim { repeated MultiRewardIndex reward_indexes = 2 [(gogoproto.castrepeated) = "MultiRewardIndexes", (gogoproto.nullable) = false]; } + +// EarnClaim stores the earn rewards that can be claimed by owner +message EarnClaim { + option (cosmos_proto.implements_interface) = "Claim"; + + BaseMultiClaim base_claim = 1 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; + + repeated MultiRewardIndex reward_indexes = 2 + [(gogoproto.castrepeated) = "MultiRewardIndexes", (gogoproto.nullable) = false]; +} diff --git a/proto/kava/incentive/v1beta1/genesis.proto b/proto/kava/incentive/v1beta1/genesis.proto index d2119f64..451bc226 100644 --- a/proto/kava/incentive/v1beta1/genesis.proto +++ b/proto/kava/incentive/v1beta1/genesis.proto @@ -60,4 +60,8 @@ message GenesisState { GenesisRewardState savings_reward_state = 11 [(gogoproto.nullable) = false]; repeated SavingsClaim savings_claims = 12 [(gogoproto.castrepeated) = "SavingsClaims", (gogoproto.nullable) = false]; + + GenesisRewardState earn_reward_state = 13 [(gogoproto.nullable) = false]; + + repeated EarnClaim earn_claims = 14 [(gogoproto.castrepeated) = "EarnClaims", (gogoproto.nullable) = false]; } diff --git a/proto/kava/incentive/v1beta1/params.proto b/proto/kava/incentive/v1beta1/params.proto index 5a010fcb..e35d0bc5 100644 --- a/proto/kava/incentive/v1beta1/params.proto +++ b/proto/kava/incentive/v1beta1/params.proto @@ -79,4 +79,7 @@ message Params { repeated MultiRewardPeriod savings_reward_periods = 8 [(gogoproto.castrepeated) = "MultiRewardPeriods", (gogoproto.nullable) = false]; + + repeated MultiRewardPeriod earn_reward_periods = 9 + [(gogoproto.castrepeated) = "MultiRewardPeriods", (gogoproto.nullable) = false]; } diff --git a/proto/kava/incentive/v1beta1/tx.proto b/proto/kava/incentive/v1beta1/tx.proto index 0eef7bad..5d83e898 100644 --- a/proto/kava/incentive/v1beta1/tx.proto +++ b/proto/kava/incentive/v1beta1/tx.proto @@ -16,11 +16,14 @@ service Msg { // ClaimDelegatorReward is a message type used to claim delegator rewards rpc ClaimDelegatorReward(MsgClaimDelegatorReward) returns (MsgClaimDelegatorRewardResponse); - // ClaimSwapReward is a message type used to claim delegator rewards + // ClaimSwapReward is a message type used to claim swap rewards rpc ClaimSwapReward(MsgClaimSwapReward) returns (MsgClaimSwapRewardResponse); // ClaimSavingsReward is a message type used to claim savings rewards rpc ClaimSavingsReward(MsgClaimSavingsReward) returns (MsgClaimSavingsRewardResponse); + + // ClaimEarnReward is a message type used to claim earn rewards + rpc ClaimEarnReward(MsgClaimEarnReward) returns (MsgClaimEarnRewardResponse); } // Selection is a pair of denom and multiplier name. It holds the choice of multiplier a user makes when they claim a @@ -92,3 +95,15 @@ message MsgClaimSavingsReward { // MsgClaimSavingsRewardResponse defines the Msg/ClaimSavingsReward response type. message MsgClaimSavingsRewardResponse {} + +// MsgClaimEarnReward message type used to claim earn rewards +message MsgClaimEarnReward { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string sender = 1; + repeated Selection denoms_to_claim = 2 [(gogoproto.castrepeated) = "Selections", (gogoproto.nullable) = false]; +} + +// MsgClaimEarnRewardResponse defines the Msg/ClaimEarnReward response type. +message MsgClaimEarnRewardResponse {} diff --git a/x/earn/types/expected_keepers.go b/x/earn/types/expected_keepers.go index 8193cb51..df654e60 100644 --- a/x/earn/types/expected_keepers.go +++ b/x/earn/types/expected_keepers.go @@ -48,6 +48,6 @@ type SavingsKeeper interface { // EarnHooks are event hooks called when a user's deposit to a earn vault changes. type EarnHooks interface { - AfterVaultDepositCreated(ctx sdk.Context, vaultDenom string, depositor sdk.AccAddress, sharedOwned sdk.Dec) - BeforeVaultDepositModified(ctx sdk.Context, vaultDenom string, depositor sdk.AccAddress, sharedOwned sdk.Dec) + AfterVaultDepositCreated(ctx sdk.Context, vaultDenom string, depositor sdk.AccAddress, sharesOwned sdk.Dec) + BeforeVaultDepositModified(ctx sdk.Context, vaultDenom string, depositor sdk.AccAddress, sharesOwned sdk.Dec) } diff --git a/x/earn/types/mocks/EarnHooks.go b/x/earn/types/mocks/EarnHooks.go index 35df4a26..97df2f16 100644 --- a/x/earn/types/mocks/EarnHooks.go +++ b/x/earn/types/mocks/EarnHooks.go @@ -12,14 +12,14 @@ type EarnHooks struct { mock.Mock } -// AfterVaultDepositCreated provides a mock function with given fields: ctx, vaultDenom, depositor, sharedOwned -func (_m *EarnHooks) AfterVaultDepositCreated(ctx types.Context, vaultDenom string, depositor types.AccAddress, sharedOwned types.Dec) { - _m.Called(ctx, vaultDenom, depositor, sharedOwned) +// AfterVaultDepositCreated provides a mock function with given fields: ctx, vaultDenom, depositor, sharesOwned +func (_m *EarnHooks) AfterVaultDepositCreated(ctx types.Context, vaultDenom string, depositor types.AccAddress, sharesOwned types.Dec) { + _m.Called(ctx, vaultDenom, depositor, sharesOwned) } -// BeforeVaultDepositModified provides a mock function with given fields: ctx, vaultDenom, depositor, sharedOwned -func (_m *EarnHooks) BeforeVaultDepositModified(ctx types.Context, vaultDenom string, depositor types.AccAddress, sharedOwned types.Dec) { - _m.Called(ctx, vaultDenom, depositor, sharedOwned) +// BeforeVaultDepositModified provides a mock function with given fields: ctx, vaultDenom, depositor, sharesOwned +func (_m *EarnHooks) BeforeVaultDepositModified(ctx types.Context, vaultDenom string, depositor types.AccAddress, sharesOwned types.Dec) { + _m.Called(ctx, vaultDenom, depositor, sharesOwned) } type mockConstructorTestingTNewEarnHooks interface { diff --git a/x/incentive/abci.go b/x/incentive/abci.go index 92306e6b..7e8b6407 100644 --- a/x/incentive/abci.go +++ b/x/incentive/abci.go @@ -28,4 +28,7 @@ func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { for _, rp := range params.SavingsRewardPeriods { k.AccumulateSavingsRewards(ctx, rp) } + for _, rp := range params.EarnRewardPeriods { + k.AccumulateEarnRewards(ctx, rp) + } } diff --git a/x/incentive/client/cli/query.go b/x/incentive/client/cli/query.go index 367ec686..248d27b5 100644 --- a/x/incentive/client/cli/query.go +++ b/x/incentive/client/cli/query.go @@ -25,9 +25,10 @@ const ( typeUSDXMinting = "usdx-minting" typeSwap = "swap" typeSavings = "savings" + typeEarn = "earn" ) -var rewardTypes = []string{typeDelegator, typeHard, typeUSDXMinting, typeSwap} +var rewardTypes = []string{typeDelegator, typeHard, typeUSDXMinting, typeSwap, typeEarn} // GetQueryCmd returns the cli query commands for the incentive module func GetQueryCmd() *cobra.Command { @@ -59,20 +60,17 @@ func queryRewardsCmd() *cobra.Command { fmt.Sprintf(`Query rewards with optional flags for owner and type Example: - $ %s query %s rewards - $ %s query %s rewards --owner kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw - $ %s query %s rewards --type hard - $ %s query %s rewards --type usdx-minting - $ %s query %s rewards --type delegator - $ %s query %s rewards --type swap - $ %s query %s rewards --type savings - $ %s query %s rewards --type hard --owner kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw - $ %s query %s rewards --type hard --unsynced + $ %[1]s query %[2]s rewards + $ %[1]s query %[2]s rewards --owner kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw + $ %[1]s query %[2]s rewards --type hard + $ %[1]s query %[2]s rewards --type usdx-minting + $ %[1]s query %[2]s rewards --type delegator + $ %[1]s query %[2]s rewards --type swap + $ %[1]s query %[2]s rewards --type savings + $ %[1]s query %[2]s rewards --type earn + $ %[1]s query %[2]s rewards --type hard --owner kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw + $ %[1]s query %[2]s rewards --type hard --unsynced `, - version.AppName, types.ModuleName, version.AppName, types.ModuleName, - version.AppName, types.ModuleName, version.AppName, types.ModuleName, - version.AppName, types.ModuleName, version.AppName, types.ModuleName, - version.AppName, types.ModuleName, version.AppName, types.ModuleName, version.AppName, types.ModuleName)), Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { @@ -131,6 +129,13 @@ func queryRewardsCmd() *cobra.Command { return err } return cliCtx.PrintObjectLegacy(claims) + case typeEarn: + params := types.NewQueryRewardsParams(page, limit, owner, boolUnsynced) + claims, err := executeEarnRewardsQuery(cliCtx, params) + if err != nil { + return err + } + return cliCtx.PrintObjectLegacy(claims) default: params := types.NewQueryRewardsParams(page, limit, owner, boolUnsynced) @@ -362,3 +367,25 @@ func executeSavingsRewardsQuery(cliCtx client.Context, params types.QueryRewards return claims, nil } + +func executeEarnRewardsQuery(cliCtx client.Context, params types.QueryRewardsParams) (types.EarnClaims, error) { + bz, err := cliCtx.LegacyAmino.MarshalJSON(params) + if err != nil { + return types.EarnClaims{}, err + } + + route := fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryGetEarnRewards) + res, height, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return types.EarnClaims{}, err + } + + cliCtx = cliCtx.WithHeight(height) + + var claims types.EarnClaims + if err := cliCtx.LegacyAmino.UnmarshalJSON(res, &claims); err != nil { + return types.EarnClaims{}, fmt.Errorf("failed to unmarshal claims: %w", err) + } + + return claims, nil +} diff --git a/x/incentive/client/rest/query.go b/x/incentive/client/rest/query.go index fa086bbb..437b79ec 100644 --- a/x/incentive/client/rest/query.go +++ b/x/incentive/client/rest/query.go @@ -68,6 +68,8 @@ func queryRewardsHandlerFn(cliCtx client.Context) http.HandlerFunc { executeDelegatorRewardsQuery(w, cliCtx, params) case "swap": executeSwapRewardsQuery(w, cliCtx, params) + case "earn": + executeEarnRewardsQuery(w, cliCtx, params) default: executeAllRewardQueries(w, cliCtx, params) } @@ -182,6 +184,23 @@ func executeSwapRewardsQuery(w http.ResponseWriter, cliCtx client.Context, param rest.PostProcessResponse(w, cliCtx, res) } +func executeEarnRewardsQuery(w http.ResponseWriter, cliCtx client.Context, params types.QueryRewardsParams) { + bz, err := cliCtx.LegacyAmino.MarshalJSON(params) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err)) + return + } + + res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetEarnRewards), bz) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, res) +} + func executeAllRewardQueries(w http.ResponseWriter, cliCtx client.Context, params types.QueryRewardsParams) { paramsBz, err := cliCtx.LegacyAmino.MarshalJSON(params) if err != nil { @@ -212,7 +231,7 @@ func executeAllRewardQueries(w http.ResponseWriter, cliCtx client.Context, param var delegatorClaims types.DelegatorClaims cliCtx.LegacyAmino.MustUnmarshalJSON(delegatorRes, &delegatorClaims) - swapRes, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetSwapRewards), paramsBz) + swapRes, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetSwapRewards), paramsBz) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return @@ -220,6 +239,14 @@ func executeAllRewardQueries(w http.ResponseWriter, cliCtx client.Context, param var swapClaims types.SwapClaims cliCtx.LegacyAmino.MustUnmarshalJSON(swapRes, &swapClaims) + earnRes, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetEarnRewards), paramsBz) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + var earnClaims types.EarnClaims + cliCtx.LegacyAmino.MustUnmarshalJSON(earnRes, &earnClaims) + cliCtx = cliCtx.WithHeight(height) type rewardResult struct { @@ -227,6 +254,7 @@ func executeAllRewardQueries(w http.ResponseWriter, cliCtx client.Context, param UsdxMintingClaims types.USDXMintingClaims `json:"usdx_minting_claims" yaml:"usdx_minting_claims"` DelegatorClaims types.DelegatorClaims `json:"delegator_claims" yaml:"delegator_claims"` SwapClaims types.SwapClaims `json:"swap_claims" yaml:"swap_claims"` + EarnClaims types.EarnClaims `json:"earn_claims" yaml:"earn_claims"` } res := rewardResult{ @@ -234,6 +262,7 @@ func executeAllRewardQueries(w http.ResponseWriter, cliCtx client.Context, param UsdxMintingClaims: usdxMintingClaims, DelegatorClaims: delegatorClaims, SwapClaims: swapClaims, + EarnClaims: earnClaims, } resBz, err := cliCtx.LegacyAmino.MarshalJSON(res) diff --git a/x/incentive/client/rest/tx.go b/x/incentive/client/rest/tx.go index dd7fe70a..61b2da78 100644 --- a/x/incentive/client/rest/tx.go +++ b/x/incentive/client/rest/tx.go @@ -20,6 +20,7 @@ func registerTxRoutes(cliCtx client.Context, r *mux.Router) { r.HandleFunc("/incentive/claim-hard", postClaimHandlerFn(cliCtx, hardGenerator)).Methods("POST") r.HandleFunc("/incentive/claim-delegator", postClaimHandlerFn(cliCtx, delegatorGenerator)).Methods("POST") r.HandleFunc("/incentive/claim-swap", postClaimHandlerFn(cliCtx, swapGenerator)).Methods("POST") + r.HandleFunc("/incentive/claim-earn", postClaimHandlerFn(cliCtx, earnGenerator)).Methods("POST") } func usdxMintingGenerator(req PostClaimReq) (sdk.Msg, error) { @@ -45,6 +46,11 @@ func swapGenerator(req PostClaimReq) (sdk.Msg, error) { return &msg, nil } +func earnGenerator(req PostClaimReq) (sdk.Msg, error) { + msg := types.NewMsgClaimEarnReward(req.Sender.String(), req.DenomsToClaim) + return &msg, nil +} + func postClaimHandlerFn(cliCtx client.Context, msgGenerator func(req PostClaimReq) (sdk.Msg, error)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var requestBody PostClaimReq diff --git a/x/incentive/genesis.go b/x/incentive/genesis.go index 2fd89939..6f2580ff 100644 --- a/x/incentive/genesis.go +++ b/x/incentive/genesis.go @@ -126,6 +126,20 @@ func InitGenesis( for _, mri := range gs.SavingsRewardState.MultiRewardIndexes { k.SetSavingsRewardIndexes(ctx, mri.CollateralType, mri.RewardIndexes) } + + // Earn + for _, claim := range gs.EarnClaims { + k.SetEarnClaim(ctx, claim) + } + for _, gat := range gs.EarnRewardState.AccumulationTimes { + if err := ValidateAccumulationTime(gat.PreviousAccumulationTime, ctx.BlockTime()); err != nil { + panic(err.Error()) + } + k.SetEarnRewardAccrualTime(ctx, gat.CollateralType, gat.PreviousAccumulationTime) + } + for _, mri := range gs.EarnRewardState.MultiRewardIndexes { + k.SetEarnRewardIndexes(ctx, mri.CollateralType, mri.RewardIndexes) + } } // ExportGenesis export genesis state for incentive module @@ -148,10 +162,15 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState { savingsClaims := k.GetAllSavingsClaims(ctx) savingsRewardState := getSavingsGenesisRewardState(ctx, k) + earnClaims := k.GetAllEarnClaims(ctx) + earnRewardState := getEarnGenesisRewardState(ctx, k) + return types.NewGenesisState( params, - usdxRewardState, hardSupplyRewardState, hardBorrowRewardState, delegatorRewardState, swapRewardState, - savingsRewardState, usdxClaims, hardClaims, delegatorClaims, swapClaims, savingsClaims, + // Reward states + usdxRewardState, hardSupplyRewardState, hardBorrowRewardState, delegatorRewardState, swapRewardState, savingsRewardState, earnRewardState, + // Claims + usdxClaims, hardClaims, delegatorClaims, swapClaims, savingsClaims, earnClaims, ) } @@ -257,6 +276,22 @@ func getSavingsGenesisRewardState(ctx sdk.Context, keeper keeper.Keeper) types.G return types.NewGenesisRewardState(ats, mris) } +func getEarnGenesisRewardState(ctx sdk.Context, keeper keeper.Keeper) types.GenesisRewardState { + var ats types.AccumulationTimes + keeper.IterateEarnRewardAccrualTimes(ctx, func(ctype string, accTime time.Time) bool { + ats = append(ats, types.NewAccumulationTime(ctype, accTime)) + return false + }) + + var mris types.MultiRewardIndexes + keeper.IterateEarnRewardIndexes(ctx, func(ctype string, indexes types.RewardIndexes) bool { + mris = append(mris, types.NewMultiRewardIndex(ctype, indexes)) + return false + }) + + return types.NewGenesisRewardState(ats, mris) +} + func ValidateAccumulationTime(previousAccumulationTime, genesisTime time.Time) error { if previousAccumulationTime.Before(genesisTime.Add(-1 * EarliestValidAccumulationTime)) { return fmt.Errorf( diff --git a/x/incentive/genesis_test.go b/x/incentive/genesis_test.go index d1281a35..887c8ea0 100644 --- a/x/incentive/genesis_test.go +++ b/x/incentive/genesis_test.go @@ -70,6 +70,7 @@ func (suite *GenesisTestSuite) SetupTest() { types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, "ukava", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), cs(c("hard", 122354)))}, types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, "btcb/usdx", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), cs(c("swp", 122354)))}, types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, "ukava", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), cs(c("hard", 122354)))}, + types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, "ukava", suite.genesisTime.Add(-1*oneYear), suite.genesisTime.Add(oneYear), cs(c("hard", 122354)))}, types.MultipliersPerDenoms{ { Denom: "ukava", @@ -100,11 +101,13 @@ func (suite *GenesisTestSuite) SetupTest() { types.DefaultGenesisRewardState, types.DefaultGenesisRewardState, types.DefaultGenesisRewardState, + types.DefaultGenesisRewardState, types.DefaultUSDXClaims, types.DefaultHardClaims, types.DefaultDelegatorClaims, types.DefaultSwapClaims, types.DefaultSavingsClaims, + types.DefaultEarnClaims, ) cdc := suite.app.AppCodec() @@ -135,6 +138,7 @@ func (suite *GenesisTestSuite) TestExportedGenesisMatchesImported() { types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, "ukava", genesisTime.Add(-1*oneYear), genesisTime.Add(oneYear), cs(c("hard", 122354)))}, types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, "btcb/usdx", genesisTime.Add(-1*oneYear), genesisTime.Add(oneYear), cs(c("swp", 122354)))}, types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, "ukava", genesisTime.Add(-1*oneYear), genesisTime.Add(oneYear), cs(c("hard", 122354)))}, + types.MultiRewardPeriods{types.NewMultiRewardPeriod(true, "ukava", genesisTime.Add(-1*oneYear), genesisTime.Add(oneYear), cs(c("hard", 122354)))}, types.MultipliersPerDenoms{ { Denom: "ukava", @@ -207,6 +211,14 @@ func (suite *GenesisTestSuite) TestExportedGenesisMatchesImported() { types.NewMultiRewardIndex("ukava", types.RewardIndexes{{CollateralType: "ukava", RewardFactor: d("0.2")}}), }, ), + types.NewGenesisRewardState( + types.AccumulationTimes{ + types.NewAccumulationTime("usdx", genesisTime.Add(-3*time.Hour)), + }, + types.MultiRewardIndexes{ + types.NewMultiRewardIndex("usdx", types.RewardIndexes{{CollateralType: "usdx", RewardFactor: d("0.2")}}), + }, + ), types.USDXMintingClaims{ types.NewUSDXMintingClaim( suite.addrs[0], @@ -254,6 +266,13 @@ func (suite *GenesisTestSuite) TestExportedGenesisMatchesImported() { types.MultiRewardIndexes{{CollateralType: "ukava", RewardIndexes: types.RewardIndexes{{CollateralType: "ukava", RewardFactor: d("0.0")}}}}, ), }, + types.EarnClaims{ + types.NewEarnClaim( + suite.addrs[3], + nil, + types.MultiRewardIndexes{{CollateralType: "usdx", RewardIndexes: types.RewardIndexes{{CollateralType: "earn", RewardFactor: d("0.0")}}}}, + ), + }, ) tApp := app.NewTestApp() diff --git a/x/incentive/keeper/claim.go b/x/incentive/keeper/claim.go index 868e6f5b..ef75f93a 100644 --- a/x/incentive/keeper/claim.go +++ b/x/incentive/keeper/claim.go @@ -256,3 +256,51 @@ func (k Keeper) ClaimSavingsReward(ctx sdk.Context, owner, receiver sdk.AccAddre ) return nil } + +// 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) + if !found { + return sdkerrors.Wrapf(types.ErrInvalidMultiplier, "denom '%s' has no multiplier '%s'", denom, multiplierName) + } + + claimEnd := k.GetClaimEnd(ctx) + + if ctx.BlockTime().After(claimEnd) { + return sdkerrors.Wrapf(types.ErrClaimExpired, "block time %s > claim end time %s", ctx.BlockTime(), claimEnd) + } + + syncedClaim, found := k.GetSynchronizedEarnClaim(ctx, owner) + if !found { + return sdkerrors.Wrapf(types.ErrClaimNotFound, "address: %s", owner) + } + + amt := syncedClaim.Reward.AmountOf(denom) + + claimingCoins := sdk.NewCoins(sdk.NewCoin(denom, amt)) + rewardCoins := sdk.NewCoins(sdk.NewCoin(denom, amt.ToDec().Mul(multiplier.Factor).RoundInt())) + if rewardCoins.IsZero() { + return types.ErrZeroClaim + } + length := k.GetPeriodLength(ctx.BlockTime(), multiplier.MonthsLockup) + + err := k.SendTimeLockedCoinsToAccount(ctx, types.IncentiveMacc, receiver, rewardCoins, length) + if err != nil { + return err + } + + // remove claimed coins (NOT reward coins) + syncedClaim.Reward = syncedClaim.Reward.Sub(claimingCoins) + k.SetEarnClaim(ctx, syncedClaim) + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeClaim, + sdk.NewAttribute(types.AttributeKeyClaimedBy, owner.String()), + sdk.NewAttribute(types.AttributeKeyClaimAmount, claimingCoins.String()), + sdk.NewAttribute(types.AttributeKeyClaimType, syncedClaim.GetType()), + ), + ) + return nil +} diff --git a/x/incentive/keeper/claim_test.go b/x/incentive/keeper/claim_test.go index 9c42a4a8..e215eeae 100644 --- a/x/incentive/keeper/claim_test.go +++ b/x/incentive/keeper/claim_test.go @@ -36,7 +36,7 @@ func (suite *ClaimTests) TestCannotClaimWhenMultiplierNotRecognised() { }, }, } - suite.keeper = suite.NewKeeper(subspace, nil, nil, nil, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(subspace, nil, nil, nil, nil, nil, nil, nil, nil) claim := types.DelegatorClaim{ BaseMultiClaim: types.BaseMultiClaim{ @@ -70,7 +70,7 @@ func (suite *ClaimTests) TestCannotClaimAfterEndTime() { ClaimEnd: endTime, }, } - suite.keeper = suite.NewKeeper(subspace, nil, nil, nil, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(subspace, nil, nil, nil, nil, nil, nil, nil, nil) suite.ctx = suite.ctx.WithBlockTime(endTime.Add(time.Nanosecond)) diff --git a/x/incentive/keeper/hooks.go b/x/incentive/keeper/hooks.go index b52e95f5..593e0e98 100644 --- a/x/incentive/keeper/hooks.go +++ b/x/incentive/keeper/hooks.go @@ -5,6 +5,7 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" cdptypes "github.com/kava-labs/kava/x/cdp/types" + earntypes "github.com/kava-labs/kava/x/earn/types" hardtypes "github.com/kava-labs/kava/x/hard/types" savingstypes "github.com/kava-labs/kava/x/savings/types" swaptypes "github.com/kava-labs/kava/x/swap/types" @@ -21,6 +22,7 @@ var ( _ stakingtypes.StakingHooks = Hooks{} _ swaptypes.SwapHooks = Hooks{} _ savingstypes.SavingsHooks = Hooks{} + _ earntypes.EarnHooks = Hooks{} ) // Hooks create new incentive hooks @@ -177,3 +179,25 @@ func (h Hooks) AfterSavingsDepositCreated(ctx sdk.Context, deposit savingstypes. func (h Hooks) BeforeSavingsDepositModified(ctx sdk.Context, deposit savingstypes.Deposit, incomingDenoms []string) { h.k.SynchronizeSavingsReward(ctx, deposit, incomingDenoms) } + +// ------------------- Earn Module Hooks ------------------- + +// AfterVaultDepositCreated function that runs after a vault deposit is created +func (h Hooks) AfterVaultDepositCreated( + ctx sdk.Context, + vaultDenom string, + depositor sdk.AccAddress, + _ sdk.Dec, +) { + h.k.InitializeEarnReward(ctx, vaultDenom, depositor) +} + +// BeforeVaultDepositModified function that runs before a vault deposit is modified +func (h Hooks) BeforeVaultDepositModified( + ctx sdk.Context, + vaultDenom string, + depositor sdk.AccAddress, + sharesOwned sdk.Dec, +) { + h.k.SynchronizeEarnReward(ctx, vaultDenom, depositor, sharesOwned) +} diff --git a/x/incentive/keeper/keeper.go b/x/incentive/keeper/keeper.go index 28964acf..bce59550 100644 --- a/x/incentive/keeper/keeper.go +++ b/x/incentive/keeper/keeper.go @@ -22,13 +22,14 @@ type Keeper struct { stakingKeeper types.StakingKeeper swapKeeper types.SwapKeeper savingsKeeper types.SavingsKeeper + earnKeeper types.EarnKeeper } // NewKeeper creates a new keeper func NewKeeper( cdc codec.Codec, key sdk.StoreKey, paramstore types.ParamSubspace, bk types.BankKeeper, cdpk types.CdpKeeper, hk types.HardKeeper, ak types.AccountKeeper, stk types.StakingKeeper, - swpk types.SwapKeeper, svk types.SavingsKeeper, + swpk types.SwapKeeper, svk types.SavingsKeeper, ek types.EarnKeeper, ) Keeper { if !paramstore.HasKeyTable() { paramstore = paramstore.WithKeyTable(types.ParamKeyTable()) @@ -45,6 +46,7 @@ func NewKeeper( stakingKeeper: stk, swapKeeper: swpk, savingsKeeper: svk, + earnKeeper: ek, } } @@ -372,6 +374,55 @@ func (k Keeper) GetAllSavingsClaims(ctx sdk.Context) types.SavingsClaims { return cs } +// GetEarnClaim returns the claim in the store corresponding the the input address. +func (k Keeper) GetEarnClaim(ctx sdk.Context, addr sdk.AccAddress) (types.EarnClaim, bool) { + store := prefix.NewStore(ctx.KVStore(k.key), types.EarnClaimKeyPrefix) + bz := store.Get(addr) + if bz == nil { + return types.EarnClaim{}, false + } + var c types.EarnClaim + k.cdc.MustUnmarshal(bz, &c) + return c, true +} + +// SetEarnClaim sets the claim in the store corresponding to the input address. +func (k Keeper) SetEarnClaim(ctx sdk.Context, c types.EarnClaim) { + store := prefix.NewStore(ctx.KVStore(k.key), types.EarnClaimKeyPrefix) + bz := k.cdc.MustMarshal(&c) + store.Set(c.Owner, bz) +} + +// DeleteEarnClaim deletes the claim in the store corresponding to the input address. +func (k Keeper) DeleteEarnClaim(ctx sdk.Context, owner sdk.AccAddress) { + store := prefix.NewStore(ctx.KVStore(k.key), types.EarnClaimKeyPrefix) + store.Delete(owner) +} + +// IterateEarnClaims iterates over all claim objects in the store and preforms a callback function +func (k Keeper) IterateEarnClaims(ctx sdk.Context, cb func(c types.EarnClaim) (stop bool)) { + store := prefix.NewStore(ctx.KVStore(k.key), types.EarnClaimKeyPrefix) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var c types.EarnClaim + k.cdc.MustUnmarshal(iterator.Value(), &c) + if cb(c) { + break + } + } +} + +// GetAllEarnClaims returns all Claim objects in the store +func (k Keeper) GetAllEarnClaims(ctx sdk.Context) types.EarnClaims { + cs := types.EarnClaims{} + k.IterateEarnClaims(ctx, func(c types.EarnClaim) (stop bool) { + cs = append(cs, c) + return false + }) + return cs +} + // SetHardSupplyRewardIndexes sets the current reward indexes for an individual denom func (k Keeper) SetHardSupplyRewardIndexes(ctx sdk.Context, denom string, indexes types.RewardIndexes) { store := prefix.NewStore(ctx.KVStore(k.key), types.HardSupplyRewardIndexesKeyPrefix) @@ -745,3 +796,77 @@ func (k Keeper) IterateSavingsRewardAccrualTimes(ctx sdk.Context, cb func(string } } } + +// SetEarnRewardIndexes stores the global reward indexes that track total rewards to a earn vault. +func (k Keeper) SetEarnRewardIndexes(ctx sdk.Context, vaultDenom string, indexes types.RewardIndexes) { + store := prefix.NewStore(ctx.KVStore(k.key), types.EarnRewardIndexesKeyPrefix) + bz := k.cdc.MustMarshal(&types.RewardIndexesProto{ + RewardIndexes: indexes, + }) + store.Set([]byte(vaultDenom), bz) +} + +// GetEarnRewardIndexes fetches the global reward indexes that track total rewards to a earn vault. +func (k Keeper) GetEarnRewardIndexes(ctx sdk.Context, vaultDenom string) (types.RewardIndexes, bool) { + store := prefix.NewStore(ctx.KVStore(k.key), types.EarnRewardIndexesKeyPrefix) + bz := store.Get([]byte(vaultDenom)) + if bz == nil { + return types.RewardIndexes{}, false + } + var proto types.RewardIndexesProto + k.cdc.MustUnmarshal(bz, &proto) + return proto.RewardIndexes, true +} + +// IterateEarnRewardIndexes iterates over all earn reward index objects in the store and preforms a callback function +func (k Keeper) IterateEarnRewardIndexes(ctx sdk.Context, cb func(vaultDenom string, indexes types.RewardIndexes) (stop bool)) { + store := prefix.NewStore(ctx.KVStore(k.key), types.EarnRewardIndexesKeyPrefix) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var proto types.RewardIndexesProto + k.cdc.MustUnmarshal(iterator.Value(), &proto) + if cb(string(iterator.Key()), proto.RewardIndexes) { + break + } + } +} + +// GetEarnRewardAccrualTime fetches the last time rewards were accrued for an earn vault. +func (k Keeper) GetEarnRewardAccrualTime(ctx sdk.Context, vaultDenom string) (blockTime time.Time, found bool) { + store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousEarnRewardAccrualTimeKeyPrefix) + b := store.Get([]byte(vaultDenom)) + if b == nil { + return time.Time{}, false + } + if err := blockTime.UnmarshalBinary(b); err != nil { + panic(err) + } + return blockTime, true +} + +// SetEarnRewardAccrualTime stores the last time rewards were accrued for a earn vault. +func (k Keeper) SetEarnRewardAccrualTime(ctx sdk.Context, vaultDenom string, blockTime time.Time) { + store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousEarnRewardAccrualTimeKeyPrefix) + bz, err := blockTime.MarshalBinary() + if err != nil { + panic(err) + } + store.Set([]byte(vaultDenom), bz) +} + +func (k Keeper) IterateEarnRewardAccrualTimes(ctx sdk.Context, cb func(string, time.Time) (stop bool)) { + store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousEarnRewardAccrualTimeKeyPrefix) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + poolID := string(iterator.Key()) + var accrualTime time.Time + if err := accrualTime.UnmarshalBinary(iterator.Value()); err != nil { + panic(err) + } + if cb(poolID, accrualTime) { + break + } + } +} diff --git a/x/incentive/keeper/keeper_test.go b/x/incentive/keeper/keeper_test.go index d19464e3..962ee55d 100644 --- a/x/incentive/keeper/keeper_test.go +++ b/x/incentive/keeper/keeper_test.go @@ -291,6 +291,215 @@ func (suite *KeeperTestSuite) TestGetSetSwapRewardAccrualTimes() { } } +func (suite *KeeperTestSuite) TestGetSetDeleteEarnClaims() { + suite.SetupApp() + c := types.NewEarnClaim(suite.addrs[0], arbitraryCoins(), nonEmptyMultiRewardIndexes) + + _, found := suite.keeper.GetEarnClaim(suite.ctx, suite.addrs[0]) + suite.Require().False(found) + + suite.Require().NotPanics(func() { + suite.keeper.SetEarnClaim(suite.ctx, c) + }) + testC, found := suite.keeper.GetEarnClaim(suite.ctx, suite.addrs[0]) + suite.Require().True(found) + suite.Require().Equal(c, testC) + + suite.Require().NotPanics(func() { + suite.keeper.DeleteEarnClaim(suite.ctx, suite.addrs[0]) + }) + _, found = suite.keeper.GetEarnClaim(suite.ctx, suite.addrs[0]) + suite.Require().False(found) +} + +func (suite *KeeperTestSuite) TestIterateEarnClaims() { + suite.SetupApp() + claims := types.EarnClaims{ + types.NewEarnClaim(suite.addrs[0], arbitraryCoins(), nonEmptyMultiRewardIndexes), + types.NewEarnClaim(suite.addrs[1], nil, nil), // different claim to the first + } + for _, claim := range claims { + suite.keeper.SetEarnClaim(suite.ctx, claim) + } + + var actualClaims types.EarnClaims + suite.keeper.IterateEarnClaims(suite.ctx, func(c types.EarnClaim) bool { + actualClaims = append(actualClaims, c) + return false + }) + + suite.Require().Equal(claims, actualClaims) +} + +func (suite *KeeperTestSuite) TestGetSetEarnRewardIndexes() { + testCases := []struct { + name string + vaultDenom string + indexes types.RewardIndexes + wantIndex types.RewardIndexes + panics bool + }{ + { + name: "two factors can be written and read", + vaultDenom: "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 vault name panics", + vaultDenom: "", + 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", + vaultDenom: "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", + vaultDenom: "usdx", + indexes: nil, + wantIndex: nil, + panics: false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupApp() + + _, found := suite.keeper.GetEarnRewardIndexes(suite.ctx, tc.vaultDenom) + suite.False(found) + + setFunc := func() { suite.keeper.SetEarnRewardIndexes(suite.ctx, tc.vaultDenom, tc.indexes) } + if tc.panics { + suite.Panics(setFunc) + return + } else { + suite.NotPanics(setFunc) + } + + storedIndexes, found := suite.keeper.GetEarnRewardIndexes(suite.ctx, tc.vaultDenom) + suite.True(found) + suite.Equal(tc.wantIndex, storedIndexes) + }) + } +} + +func (suite *KeeperTestSuite) TestIterateEarnRewardIndexes() { + suite.SetupApp() + multiIndexes := types.MultiRewardIndexes{ + { + CollateralType: "ukava", + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "earn", + RewardFactor: d("0.0000002"), + }, + { + CollateralType: "ukava", + RewardFactor: d("0.04"), + }, + }, + }, + { + CollateralType: "usdx", + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "hard", + RewardFactor: d("0.02"), + }, + }, + }, + } + for _, mi := range multiIndexes { + suite.keeper.SetEarnRewardIndexes(suite.ctx, mi.CollateralType, mi.RewardIndexes) + } + + var actualMultiIndexes types.MultiRewardIndexes + suite.keeper.IterateEarnRewardIndexes(suite.ctx, func(vaultDenom string, i types.RewardIndexes) bool { + actualMultiIndexes = actualMultiIndexes.With(vaultDenom, i) + return false + }) + + suite.Require().Equal(multiIndexes, actualMultiIndexes) +} + +func (suite *KeeperTestSuite) TestGetSetEarnRewardAccrualTimes() { + testCases := []struct { + name string + vaultDenom string + accrualTime time.Time + panics bool + }{ + { + name: "normal time can be written and read", + vaultDenom: "usdx", + accrualTime: time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC), + }, + { + name: "zero time can be written and read", + vaultDenom: "usdx", + accrualTime: time.Time{}, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupApp() + + _, found := suite.keeper.GetEarnRewardAccrualTime(suite.ctx, tc.vaultDenom) + suite.False(found) + + setFunc := func() { suite.keeper.SetEarnRewardAccrualTime(suite.ctx, tc.vaultDenom, tc.accrualTime) } + if tc.panics { + suite.Panics(setFunc) + return + } else { + suite.NotPanics(setFunc) + } + + storedTime, found := suite.keeper.GetEarnRewardAccrualTime(suite.ctx, tc.vaultDenom) + suite.True(found) + suite.Equal(tc.accrualTime, storedTime) + }) + } +} + type accrualtime struct { denom string time time.Time @@ -397,6 +606,24 @@ func (suite *KeeperTestSuite) TestIterateSwapRewardAccrualTimes() { suite.Equal(expectedAccrualTimes, actualAccrualTimes) } +func (suite *KeeperTestSuite) TestIterateEarnRewardAccrualTimes() { + suite.SetupApp() + + expectedAccrualTimes := nonEmptyAccrualTimes + + for _, at := range expectedAccrualTimes { + suite.keeper.SetEarnRewardAccrualTime(suite.ctx, at.denom, at.time) + } + + var actualAccrualTimes []accrualtime + suite.keeper.IterateEarnRewardAccrualTimes(suite.ctx, func(denom string, accrualTime time.Time) bool { + actualAccrualTimes = append(actualAccrualTimes, accrualtime{denom: denom, time: accrualTime}) + return false + }) + + suite.Equal(expectedAccrualTimes, actualAccrualTimes) +} + func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } diff --git a/x/incentive/keeper/msg_server.go b/x/incentive/keeper/msg_server.go index 2a88ded8..a4f5cdc4 100644 --- a/x/incentive/keeper/msg_server.go +++ b/x/incentive/keeper/msg_server.go @@ -108,3 +108,21 @@ func (k msgServer) ClaimSavingsReward(goCtx context.Context, msg *types.MsgClaim return &types.MsgClaimSavingsRewardResponse{}, nil } + +func (k msgServer) ClaimEarnReward(goCtx context.Context, msg *types.MsgClaimEarnReward) (*types.MsgClaimEarnRewardResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + sender, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, err + } + + for _, selection := range msg.DenomsToClaim { + err := k.keeper.ClaimEarnReward(ctx, sender, sender, selection.Denom, selection.MultiplierName) + if err != nil { + return nil, err + } + } + + return &types.MsgClaimEarnRewardResponse{}, nil +} diff --git a/x/incentive/keeper/querier.go b/x/incentive/keeper/querier.go index 1ca93cb6..43af52f2 100644 --- a/x/incentive/keeper/querier.go +++ b/x/incentive/keeper/querier.go @@ -29,6 +29,8 @@ func NewQuerier(k Keeper, legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { return queryGetSavingsRewards(ctx, req, k, legacyQuerierCdc) case types.QueryGetRewardFactors: return queryGetRewardFactors(ctx, req, k, legacyQuerierCdc) + case types.QueryGetEarnRewards: + return queryGetEarnRewards(ctx, req, k, legacyQuerierCdc) default: return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint", types.ModuleName) } @@ -261,6 +263,51 @@ func queryGetSavingsRewards(ctx sdk.Context, req abci.RequestQuery, k Keeper, le return bz, nil } +func queryGetEarnRewards(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { + var params types.QueryRewardsParams + err := legacyQuerierCdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + owner := len(params.Owner) > 0 + + var claims types.EarnClaims + switch { + case owner: + claim, found := k.GetEarnClaim(ctx, params.Owner) + if found { + claims = append(claims, claim) + } + default: + claims = k.GetAllEarnClaims(ctx) + } + + var paginatedClaims types.EarnClaims + startH, endH := client.Paginate(len(claims), params.Page, params.Limit, 100) + if startH < 0 || endH < 0 { + paginatedClaims = types.EarnClaims{} + } else { + paginatedClaims = claims[startH:endH] + } + + if !params.Unsynchronized { + for i, claim := range paginatedClaims { + syncedClaim, found := k.GetSynchronizedEarnClaim(ctx, claim.Owner) + if !found { + panic("previously found claim should still be found") + } + paginatedClaims[i] = syncedClaim + } + } + + // Marshal claims + bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, paginatedClaims) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + return bz, nil +} + func queryGetRewardFactors(ctx sdk.Context, req abci.RequestQuery, k Keeper, legacyQuerierCdc *codec.LegacyAmino) ([]byte, error) { var usdxFactors types.RewardIndexes k.IterateUSDXMintingRewardFactors(ctx, func(collateralType string, factor sdk.Dec) (stop bool) { @@ -298,6 +345,12 @@ func queryGetRewardFactors(ctx sdk.Context, req abci.RequestQuery, k Keeper, leg return false }) + var earnFactors types.MultiRewardIndexes + k.IterateEarnRewardIndexes(ctx, func(denom string, indexes types.RewardIndexes) (stop bool) { + earnFactors = earnFactors.With(denom, indexes) + return false + }) + response := types.NewQueryGetRewardFactorsResponse( usdxFactors, supplyFactors, @@ -305,6 +358,7 @@ func queryGetRewardFactors(ctx sdk.Context, req abci.RequestQuery, k Keeper, leg delegatorFactors, swapFactors, savingsFactors, + earnFactors, ) bz, err := codec.MarshalJSONIndent(legacyQuerierCdc, response) diff --git a/x/incentive/keeper/rewards_borrow_accum_test.go b/x/incentive/keeper/rewards_borrow_accum_test.go index d426e15c..2fd39985 100644 --- a/x/incentive/keeper/rewards_borrow_accum_test.go +++ b/x/incentive/keeper/rewards_borrow_accum_test.go @@ -39,7 +39,7 @@ func (suite *AccumulateBorrowRewardsTests) TestStateUpdatedWhenBlockTimeHasIncre denom := "bnb" hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil) suite.storeGlobalBorrowIndexes(types.MultiRewardIndexes{ { @@ -91,7 +91,7 @@ func (suite *AccumulateBorrowRewardsTests) TestStateUnchangedWhenBlockTimeHasNot denom := "bnb" hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil) previousIndexes := types.MultiRewardIndexes{ { @@ -136,7 +136,7 @@ func (suite *AccumulateBorrowRewardsTests) TestNoAccumulationWhenSourceSharesAre denom := "bnb" hardKeeper := newFakeHardKeeper() // zero total borrows - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil) previousIndexes := types.MultiRewardIndexes{ { @@ -182,7 +182,7 @@ func (suite *AccumulateBorrowRewardsTests) TestStateAddedWhenStateDoesNotExist() denom := "bnb" hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil) period := types.NewMultiRewardPeriod( true, @@ -225,7 +225,7 @@ func (suite *AccumulateBorrowRewardsTests) TestNoPanicWhenStateDoesNotExist() { denom := "bnb" hardKeeper := newFakeHardKeeper() - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil) period := types.NewMultiRewardPeriod( true, @@ -253,7 +253,7 @@ func (suite *AccumulateBorrowRewardsTests) TestNoAccumulationWhenBeforeStartTime denom := "bnb" hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil) previousIndexes := types.MultiRewardIndexes{ { @@ -299,7 +299,7 @@ func (suite *AccumulateBorrowRewardsTests) TestPanicWhenCurrentTimeLessThanPrevi denom := "bnb" hardKeeper := newFakeHardKeeper().addTotalBorrow(c(denom, 1e6), d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil) previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) suite.keeper.SetPreviousHardBorrowRewardAccrualTime(suite.ctx, denom, previousAccrualTime) diff --git a/x/incentive/keeper/rewards_delegator_accum_test.go b/x/incentive/keeper/rewards_delegator_accum_test.go index 2f050e2b..a7537fc2 100644 --- a/x/incentive/keeper/rewards_delegator_accum_test.go +++ b/x/incentive/keeper/rewards_delegator_accum_test.go @@ -36,7 +36,7 @@ func TestAccumulateDelegatorRewards(t *testing.T) { func (suite *AccumulateDelegatorRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreased() { stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil) suite.storeGlobalDelegatorIndexes(types.MultiRewardIndexes{ { @@ -86,7 +86,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestStateUpdatedWhenBlockTimeHasIn func (suite *AccumulateDelegatorRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIncreased() { stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil) previousIndexes := types.MultiRewardIndexes{ { @@ -129,7 +129,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestStateUnchangedWhenBlockTimeHas func (suite *AccumulateDelegatorRewardsTests) TestNoAccumulationWhenSourceSharesAreZero() { stakingKeeper := newFakeStakingKeeper() // zero total bonded - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil) previousIndexes := types.MultiRewardIndexes{ { @@ -173,7 +173,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestNoAccumulationWhenSourceShares func (suite *AccumulateDelegatorRewardsTests) TestStateAddedWhenStateDoesNotExist() { stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil) period := types.NewMultiRewardPeriod( true, @@ -214,7 +214,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestStateAddedWhenStateDoesNotExis func (suite *AccumulateDelegatorRewardsTests) TestNoPanicWhenStateDoesNotExist() { stakingKeeper := newFakeStakingKeeper() - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil) period := types.NewMultiRewardPeriod( true, @@ -240,7 +240,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestNoPanicWhenStateDoesNotExist() func (suite *AccumulateDelegatorRewardsTests) TestNoAccumulationWhenBeforeStartTime() { stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil) previousIndexes := types.MultiRewardIndexes{ { @@ -284,7 +284,7 @@ func (suite *AccumulateDelegatorRewardsTests) TestNoAccumulationWhenBeforeStartT func (suite *AccumulateDelegatorRewardsTests) TestPanicWhenCurrentTimeLessThanPrevious() { stakingKeeper := newFakeStakingKeeper().addBondedTokens(1e6) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil) previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) suite.keeper.SetPreviousDelegatorRewardAccrualTime(suite.ctx, types.BondDenom, previousAccrualTime) diff --git a/x/incentive/keeper/rewards_delegator_init_test.go b/x/incentive/keeper/rewards_delegator_init_test.go index 17fbdf62..8d1eda3f 100644 --- a/x/incentive/keeper/rewards_delegator_init_test.go +++ b/x/incentive/keeper/rewards_delegator_init_test.go @@ -58,7 +58,7 @@ func (suite *InitializeDelegatorRewardTests) TestClaimIsSyncedAndIndexesAreSetWh DelegatorShares: d("1000"), }}, } - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, sk, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, sk, nil, nil, nil) claim := types.DelegatorClaim{ BaseMultiClaim: types.BaseMultiClaim{ diff --git a/x/incentive/keeper/rewards_delegator_sync_test.go b/x/incentive/keeper/rewards_delegator_sync_test.go index 735ebfde..f6f60f95 100644 --- a/x/incentive/keeper/rewards_delegator_sync_test.go +++ b/x/incentive/keeper/rewards_delegator_sync_test.go @@ -37,7 +37,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestClaimIndexesAreUnchangedWhenGl delegator := arbitraryAddress() stakingKeeper := &fakeStakingKeeper{} // use an empty staking keeper that returns no delegations - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil) claim := types.DelegatorClaim{ BaseMultiClaim: types.BaseMultiClaim{ @@ -58,7 +58,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestClaimIndexesAreUnchangedWhenGl func (suite *SynchronizeDelegatorRewardTests) TestClaimIndexesAreUpdatedWhenGlobalFactorIncreased() { delegator := arbitraryAddress() - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, &fakeStakingKeeper{}, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, &fakeStakingKeeper{}, nil, nil, nil) claim := types.DelegatorClaim{ BaseMultiClaim: types.BaseMultiClaim{ @@ -97,7 +97,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestRewardIsUnchangedWhenGlobalFac unslashedBondedValidator(validatorAddress), }, } - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil) claim := types.DelegatorClaim{ BaseMultiClaim: types.BaseMultiClaim{ @@ -142,7 +142,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestRewardIsIncreasedWhenNewReward unslashedBondedValidator(validatorAddress), }, } - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil) claim := types.DelegatorClaim{ BaseMultiClaim: types.BaseMultiClaim{ @@ -192,7 +192,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestRewardIsIncreasedWhenGlobalFac unslashedBondedValidator(validatorAddress), }, } - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil) claim := types.DelegatorClaim{ BaseMultiClaim: types.BaseMultiClaim{ @@ -299,7 +299,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestGetDelegatedWhenValAddrIsNil() unslashedNotBondedValidator(validatorAddresses[3]), }, } - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil) suite.Equal( d("11"), // delegation to bonded validators @@ -343,7 +343,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestGetDelegatedWhenExcludingAVali unslashedNotBondedValidator(validatorAddresses[3]), }, } - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil) suite.Equal( d("10"), @@ -387,7 +387,7 @@ func (suite *SynchronizeDelegatorRewardTests) TestGetDelegatedWhenIncludingAVali unslashedNotBondedValidator(validatorAddresses[3]), }, } - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, stakingKeeper, nil, nil, nil) suite.Equal( d("111"), diff --git a/x/incentive/keeper/rewards_earn.go b/x/incentive/keeper/rewards_earn.go new file mode 100644 index 00000000..0e907317 --- /dev/null +++ b/x/incentive/keeper/rewards_earn.go @@ -0,0 +1,142 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + earntypes "github.com/kava-labs/kava/x/earn/types" + "github.com/kava-labs/kava/x/incentive/types" +) + +// AccumulateEarnRewards calculates new rewards to distribute this block and updates the global indexes to reflect this. +// The provided rewardPeriod must be valid to avoid panics in calculating time durations. +func (k Keeper) AccumulateEarnRewards(ctx sdk.Context, rewardPeriod types.MultiRewardPeriod) { + previousAccrualTime, found := k.GetEarnRewardAccrualTime(ctx, rewardPeriod.CollateralType) + if !found { + previousAccrualTime = ctx.BlockTime() + } + + indexes, found := k.GetEarnRewardIndexes(ctx, rewardPeriod.CollateralType) + if !found { + indexes = types.RewardIndexes{} + } + + acc := types.NewAccumulator(previousAccrualTime, indexes) + + totalSource := k.getEarnTotalSourceShares(ctx, rewardPeriod.CollateralType) + + acc.Accumulate(rewardPeriod, totalSource, ctx.BlockTime()) + + k.SetEarnRewardAccrualTime(ctx, rewardPeriod.CollateralType, acc.PreviousAccumulationTime) + if len(acc.Indexes) > 0 { + // the store panics when setting empty or nil indexes + k.SetEarnRewardIndexes(ctx, rewardPeriod.CollateralType, acc.Indexes) + } +} + +// getEarnTotalSourceShares fetches the sum of all source shares for a earn reward. +// In the case of earn, these are the total (earn module) shares in a particular vault. +func (k Keeper) getEarnTotalSourceShares(ctx sdk.Context, vaultDenom string) sdk.Dec { + totalShares, found := k.earnKeeper.GetVaultTotalShares(ctx, vaultDenom) + if !found { + return sdk.ZeroDec() + } + return totalShares.Amount +} + +// InitializeEarnReward creates a new claim with zero rewards and indexes matching the global indexes. +// If the claim already exists it just updates the indexes. +func (k Keeper) InitializeEarnReward(ctx sdk.Context, vaultDenom string, owner sdk.AccAddress) { + claim, found := k.GetEarnClaim(ctx, owner) + if !found { + claim = types.NewEarnClaim(owner, sdk.Coins{}, nil) + } + + globalRewardIndexes, found := k.GetEarnRewardIndexes(ctx, vaultDenom) + if !found { + globalRewardIndexes = types.RewardIndexes{} + } + claim.RewardIndexes = claim.RewardIndexes.With(vaultDenom, globalRewardIndexes) + + k.SetEarnClaim(ctx, claim) +} + +// SynchronizeEarnReward updates the claim object by adding any accumulated rewards +// and updating the reward index value. +func (k Keeper) SynchronizeEarnReward( + ctx sdk.Context, + vaultDenom string, + owner sdk.AccAddress, + shares sdk.Dec, +) { + claim, found := k.GetEarnClaim(ctx, owner) + if !found { + return + } + claim = k.synchronizeEarnReward(ctx, claim, vaultDenom, owner, shares) + + k.SetEarnClaim(ctx, claim) +} + +// synchronizeEarnReward updates the reward and indexes in a earn claim for one vault. +func (k *Keeper) synchronizeEarnReward( + ctx sdk.Context, + claim types.EarnClaim, + vaultDenom string, + owner sdk.AccAddress, + shares sdk.Dec, +) types.EarnClaim { + globalRewardIndexes, found := k.GetEarnRewardIndexes(ctx, vaultDenom) + if !found { + // The global factor is only not found if + // - the vault has not started accumulating rewards yet (either there is no reward specified in params, or the reward start time hasn't been hit) + // - OR it was wrongly deleted from state (factors should never be removed while unsynced claims exist) + // If not found we could either skip this sync, or assume the global factor is zero. + // Skipping will avoid storing unnecessary factors in the claim for non rewarded vaults. + // And in the event a global factor is wrongly deleted, it will avoid this function panicking when calculating rewards. + return claim + } + + userRewardIndexes, found := claim.RewardIndexes.Get(vaultDenom) + if !found { + // Normally the reward indexes should always be found. + // But if a vault was not rewarded then becomes rewarded (ie a reward period is added to params), then the indexes will be missing from claims for that vault. + // So given the reward period was just added, assume the starting value for any global reward indexes, which is an empty slice. + userRewardIndexes = types.RewardIndexes{} + } + + newRewards, err := k.CalculateRewards(userRewardIndexes, globalRewardIndexes, shares) + if err != nil { + // Global reward factors should never decrease, as it would lead to a negative update to claim.Rewards. + // This panics if a global reward factor decreases or disappears between the old and new indexes. + panic(fmt.Sprintf("corrupted global reward indexes found: %v", err)) + } + + claim.Reward = claim.Reward.Add(newRewards...) + claim.RewardIndexes = claim.RewardIndexes.With(vaultDenom, globalRewardIndexes) + + return claim +} + +// GetSynchronizedEarnClaim fetches a earn claim from the store and syncs rewards for all rewarded vaults. +func (k Keeper) GetSynchronizedEarnClaim(ctx sdk.Context, owner sdk.AccAddress) (types.EarnClaim, bool) { + claim, found := k.GetEarnClaim(ctx, owner) + if !found { + return types.EarnClaim{}, false + } + + shares, found := k.earnKeeper.GetVaultAccountShares(ctx, owner) + if !found { + shares = earntypes.NewVaultShares() + } + + k.IterateEarnRewardIndexes(ctx, func(vaultDenom string, _ types.RewardIndexes) bool { + vaultAmount := shares.AmountOf(vaultDenom) + claim = k.synchronizeEarnReward(ctx, claim, vaultDenom, owner, vaultAmount) + + return false + }) + + return claim, true +} diff --git a/x/incentive/keeper/rewards_earn_accum_test.go b/x/incentive/keeper/rewards_earn_accum_test.go new file mode 100644 index 00000000..d2d931e5 --- /dev/null +++ b/x/incentive/keeper/rewards_earn_accum_test.go @@ -0,0 +1,321 @@ +package keeper_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/suite" + + earntypes "github.com/kava-labs/kava/x/earn/types" + "github.com/kava-labs/kava/x/incentive/types" +) + +type AccumulateEarnRewardsTests struct { + unitTester +} + +func (suite *AccumulateEarnRewardsTests) storedTimeEquals(vaultDenom string, expected time.Time) { + storedTime, found := suite.keeper.GetEarnRewardAccrualTime(suite.ctx, vaultDenom) + suite.True(found) + suite.Equal(expected, storedTime) +} + +func (suite *AccumulateEarnRewardsTests) storedIndexesEqual(vaultDenom string, expected types.RewardIndexes) { + storedIndexes, found := suite.keeper.GetEarnRewardIndexes(suite.ctx, vaultDenom) + suite.Equal(found, expected != nil, "expected indexes is %v but indexes found = %v", expected, found) + if found { + suite.Equal(expected, storedIndexes) + } else { + suite.Empty(storedIndexes) + } +} + +func TestAccumulateEarnRewards(t *testing.T) { + suite.Run(t, new(AccumulateEarnRewardsTests)) +} + +func (suite *AccumulateEarnRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreased() { + vaultDenom := "usdx" + + earnKeeper := newFakeEarnKeeper().addVault(vaultDenom, earntypes.NewVaultShare(vaultDenom, d("1000000"))) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper) + + suite.storeGlobalEarnIndexes(types.MultiRewardIndexes{ + { + CollateralType: vaultDenom, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "earn", + RewardFactor: d("0.02"), + }, + { + CollateralType: "ukava", + RewardFactor: d("0.04"), + }, + }, + }, + }) + previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) + suite.keeper.SetEarnRewardAccrualTime(suite.ctx, vaultDenom, previousAccrualTime) + + newAccrualTime := previousAccrualTime.Add(1 * time.Hour) + suite.ctx = suite.ctx.WithBlockTime(newAccrualTime) + + period := types.NewMultiRewardPeriod( + true, + vaultDenom, + time.Unix(0, 0), // ensure the test is within start and end times + distantFuture, + cs(c("earn", 2000), c("ukava", 1000)), // same denoms as in global indexes + ) + + suite.keeper.AccumulateEarnRewards(suite.ctx, period) + + // check time and factors + + suite.storedTimeEquals(vaultDenom, newAccrualTime) + suite.storedIndexesEqual(vaultDenom, types.RewardIndexes{ + { + CollateralType: "earn", + RewardFactor: d("7.22"), + }, + { + CollateralType: "ukava", + RewardFactor: d("3.64"), + }, + }) +} + +func (suite *AccumulateEarnRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIncreased() { + vaultDenom := "usdx" + + earnKeeper := newFakeEarnKeeper().addVault(vaultDenom, earntypes.NewVaultShare(vaultDenom, d("1000000"))) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper) + + previousIndexes := types.MultiRewardIndexes{ + { + CollateralType: vaultDenom, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "earn", + RewardFactor: d("0.02"), + }, + { + CollateralType: "ukava", + RewardFactor: d("0.04"), + }, + }, + }, + } + suite.storeGlobalEarnIndexes(previousIndexes) + previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) + suite.keeper.SetEarnRewardAccrualTime(suite.ctx, vaultDenom, previousAccrualTime) + + suite.ctx = suite.ctx.WithBlockTime(previousAccrualTime) + + period := types.NewMultiRewardPeriod( + true, + vaultDenom, + time.Unix(0, 0), // ensure the test is within start and end times + distantFuture, + cs(c("earn", 2000), c("ukava", 1000)), // same denoms as in global indexes + ) + + suite.keeper.AccumulateEarnRewards(suite.ctx, period) + + // check time and factors + + suite.storedTimeEquals(vaultDenom, previousAccrualTime) + expected, f := previousIndexes.Get(vaultDenom) + suite.True(f) + suite.storedIndexesEqual(vaultDenom, expected) +} + +func (suite *AccumulateEarnRewardsTests) TestNoAccumulationWhenSourceSharesAreZero() { + vaultDenom := "usdx" + + earnKeeper := newFakeEarnKeeper() // no vault, so no source shares + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper) + + previousIndexes := types.MultiRewardIndexes{ + { + CollateralType: vaultDenom, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "earn", + RewardFactor: d("0.02"), + }, + { + CollateralType: "ukava", + RewardFactor: d("0.04"), + }, + }, + }, + } + suite.storeGlobalEarnIndexes(previousIndexes) + previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) + suite.keeper.SetEarnRewardAccrualTime(suite.ctx, vaultDenom, previousAccrualTime) + + firstAccrualTime := previousAccrualTime.Add(7 * time.Second) + suite.ctx = suite.ctx.WithBlockTime(firstAccrualTime) + + period := types.NewMultiRewardPeriod( + true, + vaultDenom, + time.Unix(0, 0), // ensure the test is within start and end times + distantFuture, + cs(c("earn", 2000), c("ukava", 1000)), // same denoms as in global indexes + ) + + suite.keeper.AccumulateEarnRewards(suite.ctx, period) + + // check time and factors + + suite.storedTimeEquals(vaultDenom, firstAccrualTime) + expected, f := previousIndexes.Get(vaultDenom) + suite.True(f) + suite.storedIndexesEqual(vaultDenom, expected) +} + +func (suite *AccumulateEarnRewardsTests) TestStateAddedWhenStateDoesNotExist() { + vaultDenom := "usdx" + + earnKeeper := newFakeEarnKeeper().addVault(vaultDenom, earntypes.NewVaultShare(vaultDenom, d("1000000"))) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper) + + period := types.NewMultiRewardPeriod( + true, + vaultDenom, + time.Unix(0, 0), // ensure the test is within start and end times + distantFuture, + cs(c("earn", 2000), c("ukava", 1000)), + ) + + firstAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) + suite.ctx = suite.ctx.WithBlockTime(firstAccrualTime) + + suite.keeper.AccumulateEarnRewards(suite.ctx, period) + + // After the first accumulation only the current block time should be stored. + // The indexes will be empty as no time has passed since the previous block because it didn't exist. + suite.storedTimeEquals(vaultDenom, firstAccrualTime) + suite.storedIndexesEqual(vaultDenom, nil) + + secondAccrualTime := firstAccrualTime.Add(10 * time.Second) + suite.ctx = suite.ctx.WithBlockTime(secondAccrualTime) + + suite.keeper.AccumulateEarnRewards(suite.ctx, period) + + // After the second accumulation both current block time and indexes should be stored. + suite.storedTimeEquals(vaultDenom, secondAccrualTime) + suite.storedIndexesEqual(vaultDenom, types.RewardIndexes{ + { + CollateralType: "earn", + RewardFactor: d("0.02"), + }, + { + CollateralType: "ukava", + RewardFactor: d("0.01"), + }, + }) +} + +func (suite *AccumulateEarnRewardsTests) TestNoPanicWhenStateDoesNotExist() { + vaultDenom := "usdx" + + earnKeeper := newFakeEarnKeeper() + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper) + + period := types.NewMultiRewardPeriod( + true, + vaultDenom, + time.Unix(0, 0), // ensure the test is within start and end times + distantFuture, + cs(), + ) + + accrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) + suite.ctx = suite.ctx.WithBlockTime(accrualTime) + + // Accumulate with no earn shares and no rewards per second will result in no increment to the indexes. + // No increment and no previous indexes stored, results in an updated of nil. Setting this in the state panics. + // Check there is no panic. + suite.NotPanics(func() { + suite.keeper.AccumulateEarnRewards(suite.ctx, period) + }) + + suite.storedTimeEquals(vaultDenom, accrualTime) + suite.storedIndexesEqual(vaultDenom, nil) +} + +func (suite *AccumulateEarnRewardsTests) TestNoAccumulationWhenBeforeStartTime() { + vaultDenom := "usdx" + + earnKeeper := newFakeEarnKeeper().addVault(vaultDenom, earntypes.NewVaultShare(vaultDenom, d("1000000"))) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper) + + previousIndexes := types.MultiRewardIndexes{ + { + CollateralType: vaultDenom, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "earn", + RewardFactor: d("0.02"), + }, + { + CollateralType: "ukava", + RewardFactor: d("0.04"), + }, + }, + }, + } + suite.storeGlobalEarnIndexes(previousIndexes) + previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) + suite.keeper.SetEarnRewardAccrualTime(suite.ctx, vaultDenom, previousAccrualTime) + + firstAccrualTime := previousAccrualTime.Add(10 * time.Second) + + period := types.NewMultiRewardPeriod( + true, + vaultDenom, + firstAccrualTime.Add(time.Nanosecond), // start time after accrual time + distantFuture, + cs(c("earn", 2000), c("ukava", 1000)), + ) + + suite.ctx = suite.ctx.WithBlockTime(firstAccrualTime) + + suite.keeper.AccumulateEarnRewards(suite.ctx, period) + + // The accrual time should be updated, but the indexes unchanged + suite.storedTimeEquals(vaultDenom, firstAccrualTime) + expectedIndexes, f := previousIndexes.Get(vaultDenom) + suite.True(f) + suite.storedIndexesEqual(vaultDenom, expectedIndexes) +} + +func (suite *AccumulateEarnRewardsTests) TestPanicWhenCurrentTimeLessThanPrevious() { + vaultDenom := "usdx" + + earnKeeper := newFakeEarnKeeper().addVault(vaultDenom, earntypes.NewVaultShare(vaultDenom, d("1000000"))) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper) + + previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) + suite.keeper.SetEarnRewardAccrualTime(suite.ctx, vaultDenom, previousAccrualTime) + + firstAccrualTime := time.Time{} + + period := types.NewMultiRewardPeriod( + true, + vaultDenom, + time.Time{}, // start time after accrual time + distantFuture, + cs(c("earn", 2000), c("ukava", 1000)), + ) + + suite.ctx = suite.ctx.WithBlockTime(firstAccrualTime) + + suite.Panics(func() { + suite.keeper.AccumulateEarnRewards(suite.ctx, period) + }) +} diff --git a/x/incentive/keeper/rewards_earn_init_test.go b/x/incentive/keeper/rewards_earn_init_test.go new file mode 100644 index 00000000..4931ae0b --- /dev/null +++ b/x/incentive/keeper/rewards_earn_init_test.go @@ -0,0 +1,195 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" + + "github.com/kava-labs/kava/x/incentive/types" +) + +// InitializeEarnRewardTests runs unit tests for the keeper.InitializeEarnReward method +// +// inputs +// - claim in store if it exists +// - global indexes in store +// +// outputs +// - sets or creates a claim +type InitializeEarnRewardTests struct { + unitTester +} + +func TestInitializeEarnReward(t *testing.T) { + suite.Run(t, new(InitializeEarnRewardTests)) +} + +func (suite *InitializeEarnRewardTests) TestClaimAddedWhenClaimDoesNotExistAndNoRewards() { + // When a claim doesn't exist, and a user deposits to a non-rewarded pool; + // then a claim is added with no rewards and no indexes + + vaultDenom := "usdx" + + // no global indexes stored as this pool is not rewarded + + owner := arbitraryAddress() + + suite.keeper.InitializeEarnReward(suite.ctx, vaultDenom, owner) + + syncedClaim, found := suite.keeper.GetEarnClaim(suite.ctx, owner) + suite.True(found) + // A new claim should have empty indexes. It doesn't strictly need the vaultDenom either. + expectedIndexes := types.MultiRewardIndexes{{ + CollateralType: vaultDenom, + RewardIndexes: nil, + }} + suite.Equal(expectedIndexes, syncedClaim.RewardIndexes) + // a new claim should start with 0 rewards + suite.Equal(sdk.Coins(nil), syncedClaim.Reward) +} + +func (suite *InitializeEarnRewardTests) TestClaimAddedWhenClaimDoesNotExistAndRewardsExist() { + // When a claim doesn't exist, and a user deposits to a rewarded pool; + // then a claim is added with no rewards and indexes matching the global indexes + + vaultDenom := "usdx" + + globalIndexes := types.MultiRewardIndexes{ + { + CollateralType: vaultDenom, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "rewarddenom", + RewardFactor: d("1000.001"), + }, + }, + }, + } + suite.storeGlobalEarnIndexes(globalIndexes) + + owner := arbitraryAddress() + + suite.keeper.InitializeEarnReward(suite.ctx, vaultDenom, owner) + + syncedClaim, found := suite.keeper.GetEarnClaim(suite.ctx, owner) + suite.True(found) + // a new claim should start with the current global indexes + suite.Equal(globalIndexes, syncedClaim.RewardIndexes) + // a new claim should start with 0 rewards + suite.Equal(sdk.Coins(nil), syncedClaim.Reward) +} + +func (suite *InitializeEarnRewardTests) TestClaimUpdatedWhenClaimExistsAndNoRewards() { + // When a claim exists, and a user deposits to a new non-rewarded pool; + // then the claim's rewards don't change + + preexistingvaultDenom := "preexisting" + preexistingIndexes := types.RewardIndexes{ + { + CollateralType: "rewarddenom", + RewardFactor: d("1000.001"), + }, + } + + newVaultDenom := "btcb:usdx" + + claim := types.EarnClaim{ + BaseMultiClaim: types.BaseMultiClaim{ + Owner: arbitraryAddress(), + Reward: arbitraryCoins(), + }, + RewardIndexes: types.MultiRewardIndexes{ + { + CollateralType: preexistingvaultDenom, + RewardIndexes: preexistingIndexes, + }, + }, + } + suite.storeEarnClaim(claim) + + // no global indexes stored as the new pool is not rewarded + + suite.keeper.InitializeEarnReward(suite.ctx, newVaultDenom, claim.Owner) + + syncedClaim, _ := suite.keeper.GetEarnClaim(suite.ctx, claim.Owner) + // The preexisting indexes shouldn't be changed. It doesn't strictly need the new vaultDenom either. + expectedIndexes := types.MultiRewardIndexes{ + { + CollateralType: preexistingvaultDenom, + RewardIndexes: preexistingIndexes, + }, + { + CollateralType: newVaultDenom, + RewardIndexes: nil, + }, + } + suite.Equal(expectedIndexes, syncedClaim.RewardIndexes) + // init should never alter the rewards + suite.Equal(claim.Reward, syncedClaim.Reward) +} + +func (suite *InitializeEarnRewardTests) TestClaimUpdatedWhenClaimExistsAndRewardsExist() { + // When a claim exists, and a user deposits to a new rewarded pool; + // then the claim's rewards don't change and the indexes are updated to match the global indexes + + preexistingvaultDenom := "preexisting" + preexistingIndexes := types.RewardIndexes{ + { + CollateralType: "rewarddenom", + RewardFactor: d("1000.001"), + }, + } + + newVaultDenom := "btcb:usdx" + newIndexes := types.RewardIndexes{ + { + CollateralType: "otherrewarddenom", + RewardFactor: d("1000.001"), + }, + } + + claim := types.EarnClaim{ + BaseMultiClaim: types.BaseMultiClaim{ + Owner: arbitraryAddress(), + Reward: arbitraryCoins(), + }, + RewardIndexes: types.MultiRewardIndexes{ + { + CollateralType: preexistingvaultDenom, + RewardIndexes: preexistingIndexes, + }, + }, + } + suite.storeEarnClaim(claim) + + globalIndexes := types.MultiRewardIndexes{ + { + CollateralType: preexistingvaultDenom, + RewardIndexes: increaseRewardFactors(preexistingIndexes), + }, + { + CollateralType: newVaultDenom, + RewardIndexes: newIndexes, + }, + } + suite.storeGlobalEarnIndexes(globalIndexes) + + suite.keeper.InitializeEarnReward(suite.ctx, newVaultDenom, claim.Owner) + + syncedClaim, _ := suite.keeper.GetEarnClaim(suite.ctx, claim.Owner) + // only the indexes for the new pool should be updated + expectedIndexes := types.MultiRewardIndexes{ + { + CollateralType: preexistingvaultDenom, + RewardIndexes: preexistingIndexes, + }, + { + CollateralType: newVaultDenom, + RewardIndexes: newIndexes, + }, + } + suite.Equal(expectedIndexes, syncedClaim.RewardIndexes) + // init should never alter the rewards + suite.Equal(claim.Reward, syncedClaim.Reward) +} diff --git a/x/incentive/keeper/rewards_earn_sync_test.go b/x/incentive/keeper/rewards_earn_sync_test.go new file mode 100644 index 00000000..9269cf24 --- /dev/null +++ b/x/incentive/keeper/rewards_earn_sync_test.go @@ -0,0 +1,473 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + earntypes "github.com/kava-labs/kava/x/earn/types" + "github.com/kava-labs/kava/x/incentive/types" +) + +// SynchronizeEarnRewardTests runs unit tests for the keeper.SynchronizeEarnReward method +// +// inputs +// - claim in store (only claim.RewardIndexes, claim.Reward) +// - global indexes in store +// - shares function arg +// +// outputs +// - sets a claim +type SynchronizeEarnRewardTests struct { + unitTester +} + +func TestSynchronizeEarnReward(t *testing.T) { + suite.Run(t, new(SynchronizeEarnRewardTests)) +} + +func (suite *SynchronizeEarnRewardTests) TestClaimUpdatedWhenGlobalIndexesHaveIncreased() { + // This is the normal case + // Given some time has passed (meaning the global indexes have increased) + // When the claim is synced + // The user earns rewards for the time passed, and the claim indexes are updated + + originalReward := arbitraryCoins() + vaultDenom := "cats" + + claim := types.EarnClaim{ + BaseMultiClaim: types.BaseMultiClaim{ + Owner: arbitraryAddress(), + Reward: originalReward, + }, + RewardIndexes: types.MultiRewardIndexes{ + { + CollateralType: vaultDenom, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "rewarddenom", + RewardFactor: d("1000.001"), + }, + }, + }, + }, + } + suite.storeEarnClaim(claim) + + globalIndexes := types.MultiRewardIndexes{ + { + CollateralType: vaultDenom, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "rewarddenom", + RewardFactor: d("2000.002"), + }, + }, + }, + } + suite.storeGlobalEarnIndexes(globalIndexes) + + userShares := d("1000000000") + + suite.keeper.SynchronizeEarnReward(suite.ctx, vaultDenom, claim.Owner, userShares) + + syncedClaim, _ := suite.keeper.GetEarnClaim(suite.ctx, claim.Owner) + // indexes updated from global + suite.Equal(globalIndexes, syncedClaim.RewardIndexes) + // new reward is (new index - old index) * user shares + suite.Equal( + cs(c("rewarddenom", 1_000_001_000_000)).Add(originalReward...), + syncedClaim.Reward, + ) +} + +func (suite *SynchronizeEarnRewardTests) TestClaimUnchangedWhenGlobalIndexesUnchanged() { + // It should be safe to call SynchronizeEarnReward multiple times + + vaultDenom := "cats" + unchangingIndexes := types.MultiRewardIndexes{ + { + CollateralType: vaultDenom, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "rewarddenom", + RewardFactor: d("1000.001"), + }, + }, + }, + } + + claim := types.EarnClaim{ + BaseMultiClaim: types.BaseMultiClaim{ + Owner: arbitraryAddress(), + Reward: arbitraryCoins(), + }, + RewardIndexes: unchangingIndexes, + } + suite.storeEarnClaim(claim) + + suite.storeGlobalEarnIndexes(unchangingIndexes) + + userShares := d("1000000000") + + suite.keeper.SynchronizeEarnReward(suite.ctx, vaultDenom, claim.Owner, userShares) + + syncedClaim, _ := suite.keeper.GetEarnClaim(suite.ctx, claim.Owner) + // claim should have the same rewards and indexes as before + suite.Equal(claim, syncedClaim) +} + +func (suite *SynchronizeEarnRewardTests) TestClaimUpdatedWhenNewRewardAdded() { + // When a new reward is added (via gov) for a vault the user has already deposited to, and the claim is synced; + // Then the user earns rewards for the time since the reward was added, and the indexes are added to the claim. + + originalReward := arbitraryCoins() + newlyRewardVaultDenom := "newlyRewardedVault" + + claim := types.EarnClaim{ + BaseMultiClaim: types.BaseMultiClaim{ + Owner: arbitraryAddress(), + Reward: originalReward, + }, + RewardIndexes: types.MultiRewardIndexes{ + { + CollateralType: "currentlyRewardedVault", + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "reward", + RewardFactor: d("1000.001"), + }, + }, + }, + }, + } + suite.storeEarnClaim(claim) + + globalIndexes := types.MultiRewardIndexes{ + { + CollateralType: "currentlyRewardedVault", + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "reward", + RewardFactor: d("2000.002"), + }, + }, + }, + { + CollateralType: newlyRewardVaultDenom, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "otherreward", + // Indexes start at 0 when the reward is added by gov, + // so this represents the syncing happening some time later. + RewardFactor: d("1000.001"), + }, + }, + }, + } + suite.storeGlobalEarnIndexes(globalIndexes) + + userShares := d("1000000000") + + suite.keeper.SynchronizeEarnReward(suite.ctx, newlyRewardVaultDenom, claim.Owner, userShares) + + syncedClaim, _ := suite.keeper.GetEarnClaim(suite.ctx, claim.Owner) + // the new indexes should be added to the claim, but the old ones should be unchanged + newlyRewrdedIndexes, _ := globalIndexes.Get(newlyRewardVaultDenom) + expectedIndexes := claim.RewardIndexes.With(newlyRewardVaultDenom, newlyRewrdedIndexes) + suite.Equal(expectedIndexes, syncedClaim.RewardIndexes) + // new reward is (new index - old index) * shares for the synced vault + // The old index for `newlyrewarded` isn't in the claim, so it's added starting at 0 for calculating the reward. + suite.Equal( + cs(c("otherreward", 1_000_001_000_000)).Add(originalReward...), + syncedClaim.Reward, + ) +} + +func (suite *SynchronizeEarnRewardTests) TestClaimUnchangedWhenNoReward() { + // When a vault is not rewarded but the user has deposited to that vault, and the claim is synced; + // Then the claim should be the same. + + claim := types.EarnClaim{ + BaseMultiClaim: types.BaseMultiClaim{ + Owner: arbitraryAddress(), + Reward: arbitraryCoins(), + }, + RewardIndexes: nonEmptyMultiRewardIndexes, + } + suite.storeEarnClaim(claim) + + vaultDenom := "nonRewardVault" + // No global indexes stored as this vault is not rewarded + + userShares := d("1000000000") + + suite.keeper.SynchronizeEarnReward(suite.ctx, vaultDenom, claim.Owner, userShares) + + syncedClaim, _ := suite.keeper.GetEarnClaim(suite.ctx, claim.Owner) + suite.Equal(claim, syncedClaim) +} + +func (suite *SynchronizeEarnRewardTests) TestClaimUpdatedWhenNewRewardDenomAdded() { + // When a new reward coin is added (via gov) to an already rewarded vault (that the user has already deposited to), and the claim is synced; + // Then the user earns rewards for the time since the reward was added, and the new indexes are added. + + originalReward := arbitraryCoins() + vaultDenom := "cats" + + claim := types.EarnClaim{ + BaseMultiClaim: types.BaseMultiClaim{ + Owner: arbitraryAddress(), + Reward: originalReward, + }, + RewardIndexes: types.MultiRewardIndexes{ + { + CollateralType: vaultDenom, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "reward", + RewardFactor: d("1000.001"), + }, + }, + }, + }, + } + suite.storeEarnClaim(claim) + + globalIndexes := types.MultiRewardIndexes{ + { + CollateralType: vaultDenom, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "reward", + RewardFactor: d("2000.002"), + }, + { + CollateralType: "otherreward", + // Indexes start at 0 when the reward is added by gov, + // so this represents the syncing happening some time later. + RewardFactor: d("1000.001"), + }, + }, + }, + } + suite.storeGlobalEarnIndexes(globalIndexes) + + userShares := d("1000000000") + + suite.keeper.SynchronizeEarnReward(suite.ctx, vaultDenom, claim.Owner, userShares) + + syncedClaim, _ := suite.keeper.GetEarnClaim(suite.ctx, claim.Owner) + // indexes should have the new reward denom added + suite.Equal(globalIndexes, syncedClaim.RewardIndexes) + // new reward is (new index - old index) * shares + // The old index for `otherreward` isn't in the claim, so it's added starting at 0 for calculating the reward. + suite.Equal( + cs(c("reward", 1_000_001_000_000), c("otherreward", 1_000_001_000_000)).Add(originalReward...), + syncedClaim.Reward, + ) +} + +func (suite *SynchronizeEarnRewardTests) TestClaimUpdatedWhenGlobalIndexesIncreasedAndSourceIsZero() { + // Given some time has passed (meaning the global indexes have increased) + // When the claim is synced, but the user has no shares + // The user earns no rewards for the time passed, but the claim indexes are updated + + vaultDenom := "cats" + + claim := types.EarnClaim{ + BaseMultiClaim: types.BaseMultiClaim{ + Owner: arbitraryAddress(), + Reward: arbitraryCoins(), + }, + RewardIndexes: types.MultiRewardIndexes{ + { + CollateralType: vaultDenom, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "rewarddenom", + RewardFactor: d("1000.001"), + }, + }, + }, + }, + } + suite.storeEarnClaim(claim) + + globalIndexes := types.MultiRewardIndexes{ + { + CollateralType: vaultDenom, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "rewarddenom", + RewardFactor: d("2000.002"), + }, + }, + }, + } + suite.storeGlobalEarnIndexes(globalIndexes) + + userShares := d("0") + + suite.keeper.SynchronizeEarnReward(suite.ctx, vaultDenom, claim.Owner, userShares) + + syncedClaim, _ := suite.keeper.GetEarnClaim(suite.ctx, claim.Owner) + // indexes updated from global + suite.Equal(globalIndexes, syncedClaim.RewardIndexes) + // reward is unchanged + suite.Equal(claim.Reward, syncedClaim.Reward) +} + +func (suite *SynchronizeEarnRewardTests) TestGetSyncedClaim_ClaimUnchangedWhenNoGlobalIndexes() { + vaultDenom_1 := "usdx" + owner := arbitraryAddress() + + earnKeeper := newFakeEarnKeeper(). + addDeposit(owner, earntypes.NewVaultShare("usdx", d("1000000000"))) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper) + + claim := types.EarnClaim{ + BaseMultiClaim: types.BaseMultiClaim{ + Owner: owner, + Reward: nil, + }, + RewardIndexes: types.MultiRewardIndexes{ + { + CollateralType: vaultDenom_1, + RewardIndexes: nil, // this state only happens because Init stores empty indexes + }, + }, + } + suite.storeEarnClaim(claim) + + // no global indexes for any vault + + syncedClaim, f := suite.keeper.GetSynchronizedEarnClaim(suite.ctx, claim.Owner) + suite.True(f) + + // indexes are unchanged + suite.Equal(claim.RewardIndexes, syncedClaim.RewardIndexes) + // reward is unchanged + suite.Equal(claim.Reward, syncedClaim.Reward) +} + +func (suite *SynchronizeEarnRewardTests) TestGetSyncedClaim_ClaimUpdatedWhenMissingIndexAndHasNoSourceShares() { + vaultDenom_1 := "usdx" + vaultDenom_2 := "ukava" + owner := arbitraryAddress() + + // owner has no shares in any vault + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, newFakeEarnKeeper()) + + claim := types.EarnClaim{ + BaseMultiClaim: types.BaseMultiClaim{ + Owner: owner, + Reward: arbitraryCoins(), + }, + RewardIndexes: types.MultiRewardIndexes{ + { + CollateralType: vaultDenom_1, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "rewarddenom1", + RewardFactor: d("1000.001"), + }, + }, + }, + }, + } + suite.storeEarnClaim(claim) + + globalIndexes := types.MultiRewardIndexes{ + { + CollateralType: vaultDenom_1, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "rewarddenom1", + RewardFactor: d("2000.002"), + }, + }, + }, + { + CollateralType: vaultDenom_2, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "rewarddenom2", + RewardFactor: d("2000.002"), + }, + }, + }, + } + suite.storeGlobalEarnIndexes(globalIndexes) + + syncedClaim, f := suite.keeper.GetSynchronizedEarnClaim(suite.ctx, claim.Owner) + suite.True(f) + + // indexes updated from global + suite.Equal(globalIndexes, syncedClaim.RewardIndexes) + // reward is unchanged + suite.Equal(claim.Reward, syncedClaim.Reward) +} + +func (suite *SynchronizeEarnRewardTests) TestGetSyncedClaim_ClaimUpdatedWhenMissingIndexButHasSourceShares() { + VaultDenom_1 := "usdx" + VaultDenom_2 := "ukava" + owner := arbitraryAddress() + + earnKeeper := newFakeEarnKeeper(). + addVault(VaultDenom_1, earntypes.NewVaultShare(VaultDenom_1, d("1000000000"))). + addVault(VaultDenom_2, earntypes.NewVaultShare(VaultDenom_2, d("1000000000"))). + addDeposit(owner, earntypes.NewVaultShare(VaultDenom_1, d("1000000000"))). + addDeposit(owner, earntypes.NewVaultShare(VaultDenom_2, d("1000000000"))) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, earnKeeper) + + claim := types.EarnClaim{ + BaseMultiClaim: types.BaseMultiClaim{ + Owner: owner, + Reward: arbitraryCoins(), + }, + RewardIndexes: types.MultiRewardIndexes{ + { + CollateralType: VaultDenom_1, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "rewarddenom1", + RewardFactor: d("1000.001"), + }, + }, + }, + }, + } + suite.storeEarnClaim(claim) + + globalIndexes := types.MultiRewardIndexes{ + { + CollateralType: VaultDenom_1, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "rewarddenom1", + RewardFactor: d("2000.002"), + }, + }, + }, + { + CollateralType: VaultDenom_2, + RewardIndexes: types.RewardIndexes{ + { + CollateralType: "rewarddenom2", + RewardFactor: d("2000.002"), + }, + }, + }, + } + suite.storeGlobalEarnIndexes(globalIndexes) + + syncedClaim, f := suite.keeper.GetSynchronizedEarnClaim(suite.ctx, claim.Owner) + suite.True(f) + + // indexes updated from global + suite.Equal(globalIndexes, syncedClaim.RewardIndexes) + // reward is incremented + expectedReward := cs(c("rewarddenom1", 1_000_001_000_000), c("rewarddenom2", 2_000_002_000_000)) + suite.Equal(claim.Reward.Add(expectedReward...), syncedClaim.Reward) +} diff --git a/x/incentive/keeper/rewards_supply_accum_test.go b/x/incentive/keeper/rewards_supply_accum_test.go index b3e134e6..145cd68d 100644 --- a/x/incentive/keeper/rewards_supply_accum_test.go +++ b/x/incentive/keeper/rewards_supply_accum_test.go @@ -38,7 +38,7 @@ func (suite *AccumulateSupplyRewardsTests) TestStateUpdatedWhenBlockTimeHasIncre denom := "bnb" hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil) suite.storeGlobalSupplyIndexes(types.MultiRewardIndexes{ { @@ -90,7 +90,7 @@ func (suite *AccumulateSupplyRewardsTests) TestStateUnchangedWhenBlockTimeHasNot denom := "bnb" hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil) previousIndexes := types.MultiRewardIndexes{ { @@ -135,7 +135,7 @@ func (suite *AccumulateSupplyRewardsTests) TestNoAccumulationWhenSourceSharesAre denom := "bnb" hardKeeper := newFakeHardKeeper() // zero total supplys - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil) previousIndexes := types.MultiRewardIndexes{ { @@ -181,7 +181,7 @@ func (suite *AccumulateSupplyRewardsTests) TestStateAddedWhenStateDoesNotExist() denom := "bnb" hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil) period := types.NewMultiRewardPeriod( true, @@ -224,7 +224,7 @@ func (suite *AccumulateSupplyRewardsTests) TestNoPanicWhenStateDoesNotExist() { denom := "bnb" hardKeeper := newFakeHardKeeper() - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil) period := types.NewMultiRewardPeriod( true, @@ -252,7 +252,7 @@ func (suite *AccumulateSupplyRewardsTests) TestNoAccumulationWhenBeforeStartTime denom := "bnb" hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil) previousIndexes := types.MultiRewardIndexes{ { @@ -298,7 +298,7 @@ func (suite *AccumulateSupplyRewardsTests) TestPanicWhenCurrentTimeLessThanPrevi denom := "bnb" hardKeeper := newFakeHardKeeper().addTotalSupply(c(denom, 1e6), d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, hardKeeper, nil, nil, nil, nil, nil) previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) suite.keeper.SetPreviousHardSupplyRewardAccrualTime(suite.ctx, denom, previousAccrualTime) diff --git a/x/incentive/keeper/rewards_swap_accum_test.go b/x/incentive/keeper/rewards_swap_accum_test.go index 0bc082b6..c836b931 100644 --- a/x/incentive/keeper/rewards_swap_accum_test.go +++ b/x/incentive/keeper/rewards_swap_accum_test.go @@ -37,7 +37,7 @@ func (suite *AccumulateSwapRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreas pool := "btc:usdx" swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6)) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil) suite.storeGlobalSwapIndexes(types.MultiRewardIndexes{ { @@ -89,7 +89,7 @@ func (suite *AccumulateSwapRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIn pool := "btc:usdx" swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6)) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil) previousIndexes := types.MultiRewardIndexes{ { @@ -134,7 +134,7 @@ func (suite *AccumulateSwapRewardsTests) TestNoAccumulationWhenSourceSharesAreZe pool := "btc:usdx" swapKeeper := newFakeSwapKeeper() // no pools, so no source shares - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil) previousIndexes := types.MultiRewardIndexes{ { @@ -180,7 +180,7 @@ func (suite *AccumulateSwapRewardsTests) TestStateAddedWhenStateDoesNotExist() { pool := "btc:usdx" swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6)) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil) period := types.NewMultiRewardPeriod( true, @@ -223,7 +223,7 @@ func (suite *AccumulateSwapRewardsTests) TestNoPanicWhenStateDoesNotExist() { pool := "btc:usdx" swapKeeper := newFakeSwapKeeper() - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil) period := types.NewMultiRewardPeriod( true, @@ -251,7 +251,7 @@ func (suite *AccumulateSwapRewardsTests) TestNoAccumulationWhenBeforeStartTime() pool := "btc:usdx" swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6)) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil) previousIndexes := types.MultiRewardIndexes{ { @@ -297,7 +297,7 @@ func (suite *AccumulateSwapRewardsTests) TestPanicWhenCurrentTimeLessThanPreviou pool := "btc:usdx" swapKeeper := newFakeSwapKeeper().addPool(pool, i(1e6)) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil) previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) suite.keeper.SetSwapRewardAccrualTime(suite.ctx, pool, previousAccrualTime) diff --git a/x/incentive/keeper/rewards_swap_sync_test.go b/x/incentive/keeper/rewards_swap_sync_test.go index feb5f597..63570439 100644 --- a/x/incentive/keeper/rewards_swap_sync_test.go +++ b/x/incentive/keeper/rewards_swap_sync_test.go @@ -323,7 +323,7 @@ func (suite *SynchronizeSwapRewardTests) TestGetSyncedClaim_ClaimUnchangedWhenNo swapKeeper := newFakeSwapKeeper(). addDeposit(poolID_1, owner, i(1e9)) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil) claim := types.SwapClaim{ BaseMultiClaim: types.BaseMultiClaim{ @@ -356,7 +356,7 @@ func (suite *SynchronizeSwapRewardTests) TestGetSyncedClaim_ClaimUpdatedWhenMiss owner := arbitraryAddress() // owner has no shares in any pool - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, newFakeSwapKeeper(), nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, newFakeSwapKeeper(), nil, nil) claim := types.SwapClaim{ BaseMultiClaim: types.BaseMultiClaim{ @@ -416,7 +416,7 @@ func (suite *SynchronizeSwapRewardTests) TestGetSyncedClaim_ClaimUpdatedWhenMiss swapKeeper := newFakeSwapKeeper(). addDeposit(poolID_1, owner, i(1e9)). addDeposit(poolID_2, owner, i(1e9)) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, swapKeeper, nil, nil) claim := types.SwapClaim{ BaseMultiClaim: types.BaseMultiClaim{ diff --git a/x/incentive/keeper/rewards_usdx_accum_test.go b/x/incentive/keeper/rewards_usdx_accum_test.go index 0d354094..1fb67824 100644 --- a/x/incentive/keeper/rewards_usdx_accum_test.go +++ b/x/incentive/keeper/rewards_usdx_accum_test.go @@ -34,7 +34,7 @@ func (suite *AccumulateUSDXRewardsTests) TestStateUpdatedWhenBlockTimeHasIncreas cType := "bnb-a" cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil) suite.storeGlobalUSDXIndexes(types.RewardIndexes{ { @@ -68,7 +68,7 @@ func (suite *AccumulateUSDXRewardsTests) TestStateUnchangedWhenBlockTimeHasNotIn cType := "bnb-a" cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil) previousIndexes := types.RewardIndexes{ { @@ -104,7 +104,7 @@ func (suite *AccumulateUSDXRewardsTests) TestNoAccumulationWhenSourceSharesAreZe cType := "bnb-a" cdpKeeper := newFakeCDPKeeper() // zero total borrows - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil) previousIndexes := types.RewardIndexes{ { @@ -141,7 +141,7 @@ func (suite *AccumulateUSDXRewardsTests) TestStateAddedWhenStateDoesNotExist() { cType := "bnb-a" cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil) period := types.NewRewardPeriod( true, @@ -174,7 +174,7 @@ func (suite *AccumulateUSDXRewardsTests) TestNoAccumulationWhenBeforeStartTime() cType := "bnb-a" cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil) previousIndexes := types.RewardIndexes{ { @@ -211,7 +211,7 @@ func (suite *AccumulateUSDXRewardsTests) TestPanicWhenCurrentTimeLessThanPreviou cType := "bnb-a" cdpKeeper := newFakeCDPKeeper().addTotalPrincipal(i(1e6)).addInterestFactor(d("1")) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, cdpKeeper, nil, nil, nil, nil, nil, nil) previousAccrualTime := time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC) suite.keeper.SetPreviousUSDXMintingAccrualTime(suite.ctx, cType, previousAccrualTime) diff --git a/x/incentive/keeper/unit_test.go b/x/incentive/keeper/unit_test.go index fe53c092..14f527cc 100644 --- a/x/incentive/keeper/unit_test.go +++ b/x/incentive/keeper/unit_test.go @@ -15,6 +15,7 @@ import ( "github.com/kava-labs/kava/app" cdptypes "github.com/kava-labs/kava/x/cdp/types" + earntypes "github.com/kava-labs/kava/x/earn/types" tmprototypes "github.com/tendermint/tendermint/proto/tendermint/types" hardtypes "github.com/kava-labs/kava/x/hard/types" @@ -58,7 +59,7 @@ func (suite *unitTester) SetupSuite() { func (suite *unitTester) SetupTest() { suite.ctx = NewTestContext(suite.incentiveStoreKey) - suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil) + suite.keeper = suite.NewKeeper(&fakeParamSubspace{}, nil, nil, nil, nil, nil, nil, nil, nil) } func (suite *unitTester) TearDownTest() { @@ -66,8 +67,8 @@ func (suite *unitTester) TearDownTest() { suite.ctx = sdk.Context{} } -func (suite *unitTester) NewKeeper(paramSubspace types.ParamSubspace, bk types.BankKeeper, cdpk types.CdpKeeper, hk types.HardKeeper, ak types.AccountKeeper, stk types.StakingKeeper, swk types.SwapKeeper, svk types.SavingsKeeper) keeper.Keeper { - return keeper.NewKeeper(suite.cdc, suite.incentiveStoreKey, paramSubspace, bk, cdpk, hk, ak, stk, swk, svk) +func (suite *unitTester) NewKeeper(paramSubspace types.ParamSubspace, bk types.BankKeeper, cdpk types.CdpKeeper, hk types.HardKeeper, ak types.AccountKeeper, stk types.StakingKeeper, swk types.SwapKeeper, svk types.SavingsKeeper, ek types.EarnKeeper) keeper.Keeper { + return keeper.NewKeeper(suite.cdc, suite.incentiveStoreKey, paramSubspace, bk, cdpk, hk, ak, stk, swk, svk, ek) } func (suite *unitTester) storeGlobalBorrowIndexes(indexes types.MultiRewardIndexes) { @@ -100,6 +101,12 @@ func (suite *unitTester) storeGlobalSavingsIndexes(indexes types.MultiRewardInde } } +func (suite *unitTester) storeGlobalEarnIndexes(indexes types.MultiRewardIndexes) { + for _, i := range indexes { + suite.keeper.SetEarnRewardIndexes(suite.ctx, i.CollateralType, i.RewardIndexes) + } +} + func (suite *unitTester) storeHardClaim(claim types.HardLiquidityProviderClaim) { suite.keeper.SetHardLiquidityProviderClaim(suite.ctx, claim) } @@ -116,6 +123,10 @@ func (suite *unitTester) storeSavingsClaim(claim types.SavingsClaim) { suite.keeper.SetSavingsClaim(suite.ctx, claim) } +func (suite *unitTester) storeEarnClaim(claim types.EarnClaim) { + suite.keeper.SetEarnClaim(suite.ctx, claim) +} + // fakeParamSubspace is a stub paramSpace to simplify keeper unit test setup. type fakeParamSubspace struct { params types.Params @@ -351,6 +362,56 @@ func (k *fakeCDPKeeper) GetCollateral(_ sdk.Context, collateralType string) (cdp return cdptypes.CollateralParam{}, false } +// fakeEarnKeeper is a stub earn keeper. +// It can be used to return values to the incentive keeper without having to initialize a full earn keeper. +type fakeEarnKeeper struct { + vaultShares map[string]earntypes.VaultShare + depositShares map[string]earntypes.VaultShares +} + +var _ types.EarnKeeper = newFakeEarnKeeper() + +func newFakeEarnKeeper() *fakeEarnKeeper { + return &fakeEarnKeeper{ + vaultShares: map[string]earntypes.VaultShare{}, + depositShares: map[string]earntypes.VaultShares{}, + } +} + +func (k *fakeEarnKeeper) addVault(vaultDenom string, shares earntypes.VaultShare) *fakeEarnKeeper { + k.vaultShares[vaultDenom] = shares + return k +} + +func (k *fakeEarnKeeper) addDeposit( + depositor sdk.AccAddress, + shares earntypes.VaultShare, +) *fakeEarnKeeper { + if k.depositShares[depositor.String()] == nil { + k.depositShares[depositor.String()] = earntypes.NewVaultShares() + } + + k.depositShares[depositor.String()] = k.depositShares[depositor.String()].Add(shares) + + return k +} + +func (k *fakeEarnKeeper) GetVaultTotalShares( + ctx sdk.Context, + denom string, +) (shares earntypes.VaultShare, found bool) { + vaultShares, found := k.vaultShares[denom] + return vaultShares, found +} + +func (k *fakeEarnKeeper) GetVaultAccountShares( + ctx sdk.Context, + acc sdk.AccAddress, +) (shares earntypes.VaultShares, found bool) { + accShares, found := k.depositShares[acc.String()] + return accShares, found +} + // Assorted Testing Data // note: amino panics when encoding times ≥ the start of year 10000. diff --git a/x/incentive/legacy/go.mod b/x/incentive/legacy/go.mod new file mode 100644 index 00000000..e69de29b diff --git a/x/incentive/types/claims.go b/x/incentive/types/claims.go index 9d1ce889..ac7bc5f6 100644 --- a/x/incentive/types/claims.go +++ b/x/incentive/types/claims.go @@ -14,6 +14,7 @@ const ( DelegatorClaimType = "delegator_claim" SwapClaimType = "swap" SavingsClaimType = "savings" + EarnClaimType = "earn" ) // GetOwner is a getter for Claim Owner @@ -339,6 +340,58 @@ func (cs SavingsClaims) Validate() error { return nil } +// NewEarnClaim returns a new EarnClaim +func NewEarnClaim(owner sdk.AccAddress, rewards sdk.Coins, rewardIndexes MultiRewardIndexes) EarnClaim { + return EarnClaim{ + BaseMultiClaim: BaseMultiClaim{ + Owner: owner, + Reward: rewards, + }, + RewardIndexes: rewardIndexes, + } +} + +// GetType returns the claim's type +func (c EarnClaim) GetType() string { return EarnClaimType } + +// GetReward returns the claim's reward coin +func (c EarnClaim) GetReward() sdk.Coins { return c.Reward } + +// GetOwner returns the claim's owner +func (c EarnClaim) GetOwner() sdk.AccAddress { return c.Owner } + +// Validate performs a basic check of a SwapClaim fields +func (c EarnClaim) Validate() error { + if err := c.RewardIndexes.Validate(); err != nil { + return err + } + return c.BaseMultiClaim.Validate() +} + +// HasRewardIndex check if a claim has a reward index for the input pool ID. +func (c EarnClaim) HasRewardIndex(poolID string) (int64, bool) { + for index, ri := range c.RewardIndexes { + if ri.CollateralType == poolID { + return int64(index), true + } + } + return 0, false +} + +// EarnClaims slice of EarnClaim +type EarnClaims []EarnClaim + +// Validate checks if all the claims are valid. +func (cs EarnClaims) Validate() error { + for _, c := range cs { + if err := c.Validate(); err != nil { + return err + } + } + + return nil +} + // ---------------------- Reward indexes are used internally in the store ---------------------- // NewRewardIndex returns a new RewardIndex diff --git a/x/incentive/types/claims.pb.go b/x/incentive/types/claims.pb.go index 44f553f5..77839b79 100644 --- a/x/incentive/types/claims.pb.go +++ b/x/incentive/types/claims.pb.go @@ -454,6 +454,45 @@ func (m *SavingsClaim) XXX_DiscardUnknown() { var xxx_messageInfo_SavingsClaim proto.InternalMessageInfo +// EarnClaim stores the earn rewards that can be claimed by owner +type EarnClaim struct { + BaseMultiClaim `protobuf:"bytes,1,opt,name=base_claim,json=baseClaim,proto3,embedded=base_claim" json:"base_claim"` + RewardIndexes MultiRewardIndexes `protobuf:"bytes,2,rep,name=reward_indexes,json=rewardIndexes,proto3,castrepeated=MultiRewardIndexes" json:"reward_indexes"` +} + +func (m *EarnClaim) Reset() { *m = EarnClaim{} } +func (m *EarnClaim) String() string { return proto.CompactTextString(m) } +func (*EarnClaim) ProtoMessage() {} +func (*EarnClaim) Descriptor() ([]byte, []int) { + return fileDescriptor_5f7515029623a895, []int{11} +} +func (m *EarnClaim) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EarnClaim) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EarnClaim.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *EarnClaim) XXX_Merge(src proto.Message) { + xxx_messageInfo_EarnClaim.Merge(m, src) +} +func (m *EarnClaim) XXX_Size() int { + return m.Size() +} +func (m *EarnClaim) XXX_DiscardUnknown() { + xxx_messageInfo_EarnClaim.DiscardUnknown(m) +} + +var xxx_messageInfo_EarnClaim proto.InternalMessageInfo + func init() { proto.RegisterType((*BaseClaim)(nil), "kava.incentive.v1beta1.BaseClaim") proto.RegisterType((*BaseMultiClaim)(nil), "kava.incentive.v1beta1.BaseMultiClaim") @@ -466,6 +505,7 @@ func init() { proto.RegisterType((*DelegatorClaim)(nil), "kava.incentive.v1beta1.DelegatorClaim") proto.RegisterType((*SwapClaim)(nil), "kava.incentive.v1beta1.SwapClaim") proto.RegisterType((*SavingsClaim)(nil), "kava.incentive.v1beta1.SavingsClaim") + proto.RegisterType((*EarnClaim)(nil), "kava.incentive.v1beta1.EarnClaim") } func init() { @@ -473,50 +513,51 @@ func init() { } var fileDescriptor_5f7515029623a895 = []byte{ - // 686 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x96, 0x4f, 0x4f, 0x13, 0x4f, - 0x18, 0xc7, 0x3b, 0xf0, 0x83, 0xfc, 0x3a, 0x94, 0x4a, 0x16, 0x50, 0xe8, 0x61, 0x8b, 0x25, 0xc1, - 0x26, 0xa6, 0xbb, 0x82, 0x07, 0x13, 0x6f, 0x2c, 0xc4, 0x80, 0x91, 0x48, 0xb6, 0x9a, 0x18, 0x0f, - 0x36, 0xb3, 0xbb, 0x63, 0x9d, 0xb0, 0xdd, 0xa9, 0x3b, 0xd3, 0x96, 0xbe, 0x06, 0x2f, 0xfa, 0x06, - 0x7c, 0x01, 0x5e, 0xbc, 0xf0, 0x22, 0x88, 0xf1, 0x40, 0x8c, 0x89, 0x7f, 0x0e, 0x15, 0xe1, 0xea, - 0x2b, 0xf0, 0x64, 0xe6, 0x0f, 0xb0, 0x40, 0x4b, 0x88, 0x29, 0x1e, 0x38, 0xb5, 0xf3, 0xcc, 0xb3, - 0xcf, 0xf7, 0xf3, 0x7c, 0xf7, 0xd9, 0xd9, 0x85, 0xb3, 0x1b, 0xa8, 0x89, 0x6c, 0x12, 0xf9, 0x38, - 0xe2, 0xa4, 0x89, 0xed, 0xe6, 0xbc, 0x87, 0x39, 0x9a, 0xb7, 0xfd, 0x10, 0x91, 0x1a, 0xb3, 0xea, - 0x31, 0xe5, 0xd4, 0xb8, 0x2a, 0x92, 0xac, 0xc3, 0x24, 0x4b, 0x27, 0xe5, 0x26, 0xaa, 0xb4, 0x4a, - 0x65, 0x8a, 0x2d, 0xfe, 0xa9, 0xec, 0xdc, 0xb4, 0x4f, 0x59, 0x8d, 0xb2, 0x8a, 0xda, 0x50, 0x0b, - 0xbd, 0x65, 0xaa, 0x95, 0xed, 0x21, 0x96, 0x90, 0xa2, 0x24, 0x52, 0xfb, 0x85, 0xf7, 0x00, 0xa6, - 0x1d, 0xc4, 0xf0, 0x92, 0x50, 0x37, 0x9e, 0xc1, 0x21, 0xda, 0x8a, 0x70, 0x3c, 0x05, 0x66, 0x40, - 0x31, 0xe3, 0xac, 0xfc, 0xee, 0xe4, 0x4b, 0x55, 0xc2, 0x5f, 0x34, 0x3c, 0xcb, 0xa7, 0x35, 0x5d, - 0x59, 0xff, 0x94, 0x58, 0xb0, 0x61, 0xf3, 0x76, 0x1d, 0x33, 0x6b, 0xd1, 0xf7, 0x17, 0x83, 0x20, - 0xc6, 0x8c, 0x7d, 0xda, 0x2a, 0x8d, 0x6b, 0x7d, 0x1d, 0x71, 0xda, 0x1c, 0x33, 0x57, 0x95, 0x35, - 0xee, 0xc0, 0xe1, 0x18, 0xb7, 0x50, 0x1c, 0x4c, 0x0d, 0xcc, 0x80, 0xe2, 0xc8, 0xc2, 0xb4, 0xa5, - 0x93, 0x05, 0xde, 0x41, 0x93, 0xd6, 0x12, 0x25, 0x91, 0xf3, 0xdf, 0x76, 0x27, 0x9f, 0x72, 0x75, - 0xfa, 0xdd, 0xf4, 0x87, 0xad, 0xd2, 0x90, 0x64, 0x2c, 0xec, 0x02, 0x98, 0x15, 0xc4, 0x6b, 0x8d, - 0x90, 0x93, 0x7f, 0x83, 0xed, 0x27, 0xb0, 0x07, 0xcf, 0xc6, 0xbe, 0x25, 0xb0, 0xdf, 0xfd, 0xc8, - 0x17, 0xcf, 0xa1, 0x2f, 0x2e, 0x60, 0xdd, 0x5a, 0x7c, 0x05, 0xe0, 0x88, 0x2b, 0xa3, 0xab, 0x51, - 0x80, 0x37, 0x8d, 0x1b, 0xf0, 0x8a, 0x4f, 0xc3, 0x10, 0x71, 0x1c, 0xa3, 0xb0, 0x22, 0x2e, 0x96, - 0x9d, 0xa6, 0xdd, 0xec, 0x51, 0xf8, 0x51, 0xbb, 0x8e, 0x8d, 0x32, 0x1c, 0x55, 0xd5, 0x2a, 0xcf, - 0x91, 0xcf, 0x69, 0x2c, 0x6d, 0xce, 0x38, 0x96, 0x80, 0xfa, 0xde, 0xc9, 0xcf, 0x9d, 0x03, 0x6a, - 0x19, 0xfb, 0x6e, 0x46, 0x15, 0xb9, 0x27, 0x6b, 0x14, 0x5a, 0xd0, 0x48, 0xc0, 0x60, 0xb6, 0x2e, - 0x27, 0x14, 0xc1, 0xac, 0x96, 0x22, 0x2a, 0x3c, 0x05, 0xa4, 0x37, 0xb3, 0x56, 0xf7, 0xd1, 0xb5, - 0x12, 0x35, 0x9c, 0x49, 0xed, 0xd2, 0xe8, 0xb1, 0xc2, 0xae, 0x86, 0xd7, 0xcb, 0xc2, 0x5b, 0x00, - 0xc7, 0xe4, 0x5d, 0xfe, 0x2b, 0x2f, 0x4e, 0x03, 0x0e, 0xf4, 0x1b, 0xf0, 0x0d, 0x80, 0xd7, 0x4e, - 0x02, 0x1e, 0xf8, 0xd3, 0x84, 0x13, 0x35, 0xb1, 0x55, 0xe9, 0xea, 0x52, 0xb1, 0x17, 0xc4, 0xc9, - 0x72, 0x4e, 0x4e, 0x93, 0x18, 0xa7, 0x85, 0x5c, 0xa3, 0x76, 0x2a, 0x56, 0xf8, 0x08, 0xe0, 0xd8, - 0xe3, 0xf2, 0xf2, 0x93, 0x35, 0x12, 0x71, 0x12, 0x55, 0xd5, 0x03, 0x72, 0x1f, 0x42, 0x31, 0xaa, - 0x15, 0x79, 0xc6, 0x48, 0xbf, 0x46, 0x16, 0xae, 0xf7, 0x42, 0x38, 0x3c, 0x0e, 0x9c, 0xff, 0x85, - 0xf6, 0x4e, 0x27, 0x0f, 0xdc, 0xb4, 0x77, 0x78, 0x46, 0x5c, 0xbc, 0xaf, 0xc9, 0x47, 0xe1, 0xd7, - 0x00, 0xcc, 0xad, 0xa0, 0x38, 0x78, 0x40, 0x5e, 0x36, 0x48, 0x40, 0x78, 0x7b, 0x3d, 0xa6, 0x4d, - 0x12, 0xe0, 0x58, 0xc1, 0x3c, 0xec, 0xd2, 0xd8, 0xdc, 0x59, 0x8d, 0x1d, 0x9d, 0x1a, 0xdd, 0xbb, - 0xdb, 0x84, 0x93, 0xac, 0x51, 0xaf, 0x87, 0xed, 0x4a, 0xd7, 0x26, 0xfb, 0x73, 0xdf, 0xc6, 0x95, - 0xc4, 0xb1, 0xa0, 0x50, 0xf6, 0x68, 0x1c, 0xd3, 0xd6, 0x49, 0xe5, 0xc1, 0x7e, 0x2a, 0x2b, 0x09, - 0xb7, 0x97, 0xdd, 0xdf, 0x00, 0xcc, 0x2e, 0xe3, 0x10, 0x57, 0x11, 0xa7, 0x17, 0x65, 0xf1, 0x46, - 0x8f, 0x01, 0xea, 0x4f, 0x87, 0xbd, 0x47, 0xe9, 0x33, 0x80, 0xe9, 0x72, 0x0b, 0xd5, 0x2f, 0x59, - 0x5b, 0x5f, 0x00, 0xcc, 0x94, 0x51, 0x93, 0x44, 0x55, 0x76, 0xb9, 0x3a, 0x73, 0x56, 0xb7, 0x7f, - 0x9a, 0xa9, 0xed, 0x3d, 0x13, 0xec, 0xec, 0x99, 0x60, 0x77, 0xcf, 0x04, 0xaf, 0xf7, 0xcd, 0xd4, - 0xce, 0xbe, 0x99, 0xfa, 0xba, 0x6f, 0xa6, 0x9e, 0xde, 0x4c, 0xbc, 0xcc, 0x04, 0x47, 0x29, 0x44, - 0x1e, 0x93, 0xff, 0xec, 0xcd, 0xc4, 0xe7, 0x95, 0x7c, 0xab, 0x79, 0xc3, 0xf2, 0x6b, 0xe7, 0xf6, - 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbb, 0x6c, 0x47, 0x50, 0x7d, 0x09, 0x00, 0x00, + // 693 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x96, 0x4f, 0x4f, 0x13, 0x4d, + 0x1c, 0xc7, 0x3b, 0xf0, 0x40, 0x9e, 0x0e, 0xa5, 0x0f, 0x59, 0xe0, 0x11, 0x7a, 0xd8, 0x62, 0x49, + 0xb0, 0x89, 0xe9, 0xae, 0xe0, 0xc1, 0xc4, 0x1b, 0x0b, 0x1a, 0x30, 0x12, 0xc9, 0x56, 0x13, 0xe3, + 0xc1, 0x66, 0x76, 0x77, 0xac, 0x13, 0xb6, 0x3b, 0x75, 0x66, 0xdb, 0xd2, 0xd7, 0xe0, 0x45, 0xdf, + 0x80, 0x2f, 0xc0, 0x8b, 0x17, 0x5e, 0x04, 0x31, 0x1e, 0x88, 0x31, 0xf1, 0xcf, 0xa1, 0x22, 0x5c, + 0x7d, 0x05, 0x9e, 0xcc, 0xfc, 0x01, 0x16, 0x68, 0x09, 0x31, 0xc5, 0x03, 0xa7, 0xdd, 0xf9, 0xcd, + 0x6f, 0x7f, 0xdf, 0xcf, 0xef, 0x3b, 0xb3, 0xb3, 0x0b, 0x67, 0x37, 0x50, 0x13, 0xd9, 0x24, 0xf2, + 0x71, 0x14, 0x93, 0x26, 0xb6, 0x9b, 0xf3, 0x1e, 0x8e, 0xd1, 0xbc, 0xed, 0x87, 0x88, 0xd4, 0xb8, + 0x55, 0x67, 0x34, 0xa6, 0xc6, 0xff, 0x22, 0xc9, 0x3a, 0x4c, 0xb2, 0x74, 0x52, 0x6e, 0xa2, 0x4a, + 0xab, 0x54, 0xa6, 0xd8, 0xe2, 0x4e, 0x65, 0xe7, 0xa6, 0x7d, 0xca, 0x6b, 0x94, 0x57, 0xd4, 0x84, + 0x1a, 0xe8, 0x29, 0x53, 0x8d, 0x6c, 0x0f, 0xf1, 0x84, 0x14, 0x25, 0x91, 0x9a, 0x2f, 0xbc, 0x03, + 0x30, 0xed, 0x20, 0x8e, 0x97, 0x84, 0xba, 0xf1, 0x14, 0x0e, 0xd1, 0x56, 0x84, 0xd9, 0x14, 0x98, + 0x01, 0xc5, 0x8c, 0xb3, 0xf2, 0xab, 0x93, 0x2f, 0x55, 0x49, 0xfc, 0xbc, 0xe1, 0x59, 0x3e, 0xad, + 0xe9, 0xca, 0xfa, 0x52, 0xe2, 0xc1, 0x86, 0x1d, 0xb7, 0xeb, 0x98, 0x5b, 0x8b, 0xbe, 0xbf, 0x18, + 0x04, 0x0c, 0x73, 0xfe, 0x71, 0xab, 0x34, 0xae, 0xf5, 0x75, 0xc4, 0x69, 0xc7, 0x98, 0xbb, 0xaa, + 0xac, 0x71, 0x0b, 0x0e, 0x33, 0xdc, 0x42, 0x2c, 0x98, 0x1a, 0x98, 0x01, 0xc5, 0x91, 0x85, 0x69, + 0x4b, 0x27, 0x0b, 0xbc, 0x83, 0x26, 0xad, 0x25, 0x4a, 0x22, 0xe7, 0x9f, 0xed, 0x4e, 0x3e, 0xe5, + 0xea, 0xf4, 0xdb, 0xe9, 0xf7, 0x5b, 0xa5, 0x21, 0xc9, 0x58, 0xd8, 0x05, 0x30, 0x2b, 0x88, 0xd7, + 0x1a, 0x61, 0x4c, 0xfe, 0x0e, 0xb6, 0x9f, 0xc0, 0x1e, 0x3c, 0x1b, 0xfb, 0x86, 0xc0, 0x7e, 0xfb, + 0x3d, 0x5f, 0x3c, 0x87, 0xbe, 0x78, 0x80, 0x77, 0x6b, 0xf1, 0x25, 0x80, 0x23, 0xae, 0x8c, 0xae, + 0x46, 0x01, 0xde, 0x34, 0xae, 0xc1, 0xff, 0x7c, 0x1a, 0x86, 0x28, 0xc6, 0x0c, 0x85, 0x15, 0xf1, + 0xb0, 0xec, 0x34, 0xed, 0x66, 0x8f, 0xc2, 0x0f, 0xdb, 0x75, 0x6c, 0x94, 0xe1, 0xa8, 0xaa, 0x56, + 0x79, 0x86, 0xfc, 0x98, 0x32, 0x69, 0x73, 0xc6, 0xb1, 0x04, 0xd4, 0xb7, 0x4e, 0x7e, 0xee, 0x1c, + 0x50, 0xcb, 0xd8, 0x77, 0x33, 0xaa, 0xc8, 0x5d, 0x59, 0xa3, 0xd0, 0x82, 0x46, 0x02, 0x06, 0xf3, + 0x75, 0xb9, 0x43, 0x11, 0xcc, 0x6a, 0x29, 0xa2, 0xc2, 0x53, 0x40, 0x7a, 0x33, 0x6b, 0x75, 0xdf, + 0xba, 0x56, 0xa2, 0x86, 0x33, 0xa9, 0x5d, 0x1a, 0x3d, 0x56, 0xd8, 0xd5, 0xf0, 0x7a, 0x58, 0x78, + 0x03, 0xe0, 0x98, 0x5c, 0xe5, 0x3f, 0xf2, 0xe2, 0x34, 0xe0, 0x40, 0xbf, 0x01, 0x5f, 0x03, 0x78, + 0xe5, 0x24, 0xe0, 0x81, 0x3f, 0x4d, 0x38, 0x51, 0x13, 0x53, 0x95, 0xae, 0x2e, 0x15, 0x7b, 0x41, + 0x9c, 0x2c, 0xe7, 0xe4, 0x34, 0x89, 0x71, 0x5a, 0xc8, 0x35, 0x6a, 0xa7, 0x62, 0x85, 0x0f, 0x00, + 0x8e, 0x3d, 0x2a, 0x2f, 0x3f, 0x5e, 0x23, 0x51, 0x4c, 0xa2, 0xaa, 0x7a, 0x41, 0xee, 0x41, 0x28, + 0xb6, 0x6a, 0x45, 0x9e, 0x31, 0xd2, 0xaf, 0x91, 0x85, 0xab, 0xbd, 0x10, 0x0e, 0x8f, 0x03, 0xe7, + 0x5f, 0xa1, 0xbd, 0xd3, 0xc9, 0x03, 0x37, 0xed, 0x1d, 0x9e, 0x11, 0x17, 0xef, 0x6b, 0xf2, 0x55, + 0xf8, 0x39, 0x00, 0x73, 0x2b, 0x88, 0x05, 0xf7, 0xc9, 0x8b, 0x06, 0x09, 0x48, 0xdc, 0x5e, 0x67, + 0xb4, 0x49, 0x02, 0xcc, 0x14, 0xcc, 0x83, 0x2e, 0x8d, 0xcd, 0x9d, 0xd5, 0xd8, 0xd1, 0xa9, 0xd1, + 0xbd, 0xbb, 0x4d, 0x38, 0xc9, 0x1b, 0xf5, 0x7a, 0xd8, 0xae, 0x74, 0x6d, 0xb2, 0x3f, 0xeb, 0x36, + 0xae, 0x24, 0x8e, 0x05, 0x85, 0xb2, 0x47, 0x19, 0xa3, 0xad, 0x93, 0xca, 0x83, 0xfd, 0x54, 0x56, + 0x12, 0x6e, 0x2f, 0xbb, 0xbf, 0x02, 0x98, 0x5d, 0xc6, 0x21, 0xae, 0xa2, 0x98, 0x5e, 0x94, 0xc5, + 0x1b, 0x3d, 0x36, 0x50, 0x7f, 0x3a, 0xec, 0xbd, 0x95, 0x3e, 0x01, 0x98, 0x2e, 0xb7, 0x50, 0xfd, + 0x92, 0xb5, 0xf5, 0x19, 0xc0, 0x4c, 0x19, 0x35, 0x49, 0x54, 0xe5, 0x97, 0x70, 0xc1, 0xee, 0x20, + 0x16, 0x5d, 0xae, 0xb6, 0x9c, 0xd5, 0xed, 0x1f, 0x66, 0x6a, 0x7b, 0xcf, 0x04, 0x3b, 0x7b, 0x26, + 0xd8, 0xdd, 0x33, 0xc1, 0xab, 0x7d, 0x33, 0xb5, 0xb3, 0x6f, 0xa6, 0xbe, 0xec, 0x9b, 0xa9, 0x27, + 0xd7, 0x13, 0xdf, 0x68, 0xc1, 0x51, 0x0a, 0x91, 0xc7, 0xe5, 0x9d, 0xbd, 0x99, 0xf8, 0x6b, 0x94, + 0x1f, 0x6b, 0x6f, 0x58, 0xfe, 0xc4, 0xdd, 0xfc, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xb3, 0x1b, 0x3b, + 0x5a, 0x54, 0x0a, 0x00, 0x00, } func (m *BaseClaim) Marshal() (dAtA []byte, err error) { @@ -1010,6 +1051,53 @@ func (m *SavingsClaim) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *EarnClaim) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *EarnClaim) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EarnClaim) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RewardIndexes) > 0 { + for iNdEx := len(m.RewardIndexes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.RewardIndexes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintClaims(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.BaseMultiClaim.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintClaims(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintClaims(dAtA []byte, offset int, v uint64) int { offset -= sovClaims(v) base := offset @@ -1210,6 +1298,23 @@ func (m *SavingsClaim) Size() (n int) { return n } +func (m *EarnClaim) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.BaseMultiClaim.Size() + n += 1 + l + sovClaims(uint64(l)) + if len(m.RewardIndexes) > 0 { + for _, e := range m.RewardIndexes { + l = e.Size() + n += 1 + l + sovClaims(uint64(l)) + } + } + return n +} + func sovClaims(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2469,6 +2574,123 @@ func (m *SavingsClaim) Unmarshal(dAtA []byte) error { } return nil } +func (m *EarnClaim) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClaims + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EarnClaim: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EarnClaim: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseMultiClaim", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClaims + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthClaims + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthClaims + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.BaseMultiClaim.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardIndexes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClaims + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthClaims + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthClaims + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RewardIndexes = append(m.RewardIndexes, MultiRewardIndex{}) + if err := m.RewardIndexes[len(m.RewardIndexes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipClaims(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthClaims + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipClaims(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/incentive/types/codec.go b/x/incentive/types/codec.go index 1f3af6b8..5e606cd5 100644 --- a/x/incentive/types/codec.go +++ b/x/incentive/types/codec.go @@ -17,6 +17,7 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&MsgClaimDelegatorReward{}, "incentive/MsgClaimDelegatorReward", nil) cdc.RegisterConcrete(&MsgClaimSwapReward{}, "incentive/MsgClaimSwapReward", nil) cdc.RegisterConcrete(&MsgClaimSavingsReward{}, "incentive/MsgClaimSavingsReward", nil) + cdc.RegisterConcrete(&MsgClaimEarnReward{}, "incentive/MsgClaimEarnReward", nil) } func RegisterInterfaces(registry types.InterfaceRegistry) { @@ -26,6 +27,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { &MsgClaimDelegatorReward{}, &MsgClaimSwapReward{}, &MsgClaimSavingsReward{}, + &MsgClaimEarnReward{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) diff --git a/x/incentive/types/expected_keepers.go b/x/incentive/types/expected_keepers.go index 3d9d5716..4a38486f 100644 --- a/x/incentive/types/expected_keepers.go +++ b/x/incentive/types/expected_keepers.go @@ -6,6 +6,7 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" cdptypes "github.com/kava-labs/kava/x/cdp/types" + earntypes "github.com/kava-labs/kava/x/earn/types" hardtypes "github.com/kava-labs/kava/x/hard/types" savingstypes "github.com/kava-labs/kava/x/savings/types" ) @@ -63,6 +64,12 @@ type SavingsKeeper interface { GetSavingsModuleAccountBalances(ctx sdk.Context) sdk.Coins } +// EarnKeeper defines the required methods needed by this modules keeper +type EarnKeeper interface { + GetVaultTotalShares(ctx sdk.Context, denom string) (shares earntypes.VaultShare, found bool) + GetVaultAccountShares(ctx sdk.Context, acc sdk.AccAddress) (shares earntypes.VaultShares, found bool) +} + // AccountKeeper expected interface for the account keeper (noalias) type AccountKeeper interface { GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI diff --git a/x/incentive/types/genesis.go b/x/incentive/types/genesis.go index 3790cad0..1955617b 100644 --- a/x/incentive/types/genesis.go +++ b/x/incentive/types/genesis.go @@ -15,13 +15,15 @@ var ( AccumulationTimes{}, MultiRewardIndexes{}, ) + DefaultEarnClaims = EarnClaims{} ) // NewGenesisState returns a new genesis state func NewGenesisState( params Params, - usdxState, hardSupplyState, hardBorrowState, delegatorState, swapState, savingsState GenesisRewardState, + usdxState, hardSupplyState, hardBorrowState, delegatorState, swapState, savingsState, earnState GenesisRewardState, c USDXMintingClaims, hc HardLiquidityProviderClaims, dc DelegatorClaims, sc SwapClaims, savingsc SavingsClaims, + earnc EarnClaims, ) GenesisState { return GenesisState{ Params: params, @@ -32,12 +34,14 @@ func NewGenesisState( DelegatorRewardState: delegatorState, SwapRewardState: swapState, SavingsRewardState: savingsState, + EarnRewardState: earnState, USDXMintingClaims: c, HardLiquidityProviderClaims: hc, DelegatorClaims: dc, SwapClaims: sc, SavingsClaims: savingsc, + EarnClaims: earnc, } } @@ -51,11 +55,13 @@ func DefaultGenesisState() GenesisState { DelegatorRewardState: DefaultGenesisRewardState, SwapRewardState: DefaultGenesisRewardState, SavingsRewardState: DefaultGenesisRewardState, + EarnRewardState: DefaultGenesisRewardState, USDXMintingClaims: DefaultUSDXClaims, HardLiquidityProviderClaims: DefaultHardClaims, DelegatorClaims: DefaultDelegatorClaims, SwapClaims: DefaultSwapClaims, SavingsClaims: DefaultSavingsClaims, + EarnClaims: DefaultEarnClaims, } } @@ -84,6 +90,9 @@ func (gs GenesisState) Validate() error { if err := gs.SavingsRewardState.Validate(); err != nil { return err } + if err := gs.EarnRewardState.Validate(); err != nil { + return err + } if err := gs.USDXMintingClaims.Validate(); err != nil { return err @@ -97,7 +106,12 @@ func (gs GenesisState) Validate() error { if err := gs.SwapClaims.Validate(); err != nil { return err } - return gs.SavingsClaims.Validate() + + if err := gs.SavingsClaims.Validate(); err != nil { + return err + } + + return gs.EarnClaims.Validate() } // NewGenesisRewardState returns a new GenesisRewardState diff --git a/x/incentive/types/genesis.pb.go b/x/incentive/types/genesis.pb.go index ff2a35c3..3178c213 100644 --- a/x/incentive/types/genesis.pb.go +++ b/x/incentive/types/genesis.pb.go @@ -119,6 +119,8 @@ type GenesisState struct { SwapClaims SwapClaims `protobuf:"bytes,10,rep,name=swap_claims,json=swapClaims,proto3,castrepeated=SwapClaims" json:"swap_claims"` SavingsRewardState GenesisRewardState `protobuf:"bytes,11,opt,name=savings_reward_state,json=savingsRewardState,proto3" json:"savings_reward_state"` SavingsClaims SavingsClaims `protobuf:"bytes,12,rep,name=savings_claims,json=savingsClaims,proto3,castrepeated=SavingsClaims" json:"savings_claims"` + EarnRewardState GenesisRewardState `protobuf:"bytes,13,opt,name=earn_reward_state,json=earnRewardState,proto3" json:"earn_reward_state"` + EarnClaims EarnClaims `protobuf:"bytes,14,rep,name=earn_claims,json=earnClaims,proto3,castrepeated=EarnClaims" json:"earn_claims"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -165,54 +167,57 @@ func init() { } var fileDescriptor_8b76737885d05afd = []byte{ - // 744 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x95, 0xcf, 0x4f, 0x13, 0x41, - 0x14, 0xc7, 0xbb, 0x80, 0x08, 0x53, 0xa0, 0x74, 0x2c, 0x50, 0x4b, 0xb2, 0x45, 0x20, 0xda, 0x68, - 0xdc, 0x0d, 0xf5, 0xea, 0xc5, 0x95, 0x44, 0x49, 0x24, 0x21, 0x5b, 0x34, 0xc6, 0x98, 0x34, 0xb3, - 0xdd, 0x61, 0x19, 0xdd, 0x5f, 0xee, 0xec, 0xb6, 0xf4, 0xe6, 0xd1, 0x9b, 0xfc, 0x01, 0x26, 0xde, - 0xfd, 0x4b, 0x38, 0x72, 0xf4, 0x04, 0x5a, 0xfe, 0x11, 0x33, 0xb3, 0xb3, 0x65, 0xb7, 0x65, 0x31, - 0xe2, 0x6d, 0xfa, 0xe6, 0xbd, 0xef, 0xe7, 0x3b, 0xf3, 0xde, 0x76, 0xc0, 0xe6, 0x47, 0xd4, 0x45, - 0x2a, 0x71, 0x3b, 0xd8, 0x0d, 0x49, 0x17, 0xab, 0xdd, 0x2d, 0x03, 0x87, 0x68, 0x4b, 0xb5, 0xb0, - 0x8b, 0x29, 0xa1, 0x8a, 0x1f, 0x78, 0xa1, 0x07, 0x97, 0x59, 0x96, 0x32, 0xcc, 0x52, 0x44, 0x56, - 0xad, 0x62, 0x79, 0x96, 0xc7, 0x53, 0x54, 0xb6, 0x8a, 0xb3, 0x6b, 0x1b, 0x39, 0x9a, 0x1d, 0x1b, - 0x11, 0x87, 0xfe, 0x25, 0xc9, 0x47, 0x01, 0x1a, 0x26, 0xd5, 0x2d, 0xcf, 0xb3, 0x6c, 0xac, 0xf2, - 0x5f, 0x46, 0x74, 0xa0, 0x86, 0xc4, 0xc1, 0x34, 0x44, 0x8e, 0x1f, 0x27, 0xac, 0x7f, 0x97, 0xc0, - 0xe2, 0xb3, 0x4e, 0x27, 0x72, 0x22, 0x1b, 0x85, 0xc4, 0x73, 0xf7, 0x89, 0x83, 0xe1, 0x03, 0x50, - 0xea, 0x78, 0xb6, 0x8d, 0x42, 0x1c, 0x20, 0xbb, 0x1d, 0xf6, 0x7d, 0x5c, 0x95, 0xd6, 0xa4, 0xc6, - 0xac, 0xbe, 0x70, 0x19, 0xde, 0xef, 0xfb, 0x18, 0x1a, 0xa0, 0xe6, 0x07, 0xb8, 0x4b, 0xbc, 0x88, - 0xb6, 0x51, 0x4a, 0xa5, 0xcd, 0x30, 0xd5, 0x89, 0x35, 0xa9, 0x51, 0x6c, 0xd6, 0x94, 0xd8, 0x83, - 0x92, 0x78, 0x50, 0xf6, 0x13, 0x0f, 0xda, 0xcc, 0xc9, 0x59, 0xbd, 0x70, 0x7c, 0x5e, 0x97, 0xf4, - 0x6a, 0xa2, 0x33, 0x6a, 0x66, 0xfd, 0xf3, 0x04, 0x80, 0x2f, 0xe2, 0xcb, 0xd4, 0x71, 0x0f, 0x05, - 0x66, 0x2b, 0x44, 0x21, 0x86, 0x01, 0x80, 0x63, 0x44, 0x5a, 0x95, 0xd6, 0x26, 0x1b, 0xc5, 0x66, - 0x43, 0xb9, 0xfa, 0xba, 0x95, 0x51, 0x71, 0xed, 0x2e, 0x33, 0xf0, 0xe3, 0xbc, 0x5e, 0x1e, 0xdd, - 0xa1, 0x7a, 0x19, 0x8d, 0x86, 0x60, 0x17, 0x54, 0x9c, 0xc8, 0x0e, 0x49, 0x3b, 0xe0, 0x46, 0xda, - 0xc4, 0x35, 0xf1, 0x11, 0xa6, 0xd5, 0x89, 0xeb, 0xa9, 0xbb, 0xac, 0x26, 0xf6, 0xbe, 0xc3, 0x2a, - 0xb4, 0x9a, 0xa0, 0xc2, 0xd1, 0x1d, 0x4c, 0x75, 0xe8, 0x8c, 0xc5, 0xd6, 0xbf, 0x02, 0x30, 0x27, - 0xae, 0x20, 0x3e, 0xfc, 0x53, 0x30, 0x1d, 0xb7, 0x99, 0xf7, 0xa5, 0xd8, 0x94, 0xf3, 0xd0, 0x7b, - 0x3c, 0x4b, 0x9b, 0x62, 0x40, 0x5d, 0xd4, 0x40, 0x0f, 0x94, 0x23, 0x6a, 0x1e, 0x25, 0xa7, 0xa0, - 0x4c, 0x52, 0x34, 0xeb, 0x61, 0x9e, 0xd0, 0x78, 0x07, 0xb4, 0x15, 0x26, 0x3a, 0x38, 0xab, 0x97, - 0x5e, 0xb7, 0xb6, 0xdf, 0xa6, 0x36, 0xf4, 0x12, 0x53, 0x4f, 0xf7, 0x8a, 0x80, 0xea, 0x21, 0x27, - 0x45, 0xbe, 0x6f, 0xf7, 0xb3, 0xdc, 0xc9, 0x7f, 0xe6, 0xc6, 0x87, 0x59, 0x62, 0x8a, 0x2d, 0x2e, - 0x78, 0x15, 0xca, 0xf0, 0x82, 0xc0, 0xeb, 0x65, 0x51, 0x53, 0xff, 0x83, 0xd2, 0xb8, 0x60, 0x1a, - 0x75, 0x00, 0x96, 0x4d, 0x6c, 0x63, 0x0b, 0x85, 0x5e, 0x90, 0x05, 0xdd, 0xba, 0x21, 0xa8, 0x32, - 0xd4, 0x4b, 0x73, 0xde, 0x83, 0x32, 0xed, 0x21, 0x3f, 0x8b, 0x98, 0xbe, 0x21, 0xa2, 0xc4, 0xa4, - 0xd2, 0xea, 0x5f, 0x24, 0x70, 0x87, 0x4f, 0x83, 0x43, 0xdc, 0x90, 0xb8, 0x56, 0x3b, 0xfe, 0x93, - 0xa9, 0xde, 0xbe, 0x7e, 0xa6, 0x59, 0xcf, 0x77, 0xe3, 0x8a, 0xe7, 0xac, 0x40, 0x53, 0xc4, 0x34, - 0x94, 0x47, 0x77, 0x28, 0xfb, 0xbc, 0xc6, 0x82, 0x3a, 0x1f, 0xc1, 0x4c, 0x08, 0x7e, 0x93, 0x80, - 0xcc, 0x9b, 0x67, 0x93, 0x4f, 0x11, 0x31, 0x49, 0xd8, 0x6f, 0xfb, 0x81, 0xd7, 0x25, 0x26, 0x0e, - 0x12, 0x57, 0x33, 0xdc, 0x55, 0x33, 0xcf, 0xd5, 0x4b, 0x14, 0x98, 0xaf, 0x92, 0xe2, 0x3d, 0x51, - 0x1b, 0xfb, 0xdb, 0x10, 0xdf, 0xdc, 0x6a, 0x7e, 0x0e, 0xd5, 0x57, 0x0f, 0xf3, 0x37, 0xe1, 0x07, - 0xb0, 0x78, 0xd9, 0x6f, 0xe1, 0x67, 0x96, 0xfb, 0xb9, 0x9f, 0xe7, 0x67, 0x3b, 0xc9, 0x8f, 0x3d, - 0xac, 0x08, 0x0f, 0xa5, 0x6c, 0x9c, 0xea, 0x25, 0x33, 0x1b, 0x80, 0x6f, 0x40, 0x91, 0xf7, 0x5c, - 0x60, 0x00, 0xc7, 0xdc, 0xcb, 0xc3, 0xb4, 0x7a, 0xc8, 0x8f, 0x09, 0x50, 0x10, 0xc0, 0x30, 0x44, - 0x75, 0x40, 0x87, 0x6b, 0x68, 0x80, 0x0a, 0x45, 0x5d, 0xe2, 0x5a, 0x34, 0x3b, 0x4e, 0xc5, 0x1b, - 0x8e, 0x13, 0x14, 0x6a, 0xe9, 0x89, 0x32, 0xc0, 0x42, 0xc2, 0x10, 0xf6, 0xe7, 0xb8, 0xfd, 0xcd, - 0x5c, 0xfb, 0x71, 0x76, 0x7c, 0x82, 0x25, 0x71, 0x82, 0xf9, 0x74, 0x94, 0xea, 0xf3, 0x34, 0xfd, - 0x53, 0xdb, 0x39, 0xf9, 0x2d, 0x17, 0x4e, 0x06, 0xb2, 0x74, 0x3a, 0x90, 0xa5, 0x5f, 0x03, 0x59, - 0x3a, 0xbe, 0x90, 0x0b, 0xa7, 0x17, 0x72, 0xe1, 0xe7, 0x85, 0x5c, 0x78, 0xf7, 0xc8, 0x22, 0xe1, - 0x61, 0x64, 0x28, 0x1d, 0xcf, 0x51, 0x19, 0xf3, 0xb1, 0x8d, 0x0c, 0xca, 0x57, 0xea, 0x51, 0xea, - 0xc5, 0x64, 0x0f, 0x1b, 0x35, 0xa6, 0xf9, 0xbb, 0xf4, 0xe4, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xfd, 0x2b, 0xb5, 0x5f, 0xc9, 0x07, 0x00, 0x00, + // 785 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x95, 0xcf, 0x4f, 0xdb, 0x48, + 0x14, 0xc7, 0x63, 0x60, 0x59, 0x98, 0x00, 0x21, 0xb3, 0x01, 0xb2, 0x41, 0x72, 0x58, 0x40, 0xbb, + 0xd1, 0x56, 0xb5, 0x45, 0x7a, 0xed, 0xa5, 0x2e, 0x55, 0x8b, 0x54, 0x24, 0xe4, 0x50, 0x54, 0x55, + 0x95, 0xa2, 0x71, 0x3c, 0x98, 0x69, 0xfd, 0xab, 0x1e, 0x3b, 0x21, 0xb7, 0x1e, 0x7b, 0xe4, 0x0f, + 0xa8, 0xd4, 0x7b, 0xff, 0x8f, 0x4a, 0x1c, 0x39, 0xf6, 0x04, 0x6d, 0xf8, 0x47, 0xaa, 0x19, 0x8f, + 0x83, 0x9d, 0x60, 0xaa, 0xa6, 0xb7, 0xc9, 0x9b, 0x37, 0xdf, 0xcf, 0xf7, 0xcd, 0x7b, 0x13, 0x83, + 0xed, 0xb7, 0xa8, 0x8b, 0x54, 0xe2, 0x76, 0xb0, 0x1b, 0x92, 0x2e, 0x56, 0xbb, 0x3b, 0x06, 0x0e, + 0xd1, 0x8e, 0x6a, 0x61, 0x17, 0x53, 0x42, 0x15, 0x3f, 0xf0, 0x42, 0x0f, 0xae, 0xb2, 0x2c, 0x65, + 0x98, 0xa5, 0x88, 0xac, 0x5a, 0xc5, 0xf2, 0x2c, 0x8f, 0xa7, 0xa8, 0x6c, 0x15, 0x67, 0xd7, 0xb6, + 0x72, 0x34, 0x3b, 0x36, 0x22, 0x0e, 0xfd, 0x49, 0x92, 0x8f, 0x02, 0x34, 0x4c, 0xaa, 0x5b, 0x9e, + 0x67, 0xd9, 0x58, 0xe5, 0xbf, 0x8c, 0xe8, 0x58, 0x0d, 0x89, 0x83, 0x69, 0x88, 0x1c, 0x3f, 0x4e, + 0xd8, 0xfc, 0x24, 0x81, 0xe5, 0x47, 0x9d, 0x4e, 0xe4, 0x44, 0x36, 0x0a, 0x89, 0xe7, 0x1e, 0x12, + 0x07, 0xc3, 0xff, 0x40, 0xa9, 0xe3, 0xd9, 0x36, 0x0a, 0x71, 0x80, 0xec, 0x76, 0xd8, 0xf7, 0x71, + 0x55, 0xda, 0x90, 0x1a, 0xf3, 0xfa, 0xd2, 0x4d, 0xf8, 0xb0, 0xef, 0x63, 0x68, 0x80, 0x9a, 0x1f, + 0xe0, 0x2e, 0xf1, 0x22, 0xda, 0x46, 0x29, 0x95, 0x36, 0xc3, 0x54, 0xa7, 0x36, 0xa4, 0x46, 0xb1, + 0x59, 0x53, 0x62, 0x0f, 0x4a, 0xe2, 0x41, 0x39, 0x4c, 0x3c, 0x68, 0x73, 0xe7, 0x97, 0xf5, 0xc2, + 0xd9, 0x55, 0x5d, 0xd2, 0xab, 0x89, 0xce, 0xa8, 0x99, 0xcd, 0xf7, 0x53, 0x00, 0x3e, 0x8d, 0x2f, + 0x53, 0xc7, 0x3d, 0x14, 0x98, 0xad, 0x10, 0x85, 0x18, 0x06, 0x00, 0x8e, 0x11, 0x69, 0x55, 0xda, + 0x98, 0x6e, 0x14, 0x9b, 0x0d, 0xe5, 0xf6, 0xeb, 0x56, 0x46, 0xc5, 0xb5, 0xbf, 0x99, 0x81, 0xcf, + 0x57, 0xf5, 0xf2, 0xe8, 0x0e, 0xd5, 0xcb, 0x68, 0x34, 0x04, 0xbb, 0xa0, 0xe2, 0x44, 0x76, 0x48, + 0xda, 0x01, 0x37, 0xd2, 0x26, 0xae, 0x89, 0x4f, 0x31, 0xad, 0x4e, 0xdd, 0x4d, 0xdd, 0x67, 0x67, + 0x62, 0xef, 0x7b, 0xec, 0x84, 0x56, 0x13, 0x54, 0x38, 0xba, 0x83, 0xa9, 0x0e, 0x9d, 0xb1, 0xd8, + 0xe6, 0x97, 0x22, 0x58, 0x10, 0x57, 0x10, 0x17, 0xff, 0x10, 0xcc, 0xc6, 0x6d, 0xe6, 0x7d, 0x29, + 0x36, 0xe5, 0x3c, 0xf4, 0x01, 0xcf, 0xd2, 0x66, 0x18, 0x50, 0x17, 0x67, 0xa0, 0x07, 0xca, 0x11, + 0x35, 0x4f, 0x93, 0x2a, 0x28, 0x93, 0x14, 0xcd, 0xfa, 0x3f, 0x4f, 0x68, 0xbc, 0x03, 0xda, 0x1a, + 0x13, 0x1d, 0x5c, 0xd6, 0x4b, 0x2f, 0x5a, 0xbb, 0x2f, 0x53, 0x1b, 0x7a, 0x89, 0xa9, 0xa7, 0x7b, + 0x45, 0x40, 0xf5, 0x84, 0x93, 0x22, 0xdf, 0xb7, 0xfb, 0x59, 0xee, 0xf4, 0x2f, 0x73, 0xe3, 0x62, + 0x56, 0x98, 0x62, 0x8b, 0x0b, 0xde, 0x86, 0x32, 0xbc, 0x20, 0xf0, 0x7a, 0x59, 0xd4, 0xcc, 0xef, + 0xa0, 0x34, 0x2e, 0x98, 0x46, 0x1d, 0x83, 0x55, 0x13, 0xdb, 0xd8, 0x42, 0xa1, 0x17, 0x64, 0x41, + 0x7f, 0x4c, 0x08, 0xaa, 0x0c, 0xf5, 0xd2, 0x9c, 0xd7, 0xa0, 0x4c, 0x7b, 0xc8, 0xcf, 0x22, 0x66, + 0x27, 0x44, 0x94, 0x98, 0x54, 0x5a, 0xfd, 0x83, 0x04, 0xfe, 0xe2, 0xd3, 0xe0, 0x10, 0x37, 0x24, + 0xae, 0xd5, 0x8e, 0xff, 0x64, 0xaa, 0x7f, 0xde, 0x3d, 0xd3, 0xac, 0xe7, 0xfb, 0xf1, 0x89, 0xc7, + 0xec, 0x80, 0xa6, 0x88, 0x69, 0x28, 0x8f, 0xee, 0x50, 0xf6, 0xbc, 0xc6, 0x82, 0x3a, 0x1f, 0xc1, + 0x4c, 0x08, 0x7e, 0x94, 0x80, 0xcc, 0x9b, 0x67, 0x93, 0x77, 0x11, 0x31, 0x49, 0xd8, 0x6f, 0xfb, + 0x81, 0xd7, 0x25, 0x26, 0x0e, 0x12, 0x57, 0x73, 0xdc, 0x55, 0x33, 0xcf, 0xd5, 0x33, 0x14, 0x98, + 0xcf, 0x93, 0xc3, 0x07, 0xe2, 0x6c, 0xec, 0x6f, 0x4b, 0xbc, 0xb9, 0xf5, 0xfc, 0x1c, 0xaa, 0xaf, + 0x9f, 0xe4, 0x6f, 0xc2, 0x37, 0x60, 0xf9, 0xa6, 0xdf, 0xc2, 0xcf, 0x3c, 0xf7, 0xf3, 0x6f, 0x9e, + 0x9f, 0xdd, 0x24, 0x3f, 0xf6, 0xb0, 0x26, 0x3c, 0x94, 0xb2, 0x71, 0xaa, 0x97, 0xcc, 0x6c, 0x00, + 0x1e, 0x81, 0x22, 0xef, 0xb9, 0xc0, 0x00, 0x8e, 0xf9, 0x27, 0x0f, 0xd3, 0xea, 0x21, 0x3f, 0x26, + 0x40, 0x41, 0x00, 0xc3, 0x10, 0xd5, 0x01, 0x1d, 0xae, 0xa1, 0x01, 0x2a, 0x14, 0x75, 0x89, 0x6b, + 0xd1, 0xec, 0x38, 0x15, 0x27, 0x1c, 0x27, 0x28, 0xd4, 0xd2, 0x13, 0x65, 0x80, 0xa5, 0x84, 0x21, + 0xec, 0x2f, 0x70, 0xfb, 0xdb, 0xb9, 0xf6, 0xe3, 0xec, 0xb8, 0x82, 0x15, 0x51, 0xc1, 0x62, 0x3a, + 0x4a, 0xf5, 0x45, 0x9a, 0xfe, 0xc9, 0xde, 0x04, 0x46, 0x81, 0x9b, 0x2d, 0x62, 0x71, 0xd2, 0x37, + 0xc1, 0xa4, 0xd2, 0x15, 0x1c, 0x81, 0x22, 0x57, 0x17, 0xf6, 0x97, 0xee, 0xbe, 0xfd, 0x27, 0x28, + 0x70, 0x47, 0x6e, 0x7f, 0x18, 0xa2, 0x3a, 0xc0, 0xc3, 0xb5, 0xb6, 0x77, 0xfe, 0x5d, 0x2e, 0x9c, + 0x0f, 0x64, 0xe9, 0x62, 0x20, 0x4b, 0xdf, 0x06, 0xb2, 0x74, 0x76, 0x2d, 0x17, 0x2e, 0xae, 0xe5, + 0xc2, 0xd7, 0x6b, 0xb9, 0xf0, 0xea, 0x9e, 0x45, 0xc2, 0x93, 0xc8, 0x50, 0x3a, 0x9e, 0xa3, 0x32, + 0xd4, 0x7d, 0x1b, 0x19, 0x94, 0xaf, 0xd4, 0xd3, 0xd4, 0x77, 0x9e, 0x7d, 0x8e, 0xa9, 0x31, 0xcb, + 0xbf, 0xa6, 0x0f, 0x7e, 0x04, 0x00, 0x00, 0xff, 0xff, 0x40, 0x8f, 0xb7, 0x18, 0x7f, 0x08, 0x00, + 0x00, } func (m *AccumulationTime) Marshal() (dAtA []byte, err error) { @@ -324,6 +329,30 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.EarnClaims) > 0 { + for iNdEx := len(m.EarnClaims) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.EarnClaims[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x72 + } + } + { + size, err := m.EarnRewardState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x6a if len(m.SavingsClaims) > 0 { for iNdEx := len(m.SavingsClaims) - 1; iNdEx >= 0; iNdEx-- { { @@ -564,6 +593,14 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + l = m.EarnRewardState.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.EarnClaims) > 0 { + for _, e := range m.EarnClaims { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } return n } @@ -1236,6 +1273,73 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EarnRewardState", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.EarnRewardState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EarnClaims", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EarnClaims = append(m.EarnClaims, EarnClaim{}) + if err := m.EarnClaims[len(m.EarnClaims)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/incentive/types/genesis_test.go b/x/incentive/types/genesis_test.go index 87a70bad..c3fa9f8f 100644 --- a/x/incentive/types/genesis_test.go +++ b/x/incentive/types/genesis_test.go @@ -46,6 +46,7 @@ func TestGenesisState_Validate(t *testing.T) { DefaultMultiRewardPeriods, DefaultMultiRewardPeriods, DefaultMultiRewardPeriods, + DefaultMultiRewardPeriods, MultipliersPerDenoms{ { Denom: "ukava", diff --git a/x/incentive/types/keys.go b/x/incentive/types/keys.go index f3caca0f..db921b3d 100644 --- a/x/incentive/types/keys.go +++ b/x/incentive/types/keys.go @@ -36,4 +36,7 @@ var ( SavingsClaimKeyPrefix = []byte{0x15} // prefix for keys that store savings claims SavingsRewardIndexesKeyPrefix = []byte{0x16} // prefix for key that stores savings reward indexes PreviousSavingsRewardAccrualTimeKeyPrefix = []byte{0x17} // prefix for key that stores the previous time savings rewards accrued + EarnClaimKeyPrefix = []byte{0x18} // prefix for keys that store earn claims + EarnRewardIndexesKeyPrefix = []byte{0x19} // prefix for key that stores earn reward indexes + PreviousEarnRewardAccrualTimeKeyPrefix = []byte{0x20} // prefix for key that stores the previous time earn rewards accrued ) diff --git a/x/incentive/types/msg.go b/x/incentive/types/msg.go index 4b0578d1..bcaa1b66 100644 --- a/x/incentive/types/msg.go +++ b/x/incentive/types/msg.go @@ -3,18 +3,35 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx" ) const MaxDenomsToClaim = 1000 // ensure Msg interface compliance at compile time -var _ sdk.Msg = &MsgClaimUSDXMintingReward{} - var ( + _ sdk.Msg = &MsgClaimUSDXMintingReward{} _ sdk.Msg = &MsgClaimHardReward{} _ sdk.Msg = &MsgClaimDelegatorReward{} _ sdk.Msg = &MsgClaimSwapReward{} _ sdk.Msg = &MsgClaimSavingsReward{} + _ sdk.Msg = &MsgClaimEarnReward{} + + _ legacytx.LegacyMsg = &MsgClaimUSDXMintingReward{} + _ legacytx.LegacyMsg = &MsgClaimHardReward{} + _ legacytx.LegacyMsg = &MsgClaimDelegatorReward{} + _ legacytx.LegacyMsg = &MsgClaimSwapReward{} + _ legacytx.LegacyMsg = &MsgClaimSavingsReward{} + _ legacytx.LegacyMsg = &MsgClaimEarnReward{} +) + +const ( + TypeMsgClaimUSDXMintingReward = "claim_usdx_minting_reward" + TypeMsgClaimHardReward = "claim_hard_reward" + TypeMsgClaimDelegatorReward = "claim_delegator_reward" + TypeMsgClaimSwapReward = "claim_swap_reward" + TypeMsgClaimSavingsReward = "claim_savings_reward" + TypeMsgClaimEarnReward = "claim_earn_reward" ) // NewMsgClaimUSDXMintingReward returns a new MsgClaimUSDXMintingReward. @@ -29,7 +46,7 @@ func NewMsgClaimUSDXMintingReward(sender string, multiplierName string) MsgClaim func (msg MsgClaimUSDXMintingReward) Route() string { return RouterKey } // Type returns a human-readable string for the message, intended for utilization within tags. -func (msg MsgClaimUSDXMintingReward) Type() string { return "claim_usdx_minting_reward" } +func (msg MsgClaimUSDXMintingReward) Type() string { return TypeMsgClaimUSDXMintingReward } // ValidateBasic does a simple validation check that doesn't require access to state. func (msg MsgClaimUSDXMintingReward) ValidateBasic() error { @@ -71,7 +88,7 @@ func (msg MsgClaimHardReward) Route() string { return RouterKey } // Type returns a human-readable string for the message, intended for utilization within tags. func (msg MsgClaimHardReward) Type() string { - return "claim_hard_reward" + return TypeMsgClaimHardReward } // ValidateBasic does a simple validation check that doesn't require access to state. @@ -114,7 +131,7 @@ func (msg MsgClaimDelegatorReward) Route() string { return RouterKey } // Type returns a human-readable string for the message, intended for utilization within tags. func (msg MsgClaimDelegatorReward) Type() string { - return "claim_delegator_reward" + return TypeMsgClaimDelegatorReward } // ValidateBasic does a simple validation check that doesn't require access to state. @@ -157,7 +174,7 @@ func (msg MsgClaimSwapReward) Route() string { return RouterKey } // Type returns a human-readable string for the message, intended for utilization within tags. func (msg MsgClaimSwapReward) Type() string { - return "claim_swap_reward" + return TypeMsgClaimSwapReward } // ValidateBasic does a simple validation check that doesn't require access to state. @@ -200,7 +217,7 @@ func (msg MsgClaimSavingsReward) Route() string { return RouterKey } // Type returns a human-readable string for the message, intended for utilization within tags. func (msg MsgClaimSavingsReward) Type() string { - return "claim_savings_reward" + return TypeMsgClaimSavingsReward } // ValidateBasic does a simple validation check that doesn't require access to state. @@ -229,3 +246,46 @@ func (msg MsgClaimSavingsReward) GetSigners() []sdk.AccAddress { } return []sdk.AccAddress{sender} } + +// NewMsgClaimEarnReward returns a new MsgClaimEarnReward. +func NewMsgClaimEarnReward(sender string, denomsToClaim Selections) MsgClaimEarnReward { + return MsgClaimEarnReward{ + Sender: sender, + DenomsToClaim: denomsToClaim, + } +} + +// Route return the message type used for routing the message. +func (msg MsgClaimEarnReward) Route() string { return RouterKey } + +// Type returns a human-readable string for the message, intended for utilization within tags. +func (msg MsgClaimEarnReward) Type() string { + return TypeMsgClaimEarnReward +} + +// ValidateBasic does a simple validation check that doesn't require access to state. +func (msg MsgClaimEarnReward) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty or invalid") + } + if err := msg.DenomsToClaim.Validate(); err != nil { + return err + } + return nil +} + +// GetSignBytes gets the canonical byte representation of the Msg. +func (msg MsgClaimEarnReward) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(&msg) + return sdk.MustSortJSON(bz) +} + +// GetSigners returns the addresses of signers that must sign. +func (msg MsgClaimEarnReward) GetSigners() []sdk.AccAddress { + sender, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + panic(err) + } + return []sdk.AccAddress{sender} +} diff --git a/x/incentive/types/params.go b/x/incentive/types/params.go index 62394944..05184a7f 100644 --- a/x/incentive/types/params.go +++ b/x/incentive/types/params.go @@ -21,6 +21,7 @@ var ( KeyDelegatorRewardPeriods = []byte("DelegatorRewardPeriods") KeySwapRewardPeriods = []byte("SwapRewardPeriods") KeySavingsRewardPeriods = []byte("SavingsRewardPeriods") + KeyEarnRewardPeriods = []byte("EarnRewardPeriods") KeyClaimEnd = []byte("ClaimEnd") KeyMultipliers = []byte("ClaimMultipliers") @@ -37,8 +38,12 @@ var ( ) // NewParams returns a new params object -func NewParams(usdxMinting RewardPeriods, hardSupply, hardBorrow, delegator, swap, - savings MultiRewardPeriods, multipliers MultipliersPerDenoms, claimEnd time.Time, +func NewParams( + usdxMinting RewardPeriods, + // MultiRewardPeriods + hardSupply, hardBorrow, delegator, swap, savings, earn MultiRewardPeriods, + multipliers MultipliersPerDenoms, + claimEnd time.Time, ) Params { return Params{ USDXMintingRewardPeriods: usdxMinting, @@ -61,6 +66,7 @@ func DefaultParams() Params { DefaultMultiRewardPeriods, DefaultMultiRewardPeriods, DefaultMultiRewardPeriods, + DefaultMultiRewardPeriods, DefaultMultipliers, DefaultClaimEnd, ) @@ -80,6 +86,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeyDelegatorRewardPeriods, &p.DelegatorRewardPeriods, validateMultiRewardPeriodsParam), paramtypes.NewParamSetPair(KeySwapRewardPeriods, &p.SwapRewardPeriods, validateMultiRewardPeriodsParam), paramtypes.NewParamSetPair(KeySavingsRewardPeriods, &p.SavingsRewardPeriods, validateMultiRewardPeriodsParam), + paramtypes.NewParamSetPair(KeyEarnRewardPeriods, &p.EarnRewardPeriods, validateMultiRewardPeriodsParam), paramtypes.NewParamSetPair(KeyMultipliers, &p.ClaimMultipliers, validateMultipliersPerDenomParam), paramtypes.NewParamSetPair(KeyClaimEnd, &p.ClaimEnd, validateClaimEndParam), } @@ -115,6 +122,10 @@ func (p Params) Validate() error { return err } + if err := validateMultiRewardPeriodsParam(p.EarnRewardPeriods); err != nil { + return err + } + return nil } diff --git a/x/incentive/types/params.pb.go b/x/incentive/types/params.pb.go index 6c45105c..69582b02 100644 --- a/x/incentive/types/params.pb.go +++ b/x/incentive/types/params.pb.go @@ -202,6 +202,7 @@ type Params struct { ClaimMultipliers MultipliersPerDenoms `protobuf:"bytes,6,rep,name=claim_multipliers,json=claimMultipliers,proto3,castrepeated=MultipliersPerDenoms" json:"claim_multipliers"` ClaimEnd time.Time `protobuf:"bytes,7,opt,name=claim_end,json=claimEnd,proto3,stdtime" json:"claim_end"` SavingsRewardPeriods MultiRewardPeriods `protobuf:"bytes,8,rep,name=savings_reward_periods,json=savingsRewardPeriods,proto3,castrepeated=MultiRewardPeriods" json:"savings_reward_periods"` + EarnRewardPeriods MultiRewardPeriods `protobuf:"bytes,9,rep,name=earn_reward_periods,json=earnRewardPeriods,proto3,castrepeated=MultiRewardPeriods" json:"earn_reward_periods"` } func (m *Params) Reset() { *m = Params{} } @@ -250,55 +251,56 @@ func init() { } var fileDescriptor_bb8833f5d745eac9 = []byte{ - // 760 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x96, 0x4f, 0x4f, 0x13, 0x4f, - 0x18, 0xc7, 0xbb, 0xfd, 0x47, 0x19, 0xe0, 0xf7, 0x83, 0xa1, 0xa9, 0x6b, 0x35, 0x5b, 0x52, 0x8c, - 0xd6, 0x10, 0x76, 0x45, 0x13, 0x0f, 0xde, 0x5c, 0xd1, 0xc4, 0x44, 0x12, 0xb2, 0x60, 0xa2, 0x5e, - 0x9a, 0xe9, 0xee, 0xb0, 0x6c, 0xd8, 0xdd, 0xd9, 0xcc, 0x4c, 0x0b, 0x8d, 0x07, 0x13, 0x0f, 0xde, - 0x4c, 0x88, 0x07, 0x5f, 0x04, 0x6f, 0xc3, 0x0b, 0x47, 0x8e, 0x46, 0x13, 0xd0, 0xf2, 0x46, 0xcc, - 0xcc, 0x2e, 0x74, 0x5b, 0x0b, 0x4a, 0xd2, 0x8b, 0x27, 0x66, 0x9e, 0x79, 0x9e, 0xe7, 0xf3, 0x9d, - 0x2f, 0xfb, 0x4c, 0x0a, 0x16, 0x77, 0x50, 0x07, 0x19, 0x5e, 0x68, 0xe3, 0x90, 0x7b, 0x1d, 0x6c, - 0x74, 0x56, 0x5a, 0x98, 0xa3, 0x15, 0x23, 0x42, 0x14, 0x05, 0x4c, 0x8f, 0x28, 0xe1, 0x04, 0x56, - 0x44, 0x92, 0x7e, 0x9e, 0xa4, 0x27, 0x49, 0xd5, 0xb2, 0x4b, 0x5c, 0x22, 0x53, 0x0c, 0xb1, 0x8a, - 0xb3, 0xab, 0x35, 0x97, 0x10, 0xd7, 0xc7, 0x86, 0xdc, 0xb5, 0xda, 0x5b, 0x06, 0xf7, 0x02, 0xcc, - 0x38, 0x0a, 0xa2, 0x24, 0x41, 0xb3, 0x09, 0x0b, 0x08, 0x33, 0x5a, 0x88, 0xf5, 0x81, 0x36, 0xf1, - 0xc2, 0xf8, 0xbc, 0xfe, 0x29, 0x0b, 0xa6, 0x2d, 0xbc, 0x8b, 0xa8, 0xb3, 0x8e, 0xa9, 0x47, 0x1c, - 0x58, 0x01, 0x45, 0x64, 0x0b, 0xb2, 0xaa, 0x2c, 0x28, 0x8d, 0x92, 0x95, 0xec, 0xe0, 0x1d, 0xf0, - 0xbf, 0x4d, 0x7c, 0x1f, 0x71, 0x4c, 0x91, 0xdf, 0xe4, 0xdd, 0x08, 0xab, 0xd9, 0x05, 0xa5, 0x31, - 0x69, 0xfd, 0xd7, 0x0f, 0x6f, 0x76, 0x23, 0x0c, 0x1f, 0x81, 0x02, 0xe3, 0x88, 0x72, 0x35, 0xb7, - 0xa0, 0x34, 0xa6, 0xee, 0x57, 0xf5, 0x58, 0xa2, 0x7e, 0x26, 0x51, 0xdf, 0x3c, 0x93, 0x68, 0x96, - 0x0e, 0x8f, 0x6b, 0x99, 0xfd, 0x93, 0x9a, 0x62, 0xc5, 0x25, 0xf0, 0x21, 0xc8, 0xe1, 0xd0, 0x51, - 0xf3, 0x57, 0xa8, 0x14, 0x05, 0x70, 0x0d, 0x40, 0x2a, 0x2f, 0xc1, 0x9a, 0x11, 0xa6, 0x4d, 0x86, - 0x6d, 0x12, 0x3a, 0x6a, 0x41, 0xb6, 0xb9, 0xae, 0xc7, 0x16, 0xe8, 0xc2, 0x82, 0x33, 0x3b, 0xf5, - 0x27, 0xc4, 0x0b, 0xcd, 0xbc, 0xe8, 0x62, 0xcd, 0x26, 0xa5, 0xeb, 0x98, 0x6e, 0xc8, 0xc2, 0xfa, - 0x97, 0x2c, 0x98, 0x5b, 0x6b, 0xfb, 0xdc, 0xfb, 0xf7, 0x9d, 0xe9, 0x5e, 0xe0, 0x4c, 0xee, 0x72, - 0x67, 0xee, 0x89, 0x2e, 0x07, 0x27, 0xb5, 0x86, 0xeb, 0xf1, 0xed, 0x76, 0x4b, 0xb7, 0x49, 0x60, - 0x24, 0x5f, 0x52, 0xfc, 0x67, 0x99, 0x39, 0x3b, 0x86, 0xb8, 0x2b, 0x93, 0x05, 0x6c, 0x84, 0x8b, - 0x1f, 0x15, 0x00, 0xa4, 0x8b, 0x91, 0xef, 0x61, 0x0a, 0x21, 0xc8, 0x87, 0x28, 0x88, 0xcd, 0x9b, - 0xb4, 0xe4, 0x1a, 0x2e, 0x82, 0x99, 0x80, 0x84, 0x7c, 0x9b, 0x35, 0x7d, 0x62, 0xef, 0xb4, 0x23, - 0x69, 0x5c, 0xce, 0x9a, 0x8e, 0x83, 0x2f, 0x64, 0x0c, 0x3e, 0x03, 0xc5, 0x2d, 0x64, 0x73, 0x42, - 0xa5, 0x6f, 0xd3, 0xa6, 0x2e, 0xb4, 0x7d, 0x3b, 0xae, 0xdd, 0xfe, 0x0b, 0x6d, 0xab, 0xd8, 0xb6, - 0x92, 0xea, 0xfa, 0x07, 0x05, 0xcc, 0xf7, 0xf5, 0x08, 0xa1, 0xab, 0x38, 0x24, 0x01, 0x2c, 0x83, - 0x82, 0x23, 0x16, 0x89, 0xb2, 0x78, 0x03, 0x5f, 0x83, 0xa9, 0xa0, 0x9f, 0xac, 0x66, 0xa5, 0x63, - 0x75, 0x7d, 0xf4, 0x74, 0xea, 0xfd, 0xbe, 0xe6, 0x7c, 0x62, 0xdd, 0x54, 0x8a, 0x65, 0xa5, 0x7b, - 0xd5, 0xbf, 0x4f, 0x80, 0xe2, 0xba, 0x9c, 0x79, 0xf8, 0x59, 0x01, 0x37, 0xda, 0xcc, 0xd9, 0x6b, - 0x06, 0x5e, 0xc8, 0xbd, 0xd0, 0x6d, 0xc6, 0x2e, 0x8a, 0xff, 0x95, 0x47, 0x1c, 0xa6, 0x2a, 0x12, - 0x7b, 0xeb, 0x22, 0x6c, 0xfa, 0xfb, 0x34, 0x57, 0x04, 0xb8, 0x77, 0x5c, 0x53, 0x5f, 0x6e, 0xac, - 0xbe, 0x5a, 0x8b, 0xfb, 0xa5, 0x13, 0xd8, 0xc1, 0x49, 0x6d, 0x66, 0x20, 0x60, 0xa9, 0x82, 0x3d, - 0x2a, 0x15, 0xbe, 0x57, 0x40, 0x75, 0x5b, 0x28, 0x61, 0xed, 0x28, 0xf2, 0xbb, 0xc3, 0xba, 0x62, - 0x3b, 0xee, 0x5e, 0x6a, 0xc7, 0x80, 0xb8, 0x6a, 0xe2, 0x0a, 0xfc, 0xed, 0x88, 0x59, 0xd7, 0x04, - 0x68, 0x43, 0x72, 0x2e, 0x10, 0xd1, 0x22, 0x94, 0x92, 0xdd, 0x61, 0x11, 0xb9, 0xb1, 0x8b, 0x30, - 0x25, 0x67, 0x50, 0xc4, 0x3b, 0xa0, 0x3a, 0xd8, 0xc7, 0x2e, 0xe2, 0x84, 0x0e, 0x2b, 0xc8, 0x8f, - 0x53, 0x41, 0xe5, 0x1c, 0x33, 0x28, 0xa0, 0x0d, 0xe6, 0xd9, 0x2e, 0x8a, 0x86, 0xd9, 0x85, 0x71, - 0xb2, 0xe7, 0x04, 0x61, 0x10, 0xdb, 0x01, 0x73, 0xb6, 0x8f, 0xbc, 0xa0, 0x99, 0x1e, 0x83, 0xa2, - 0x84, 0x2e, 0xfd, 0x79, 0x0c, 0xce, 0xc7, 0xcb, 0xbc, 0x99, 0x60, 0xcb, 0x23, 0x0e, 0x99, 0x35, - 0x2b, 0x19, 0xa9, 0x23, 0xf8, 0x18, 0x4c, 0xc6, 0x5c, 0xf1, 0xde, 0x4d, 0x5c, 0xe1, 0xbd, 0x2b, - 0xc9, 0xb2, 0xa7, 0xa1, 0x03, 0xdf, 0x82, 0x0a, 0x43, 0x1d, 0x2f, 0x74, 0xd9, 0xb0, 0x69, 0xa5, - 0x71, 0x9a, 0x56, 0x4e, 0x20, 0x03, 0x51, 0xf3, 0xf9, 0xe1, 0x4f, 0x2d, 0x73, 0xd8, 0xd3, 0x94, - 0xa3, 0x9e, 0xa6, 0xfc, 0xe8, 0x69, 0xca, 0xfe, 0xa9, 0x96, 0x39, 0x3a, 0xd5, 0x32, 0x5f, 0x4f, - 0xb5, 0xcc, 0x9b, 0xa5, 0xd4, 0xa3, 0x25, 0x44, 0x2c, 0xfb, 0xa8, 0xc5, 0xe4, 0xca, 0xd8, 0x4b, - 0xfd, 0x34, 0x90, 0xaf, 0x57, 0xab, 0x28, 0xef, 0xfb, 0xe0, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x8f, 0x22, 0xdc, 0x69, 0x39, 0x08, 0x00, 0x00, + // 774 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, } func (m *RewardPeriod) Marshal() (dAtA []byte, err error) { @@ -546,6 +548,20 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.EarnRewardPeriods) > 0 { + for iNdEx := len(m.EarnRewardPeriods) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.EarnRewardPeriods[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + } if len(m.SavingsRewardPeriods) > 0 { for iNdEx := len(m.SavingsRewardPeriods) - 1; iNdEx >= 0; iNdEx-- { { @@ -801,6 +817,12 @@ func (m *Params) Size() (n int) { n += 1 + l + sovParams(uint64(l)) } } + if len(m.EarnRewardPeriods) > 0 { + for _, e := range m.EarnRewardPeriods { + l = e.Size() + n += 1 + l + sovParams(uint64(l)) + } + } return n } @@ -1763,6 +1785,40 @@ func (m *Params) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EarnRewardPeriods", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EarnRewardPeriods = append(m.EarnRewardPeriods, MultiRewardPeriod{}) + if err := m.EarnRewardPeriods[len(m.EarnRewardPeriods)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:]) diff --git a/x/incentive/types/querier.go b/x/incentive/types/querier.go index f46435a8..6cbffa63 100644 --- a/x/incentive/types/querier.go +++ b/x/incentive/types/querier.go @@ -11,6 +11,7 @@ const ( QueryGetDelegatorRewards = "delegator-rewards" QueryGetSwapRewards = "swap-rewards" QueryGetSavingsRewards = "savings-rewards" + QueryGetEarnRewards = "earn-rewards" QueryGetRewardFactors = "reward-factors" QueryGetParams = "parameters" @@ -46,11 +47,12 @@ type QueryGetRewardFactorsResponse struct { DelegatorRewardFactors MultiRewardIndexes `json:"delegator_reward_factors" yaml:"delegator_reward_factors"` SwapRewardFactors MultiRewardIndexes `json:"swap_reward_factors" yaml:"swap_reward_factors"` SavingsRewardFactors MultiRewardIndexes `json:"savings_reward_factors" yaml:"savings_reward_factors"` + EarnRewardFactors MultiRewardIndexes `json:"earn_reward_factors" yaml:"earn_reward_factors"` } // NewQueryGetRewardFactorsResponse returns a new instance of QueryAllRewardFactorsResponse func NewQueryGetRewardFactorsResponse(usdxMintingFactors RewardIndexes, supplyFactors, - hardBorrowFactors, delegatorFactors, swapFactors, savingsFactors MultiRewardIndexes, + hardBorrowFactors, delegatorFactors, swapFactors, savingsFactors, earnFactors MultiRewardIndexes, ) QueryGetRewardFactorsResponse { return QueryGetRewardFactorsResponse{ USDXMintingRewardFactors: usdxMintingFactors, @@ -59,5 +61,6 @@ func NewQueryGetRewardFactorsResponse(usdxMintingFactors RewardIndexes, supplyFa DelegatorRewardFactors: delegatorFactors, SwapRewardFactors: swapFactors, SavingsRewardFactors: savingsFactors, + EarnRewardFactors: earnFactors, } } diff --git a/x/incentive/types/tx.pb.go b/x/incentive/types/tx.pb.go index 53c8b5ee..7a700217 100644 --- a/x/incentive/types/tx.pb.go +++ b/x/incentive/types/tx.pb.go @@ -448,6 +448,82 @@ func (m *MsgClaimSavingsRewardResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgClaimSavingsRewardResponse proto.InternalMessageInfo +// MsgClaimEarnReward message type used to claim earn rewards +type MsgClaimEarnReward struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + DenomsToClaim Selections `protobuf:"bytes,2,rep,name=denoms_to_claim,json=denomsToClaim,proto3,castrepeated=Selections" json:"denoms_to_claim"` +} + +func (m *MsgClaimEarnReward) Reset() { *m = MsgClaimEarnReward{} } +func (m *MsgClaimEarnReward) String() string { return proto.CompactTextString(m) } +func (*MsgClaimEarnReward) ProtoMessage() {} +func (*MsgClaimEarnReward) Descriptor() ([]byte, []int) { + return fileDescriptor_b1cec058e3ff75d5, []int{11} +} +func (m *MsgClaimEarnReward) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgClaimEarnReward) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgClaimEarnReward.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgClaimEarnReward) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgClaimEarnReward.Merge(m, src) +} +func (m *MsgClaimEarnReward) XXX_Size() int { + return m.Size() +} +func (m *MsgClaimEarnReward) XXX_DiscardUnknown() { + xxx_messageInfo_MsgClaimEarnReward.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgClaimEarnReward proto.InternalMessageInfo + +// MsgClaimEarnRewardResponse defines the Msg/ClaimEarnReward response type. +type MsgClaimEarnRewardResponse struct { +} + +func (m *MsgClaimEarnRewardResponse) Reset() { *m = MsgClaimEarnRewardResponse{} } +func (m *MsgClaimEarnRewardResponse) String() string { return proto.CompactTextString(m) } +func (*MsgClaimEarnRewardResponse) ProtoMessage() {} +func (*MsgClaimEarnRewardResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b1cec058e3ff75d5, []int{12} +} +func (m *MsgClaimEarnRewardResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgClaimEarnRewardResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgClaimEarnRewardResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgClaimEarnRewardResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgClaimEarnRewardResponse.Merge(m, src) +} +func (m *MsgClaimEarnRewardResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgClaimEarnRewardResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgClaimEarnRewardResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgClaimEarnRewardResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*Selection)(nil), "kava.incentive.v1beta1.Selection") proto.RegisterType((*MsgClaimUSDXMintingReward)(nil), "kava.incentive.v1beta1.MsgClaimUSDXMintingReward") @@ -460,44 +536,47 @@ func init() { proto.RegisterType((*MsgClaimSwapRewardResponse)(nil), "kava.incentive.v1beta1.MsgClaimSwapRewardResponse") proto.RegisterType((*MsgClaimSavingsReward)(nil), "kava.incentive.v1beta1.MsgClaimSavingsReward") proto.RegisterType((*MsgClaimSavingsRewardResponse)(nil), "kava.incentive.v1beta1.MsgClaimSavingsRewardResponse") + proto.RegisterType((*MsgClaimEarnReward)(nil), "kava.incentive.v1beta1.MsgClaimEarnReward") + proto.RegisterType((*MsgClaimEarnRewardResponse)(nil), "kava.incentive.v1beta1.MsgClaimEarnRewardResponse") } func init() { proto.RegisterFile("kava/incentive/v1beta1/tx.proto", fileDescriptor_b1cec058e3ff75d5) } var fileDescriptor_b1cec058e3ff75d5 = []byte{ - // 504 bytes of a gzipped FileDescriptorProto + // 525 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x95, 0x31, 0x6f, 0xd3, 0x40, - 0x14, 0xc7, 0x7d, 0x2d, 0x54, 0xf4, 0x21, 0x88, 0x74, 0x0a, 0x21, 0x58, 0x60, 0x37, 0x61, 0xa0, - 0x02, 0xd5, 0x56, 0x82, 0x10, 0x82, 0xb1, 0x14, 0x89, 0x25, 0x0c, 0x49, 0x91, 0x10, 0x12, 0x8a, - 0x2e, 0xc9, 0x71, 0x9c, 0xb0, 0xef, 0x8c, 0xef, 0x9a, 0x16, 0x26, 0x26, 0xc4, 0xc8, 0x82, 0x84, - 0x98, 0x3a, 0xf3, 0x49, 0x3a, 0x76, 0x64, 0x02, 0x94, 0x2c, 0xec, 0x7c, 0x01, 0x14, 0x27, 0x76, - 0xa2, 0xc4, 0xc6, 0x84, 0x29, 0xdb, 0xdd, 0xbd, 0xff, 0x7b, 0xef, 0xf7, 0x9e, 0xde, 0xd3, 0x81, - 0xfd, 0x8a, 0xf4, 0x89, 0xcb, 0x45, 0x97, 0x0a, 0xcd, 0xfb, 0xd4, 0xed, 0xd7, 0x3a, 0x54, 0x93, - 0x9a, 0xab, 0x8f, 0x9c, 0x20, 0x94, 0x5a, 0xe2, 0xd2, 0x48, 0xe0, 0x24, 0x02, 0x67, 0x22, 0x30, - 0x8b, 0x4c, 0x32, 0x19, 0x49, 0xdc, 0xd1, 0x69, 0xac, 0xae, 0xee, 0xc3, 0x66, 0x8b, 0x7a, 0xb4, - 0xab, 0xb9, 0x14, 0xb8, 0x08, 0x67, 0x7b, 0x54, 0x48, 0xbf, 0x8c, 0xb6, 0xd0, 0xf6, 0x66, 0x73, - 0x7c, 0xc1, 0x37, 0xa0, 0xe0, 0x1f, 0x78, 0x9a, 0x07, 0x1e, 0xa7, 0x61, 0x5b, 0x10, 0x9f, 0x96, - 0xd7, 0x22, 0xfb, 0xc5, 0xe9, 0xf3, 0x63, 0xe2, 0xd3, 0xfb, 0xe7, 0x3e, 0x1c, 0xdb, 0xc6, 0xaf, - 0x63, 0xdb, 0xa8, 0xbe, 0x80, 0x2b, 0x0d, 0xc5, 0x1e, 0x78, 0x84, 0xfb, 0x4f, 0x5a, 0x7b, 0x4f, - 0x1b, 0x5c, 0x68, 0x2e, 0x58, 0x93, 0x1e, 0x92, 0xb0, 0x87, 0x4b, 0xb0, 0xa1, 0xa8, 0xe8, 0xd1, - 0x70, 0x92, 0x66, 0x72, 0xfb, 0x9f, 0x3c, 0xd7, 0xa1, 0x92, 0x99, 0xa7, 0x49, 0x55, 0x20, 0x85, - 0xa2, 0xd5, 0x4f, 0x08, 0x70, 0xac, 0x7a, 0x14, 0x19, 0xfe, 0x8a, 0xf1, 0x1c, 0x0a, 0x51, 0xdd, - 0xaa, 0xad, 0x65, 0xbb, 0x3b, 0x72, 0x2a, 0xaf, 0x6d, 0xad, 0x6f, 0x9f, 0xaf, 0x57, 0x9c, 0xf4, - 0xce, 0x3a, 0x49, 0x03, 0x77, 0xf1, 0xc9, 0x77, 0xdb, 0xf8, 0xfa, 0xc3, 0x86, 0xe4, 0x49, 0x35, - 0x2f, 0x8c, 0xa3, 0xed, 0xcb, 0x08, 0x60, 0x06, 0xfe, 0x2a, 0x98, 0x8b, 0x58, 0x09, 0xf5, 0x17, - 0x04, 0x97, 0x63, 0xf3, 0x1e, 0xf5, 0x28, 0x23, 0x5a, 0x86, 0xab, 0x82, 0x5e, 0x01, 0x3b, 0x83, - 0x2d, 0xb5, 0xeb, 0xad, 0x43, 0x12, 0xac, 0x60, 0xd7, 0xa7, 0x58, 0x09, 0xf5, 0x67, 0x04, 0x97, - 0x12, 0x33, 0xe9, 0x73, 0xc1, 0xd4, 0xaa, 0x80, 0xdb, 0x70, 0x2d, 0x95, 0x2c, 0x66, 0xaf, 0xff, - 0x3e, 0x03, 0xeb, 0x0d, 0xc5, 0xf0, 0x7b, 0x04, 0xa5, 0x8c, 0xd5, 0xab, 0x65, 0x31, 0x65, 0x6e, - 0x91, 0x79, 0x6f, 0x69, 0x97, 0x18, 0x08, 0xbf, 0x86, 0xc2, 0xfc, 0xd2, 0xdd, 0xcc, 0x8b, 0x36, - 0xd5, 0x9a, 0xf5, 0x7f, 0xd7, 0x26, 0x29, 0xdf, 0x21, 0x28, 0xa6, 0xae, 0x8c, 0x9b, 0x17, 0x6c, - 0xce, 0xc1, 0xbc, 0xbb, 0xa4, 0xc3, 0x42, 0xd5, 0x33, 0x43, 0x9f, 0x5b, 0xf5, 0x54, 0x9b, 0x5f, - 0xf5, 0xe2, 0xd4, 0xe2, 0xb7, 0x80, 0x53, 0x26, 0x76, 0x27, 0x37, 0xd2, 0xac, 0xdc, 0xbc, 0xb3, - 0x94, 0x3c, 0xce, 0xbd, 0xfb, 0xf0, 0x64, 0x60, 0xa1, 0xd3, 0x81, 0x85, 0x7e, 0x0e, 0x2c, 0xf4, - 0x71, 0x68, 0x19, 0xa7, 0x43, 0xcb, 0xf8, 0x36, 0xb4, 0x8c, 0x67, 0xb7, 0x18, 0xd7, 0x2f, 0x0f, - 0x3a, 0x4e, 0x57, 0xfa, 0xee, 0x28, 0xf4, 0x8e, 0x47, 0x3a, 0x2a, 0x3a, 0xb9, 0x47, 0x33, 0x1f, - 0x98, 0x7e, 0x13, 0x50, 0xd5, 0xd9, 0x88, 0xbe, 0xa3, 0xdb, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, - 0x7e, 0x03, 0x15, 0xb3, 0xdf, 0x06, 0x00, 0x00, + 0x14, 0xc7, 0x7d, 0xad, 0x5a, 0xd1, 0x87, 0x20, 0xd2, 0x29, 0x84, 0x60, 0x81, 0xdd, 0x84, 0x81, + 0x0a, 0x54, 0x5b, 0x09, 0x42, 0x08, 0xc6, 0xd2, 0x4a, 0x2c, 0x61, 0x48, 0x8a, 0x84, 0x90, 0x50, + 0x74, 0x49, 0x0e, 0x73, 0xc2, 0xbe, 0x33, 0xbe, 0x6b, 0x5a, 0x98, 0x98, 0x10, 0x23, 0x0b, 0x12, + 0x62, 0xea, 0xcc, 0x27, 0xe9, 0xd8, 0x91, 0x09, 0x50, 0x22, 0x21, 0x3e, 0x06, 0x8a, 0x93, 0xd8, + 0x56, 0x6d, 0x63, 0xd2, 0x29, 0x9b, 0xed, 0xf7, 0x7f, 0xef, 0xfd, 0xfe, 0x4f, 0x7e, 0x77, 0x60, + 0xbe, 0x26, 0x43, 0x62, 0x33, 0xde, 0xa7, 0x5c, 0xb1, 0x21, 0xb5, 0x87, 0x8d, 0x1e, 0x55, 0xa4, + 0x61, 0xab, 0x23, 0xcb, 0x0f, 0x84, 0x12, 0xb8, 0x32, 0x11, 0x58, 0x91, 0xc0, 0x9a, 0x09, 0xf4, + 0xb2, 0x23, 0x1c, 0x11, 0x4a, 0xec, 0xc9, 0xd3, 0x54, 0x5d, 0xdf, 0x87, 0x8d, 0x0e, 0x75, 0x69, + 0x5f, 0x31, 0xc1, 0x71, 0x19, 0xd6, 0x06, 0x94, 0x0b, 0xaf, 0x8a, 0x36, 0xd1, 0xd6, 0x46, 0x7b, + 0xfa, 0x82, 0x6f, 0x41, 0xc9, 0x3b, 0x70, 0x15, 0xf3, 0x5d, 0x46, 0x83, 0x2e, 0x27, 0x1e, 0xad, + 0xae, 0x84, 0xf1, 0xcb, 0xf1, 0xe7, 0x27, 0xc4, 0xa3, 0x0f, 0x2f, 0x7c, 0x3c, 0x36, 0xb5, 0x3f, + 0xc7, 0xa6, 0x56, 0x7f, 0x09, 0xd7, 0x5a, 0xd2, 0x79, 0xe4, 0x12, 0xe6, 0x3d, 0xed, 0xec, 0x3e, + 0x6b, 0x31, 0xae, 0x18, 0x77, 0xda, 0xf4, 0x90, 0x04, 0x03, 0x5c, 0x81, 0x75, 0x49, 0xf9, 0x80, + 0x06, 0xb3, 0x36, 0xb3, 0xb7, 0xf3, 0xf4, 0xb9, 0x09, 0xb5, 0xdc, 0x3e, 0x6d, 0x2a, 0x7d, 0xc1, + 0x25, 0xad, 0x7f, 0x46, 0x80, 0xe7, 0xaa, 0xc7, 0x61, 0xe0, 0x9f, 0x18, 0x2f, 0xa0, 0x14, 0xfa, + 0x96, 0x5d, 0x25, 0xba, 0xfd, 0x49, 0x52, 0x75, 0x65, 0x73, 0x75, 0xeb, 0x62, 0xb3, 0x66, 0x65, + 0x4f, 0xd6, 0x8a, 0x06, 0xb8, 0x83, 0x4f, 0x7e, 0x98, 0xda, 0xb7, 0x9f, 0x26, 0x44, 0x9f, 0x64, + 0xfb, 0xd2, 0xb4, 0xda, 0xbe, 0x08, 0x01, 0x12, 0xf0, 0xd7, 0x41, 0x4f, 0x63, 0x45, 0xd4, 0x5f, + 0x11, 0x5c, 0x9d, 0x87, 0x77, 0xa9, 0x4b, 0x1d, 0xa2, 0x44, 0xb0, 0x2c, 0xe8, 0x35, 0x30, 0x73, + 0xd8, 0x32, 0xa7, 0xde, 0x39, 0x24, 0xfe, 0x12, 0x4e, 0x3d, 0xc6, 0x8a, 0xa8, 0xbf, 0x20, 0xb8, + 0x12, 0x85, 0xc9, 0x90, 0x71, 0x47, 0x2e, 0x0b, 0xb8, 0x09, 0x37, 0x32, 0xc9, 0x32, 0x27, 0xbe, + 0x47, 0x02, 0xbe, 0x84, 0x13, 0x8f, 0xb1, 0xe6, 0xd4, 0xcd, 0xdf, 0x6b, 0xb0, 0xda, 0x92, 0x0e, + 0xfe, 0x80, 0xa0, 0x92, 0x73, 0x60, 0x34, 0xf2, 0x80, 0x72, 0x77, 0x5f, 0x7f, 0xb0, 0x70, 0xca, + 0x1c, 0x08, 0xbf, 0x81, 0xd2, 0xd9, 0xa3, 0xe2, 0x76, 0x51, 0xb5, 0x58, 0xab, 0x37, 0xff, 0x5f, + 0x1b, 0xb5, 0x7c, 0x8f, 0xa0, 0x9c, 0xb9, 0xe8, 0x76, 0x51, 0xb1, 0x33, 0x09, 0xfa, 0xfd, 0x05, + 0x13, 0x52, 0xae, 0x13, 0xab, 0x5a, 0xe8, 0x3a, 0xd6, 0x16, 0xbb, 0x4e, 0xef, 0x1a, 0x7e, 0x07, + 0x38, 0x63, 0xcf, 0xb6, 0x0b, 0x2b, 0x25, 0xe5, 0xfa, 0xbd, 0x85, 0xe4, 0x29, 0xbb, 0x89, 0x3d, + 0x29, 0xb4, 0x1b, 0x6b, 0x8b, 0xed, 0xa6, 0x7f, 0xf4, 0x9d, 0xbd, 0x93, 0x91, 0x81, 0x4e, 0x47, + 0x06, 0xfa, 0x35, 0x32, 0xd0, 0xa7, 0xb1, 0xa1, 0x9d, 0x8e, 0x0d, 0xed, 0xfb, 0xd8, 0xd0, 0x9e, + 0xdf, 0x71, 0x98, 0x7a, 0x75, 0xd0, 0xb3, 0xfa, 0xc2, 0xb3, 0x27, 0x75, 0xb7, 0x5d, 0xd2, 0x93, + 0xe1, 0x93, 0x7d, 0x94, 0xb8, 0xe9, 0xd5, 0x5b, 0x9f, 0xca, 0xde, 0x7a, 0x78, 0x6f, 0xdf, 0xfd, + 0x1b, 0x00, 0x00, 0xff, 0xff, 0x28, 0x8b, 0x70, 0xee, 0x08, 0x08, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -518,10 +597,12 @@ type MsgClient interface { ClaimHardReward(ctx context.Context, in *MsgClaimHardReward, opts ...grpc.CallOption) (*MsgClaimHardRewardResponse, error) // ClaimDelegatorReward is a message type used to claim delegator rewards ClaimDelegatorReward(ctx context.Context, in *MsgClaimDelegatorReward, opts ...grpc.CallOption) (*MsgClaimDelegatorRewardResponse, error) - // ClaimSwapReward is a message type used to claim delegator rewards + // ClaimSwapReward is a message type used to claim swap rewards ClaimSwapReward(ctx context.Context, in *MsgClaimSwapReward, opts ...grpc.CallOption) (*MsgClaimSwapRewardResponse, error) // ClaimSavingsReward is a message type used to claim savings rewards ClaimSavingsReward(ctx context.Context, in *MsgClaimSavingsReward, opts ...grpc.CallOption) (*MsgClaimSavingsRewardResponse, error) + // ClaimEarnReward is a message type used to claim earn rewards + ClaimEarnReward(ctx context.Context, in *MsgClaimEarnReward, opts ...grpc.CallOption) (*MsgClaimEarnRewardResponse, error) } type msgClient struct { @@ -577,6 +658,15 @@ func (c *msgClient) ClaimSavingsReward(ctx context.Context, in *MsgClaimSavingsR return out, nil } +func (c *msgClient) ClaimEarnReward(ctx context.Context, in *MsgClaimEarnReward, opts ...grpc.CallOption) (*MsgClaimEarnRewardResponse, error) { + out := new(MsgClaimEarnRewardResponse) + err := c.cc.Invoke(ctx, "/kava.incentive.v1beta1.Msg/ClaimEarnReward", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { // ClaimUSDXMintingReward is a message type used to claim USDX minting rewards @@ -585,10 +675,12 @@ type MsgServer interface { ClaimHardReward(context.Context, *MsgClaimHardReward) (*MsgClaimHardRewardResponse, error) // ClaimDelegatorReward is a message type used to claim delegator rewards ClaimDelegatorReward(context.Context, *MsgClaimDelegatorReward) (*MsgClaimDelegatorRewardResponse, error) - // ClaimSwapReward is a message type used to claim delegator rewards + // ClaimSwapReward is a message type used to claim swap rewards ClaimSwapReward(context.Context, *MsgClaimSwapReward) (*MsgClaimSwapRewardResponse, error) // ClaimSavingsReward is a message type used to claim savings rewards ClaimSavingsReward(context.Context, *MsgClaimSavingsReward) (*MsgClaimSavingsRewardResponse, error) + // ClaimEarnReward is a message type used to claim earn rewards + ClaimEarnReward(context.Context, *MsgClaimEarnReward) (*MsgClaimEarnRewardResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -610,6 +702,9 @@ func (*UnimplementedMsgServer) ClaimSwapReward(ctx context.Context, req *MsgClai func (*UnimplementedMsgServer) ClaimSavingsReward(ctx context.Context, req *MsgClaimSavingsReward) (*MsgClaimSavingsRewardResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ClaimSavingsReward not implemented") } +func (*UnimplementedMsgServer) ClaimEarnReward(ctx context.Context, req *MsgClaimEarnReward) (*MsgClaimEarnRewardResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ClaimEarnReward not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -705,6 +800,24 @@ func _Msg_ClaimSavingsReward_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _Msg_ClaimEarnReward_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgClaimEarnReward) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ClaimEarnReward(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/kava.incentive.v1beta1.Msg/ClaimEarnReward", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ClaimEarnReward(ctx, req.(*MsgClaimEarnReward)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "kava.incentive.v1beta1.Msg", HandlerType: (*MsgServer)(nil), @@ -729,6 +842,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "ClaimSavingsReward", Handler: _Msg_ClaimSavingsReward_Handler, }, + { + MethodName: "ClaimEarnReward", + Handler: _Msg_ClaimEarnReward_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "kava/incentive/v1beta1/tx.proto", @@ -1099,6 +1216,73 @@ func (m *MsgClaimSavingsRewardResponse) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *MsgClaimEarnReward) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgClaimEarnReward) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgClaimEarnReward) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.DenomsToClaim) > 0 { + for iNdEx := len(m.DenomsToClaim) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DenomsToClaim[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgClaimEarnRewardResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgClaimEarnRewardResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgClaimEarnRewardResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func encodeVarintTx(dAtA []byte, offset int, v uint64) int { offset -= sovTx(v) base := offset @@ -1265,6 +1449,34 @@ func (m *MsgClaimSavingsRewardResponse) Size() (n int) { return n } +func (m *MsgClaimEarnReward) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.DenomsToClaim) > 0 { + for _, e := range m.DenomsToClaim { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgClaimEarnRewardResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func sovTx(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2213,6 +2425,172 @@ func (m *MsgClaimSavingsRewardResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgClaimEarnReward) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgClaimEarnReward: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgClaimEarnReward: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DenomsToClaim", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DenomsToClaim = append(m.DenomsToClaim, Selection{}) + if err := m.DenomsToClaim[len(m.DenomsToClaim)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgClaimEarnRewardResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgClaimEarnRewardResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgClaimEarnRewardResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTx(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0