From fa57876ad8340f352bdbdf9fd5245ec898b099cf Mon Sep 17 00:00:00 2001 From: Denali Marsh Date: Fri, 2 Apr 2021 23:34:42 +0200 Subject: [PATCH] Incentive queries: unsynced claims, global reward factors (#894) * unsynced querier types * unsynced querier keeper methods * unsynced querier cli * unsynced querrier rest * reward factors querier types * reward factors querier keeper methods * reward factors querier cli * reward factors querier rest * move PostClaimReq from types to rest --- x/incentive/alias.go | 1 - x/incentive/client/cli/query.go | 169 ++++++++++++++++++++++++++---- x/incentive/client/rest/query.go | 172 +++++++++++++++++++++++++++++-- x/incentive/client/rest/rest.go | 15 +++ x/incentive/client/rest/tx.go | 4 +- x/incentive/keeper/keeper.go | 56 ++++++++++ x/incentive/keeper/querier.go | 166 +++++++++++++++++++++++++++++ x/incentive/types/querier.go | 94 ++++++++++++++--- 8 files changed, 627 insertions(+), 50 deletions(-) diff --git a/x/incentive/alias.go b/x/incentive/alias.go index 3a9703b7..d756e15e 100644 --- a/x/incentive/alias.go +++ b/x/incentive/alias.go @@ -140,7 +140,6 @@ type ( MultiplierName = types.MultiplierName Multipliers = types.Multipliers Params = types.Params - PostClaimReq = types.PostClaimReq QueryHardRewardsParams = types.QueryHardRewardsParams QueryRewardsParams = types.QueryRewardsParams QueryUSDXMintingRewardsParams = types.QueryUSDXMintingRewardsParams diff --git a/x/incentive/client/cli/query.go b/x/incentive/client/cli/query.go index 87b7bd46..5f576b21 100644 --- a/x/incentive/client/cli/query.go +++ b/x/incentive/client/cli/query.go @@ -17,8 +17,10 @@ import ( ) const ( - flagOwner = "owner" - flagType = "type" + flagOwner = "owner" + flagType = "type" + flagUnsynced = "unsynced" + flagDenom = "denom" ) // GetQueryCmd returns the cli query commands for the incentive module @@ -31,6 +33,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { incentiveQueryCmd.AddCommand(flags.GetCommands( queryParamsCmd(queryRoute, cdc), queryRewardsCmd(queryRoute, cdc), + queryRewardFactorsCmd(queryRoute, cdc), )...) return incentiveQueryCmd @@ -49,10 +52,11 @@ func queryRewardsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { $ %s query %s rewards --type hard $ %s query %s rewards --type usdx-minting $ %s query %s rewards --type hard --owner kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw + $ %s query %s rewards --type hard --unsynced true `, version.ClientName, types.ModuleName, version.ClientName, types.ModuleName, version.ClientName, types.ModuleName, version.ClientName, types.ModuleName, - version.ClientName, types.ModuleName)), + version.ClientName, types.ModuleName, version.ClientName, types.ModuleName)), Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) @@ -61,6 +65,7 @@ func queryRewardsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { limit := viper.GetInt(flags.FlagLimit) strOwner := viper.GetString(flagOwner) strType := viper.GetString(flagType) + boolUnsynced := viper.GetBool(flagUnsynced) // Prepare params for querier owner, err := sdk.AccAddressFromBech32(strOwner) @@ -70,34 +75,66 @@ func queryRewardsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { switch strings.ToLower(strType) { case "hard": - params := types.NewQueryHardRewardsParams(page, limit, owner) - claims, err := executeHardRewardsQuery(queryRoute, cdc, cliCtx, params) - if err != nil { - return err + var claims types.HardLiquidityProviderClaims + if boolUnsynced { + params := types.NewQueryHardRewardsUnsyncedParams(page, limit, owner) + claims, err = executeHardRewardsUnsyncedQuery(queryRoute, cdc, cliCtx, params) + if err != nil { + return err + } + } else { + params := types.NewQueryHardRewardsParams(page, limit, owner) + claims, err = executeHardRewardsQuery(queryRoute, cdc, cliCtx, params) + if err != nil { + return err + } } return cliCtx.PrintOutput(claims) case "usdx-minting": - params := types.NewQueryUSDXMintingRewardsParams(page, limit, owner) - claims, err := executeUSDXMintingRewardsQuery(queryRoute, cdc, cliCtx, params) - if err != nil { - return err + var claims types.USDXMintingClaims + if boolUnsynced { + params := types.NewQueryUSDXMintingRewardsUnsyncedParams(page, limit, owner) + claims, err = executeUSDXMintingRewardsUnsyncedQuery(queryRoute, cdc, cliCtx, params) + if err != nil { + return err + } + } else { + params := types.NewQueryUSDXMintingRewardsParams(page, limit, owner) + claims, err = executeUSDXMintingRewardsQuery(queryRoute, cdc, cliCtx, params) + if err != nil { + return err + } } return cliCtx.PrintOutput(claims) default: - paramsHard := types.NewQueryHardRewardsParams(page, limit, owner) - hardClaims, err := executeHardRewardsQuery(queryRoute, cdc, cliCtx, paramsHard) - if err != nil { - return err + var hardClaims types.HardLiquidityProviderClaims + var usdxMintingClaims types.USDXMintingClaims + if boolUnsynced { + paramsHard := types.NewQueryHardRewardsUnsyncedParams(page, limit, owner) + hardClaims, err = executeHardRewardsUnsyncedQuery(queryRoute, cdc, cliCtx, paramsHard) + if err != nil { + return err + } + paramsUSDXMinting := types.NewQueryUSDXMintingRewardsUnsyncedParams(page, limit, owner) + usdxMintingClaims, err = executeUSDXMintingRewardsUnsyncedQuery(queryRoute, cdc, cliCtx, paramsUSDXMinting) + if err != nil { + return err + } + } else { + paramsHard := types.NewQueryHardRewardsParams(page, limit, owner) + hardClaims, err = executeHardRewardsQuery(queryRoute, cdc, cliCtx, paramsHard) + if err != nil { + return err + } + paramsUSDXMinting := types.NewQueryUSDXMintingRewardsParams(page, limit, owner) + usdxMintingClaims, err = executeUSDXMintingRewardsQuery(queryRoute, cdc, cliCtx, paramsUSDXMinting) + if err != nil { + return err + } } if len(hardClaims) > 0 { cliCtx.PrintOutput(hardClaims) } - - paramsUSDXMinting := types.NewQueryUSDXMintingRewardsParams(page, limit, owner) - usdxMintingClaims, err := executeUSDXMintingRewardsQuery(queryRoute, cdc, cliCtx, paramsUSDXMinting) - if err != nil { - return err - } if len(usdxMintingClaims) > 0 { cliCtx.PrintOutput(usdxMintingClaims) } @@ -107,6 +144,7 @@ func queryRewardsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { } cmd.Flags().String(flagOwner, "", "(optional) filter by owner address") cmd.Flags().String(flagType, "", "(optional) filter by reward type") + cmd.Flags().String(flagUnsynced, "", "(optional) get unsynced claims") cmd.Flags().Int(flags.FlagPage, 1, "pagination page rewards of to to query for") cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit of rewards to query for") return cmd @@ -139,6 +177,49 @@ func queryParamsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { } } +func queryRewardFactorsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "reward-factors", + Short: "get current global reward factors", + Long: strings.TrimSpace(`get current global reward factors: + + Example: + $ kvcli q hard reward-factors + $ kvcli q hard reward-factors --denom bnb`, + ), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + denom := viper.GetString(flagDenom) + + // Construct query with params + params := types.NewQueryRewardFactorsParams(denom) + bz, err := cdc.MarshalJSON(params) + if err != nil { + return err + } + + // Execute query + route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetRewardFactors) + res, height, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return err + } + cliCtx = cliCtx.WithHeight(height) + + // Decode and print results + var rewardFactors types.RewardFactors + if err := cdc.UnmarshalJSON(res, &rewardFactors); err != nil { + return fmt.Errorf("failed to unmarshal reward factors: %w", err) + } + return cliCtx.PrintOutput(rewardFactors) + }, + } + cmd.Flags().String(flagDenom, "", "(optional) filter reward factors by denom") + return cmd +} + func executeHardRewardsQuery(queryRoute string, cdc *codec.Codec, cliCtx context.CLIContext, params types.QueryHardRewardsParams) (types.HardLiquidityProviderClaims, error) { bz, err := cdc.MarshalJSON(params) @@ -162,6 +243,29 @@ func executeHardRewardsQuery(queryRoute string, cdc *codec.Codec, cliCtx context return claims, nil } +func executeHardRewardsUnsyncedQuery(queryRoute string, cdc *codec.Codec, cliCtx context.CLIContext, + params types.QueryHardRewardsUnsyncedParams) (types.HardLiquidityProviderClaims, error) { + bz, err := cdc.MarshalJSON(params) + if err != nil { + return types.HardLiquidityProviderClaims{}, err + } + + route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetHardRewardsUnsynced) + res, height, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return types.HardLiquidityProviderClaims{}, err + } + + cliCtx = cliCtx.WithHeight(height) + + var claims types.HardLiquidityProviderClaims + if err := cdc.UnmarshalJSON(res, &claims); err != nil { + return types.HardLiquidityProviderClaims{}, fmt.Errorf("failed to unmarshal claims: %w", err) + } + + return claims, nil +} + func executeUSDXMintingRewardsQuery(queryRoute string, cdc *codec.Codec, cliCtx context.CLIContext, params types.QueryUSDXMintingRewardsParams) (types.USDXMintingClaims, error) { bz, err := cdc.MarshalJSON(params) @@ -184,3 +288,26 @@ func executeUSDXMintingRewardsQuery(queryRoute string, cdc *codec.Codec, cliCtx return claims, nil } + +func executeUSDXMintingRewardsUnsyncedQuery(queryRoute string, cdc *codec.Codec, cliCtx context.CLIContext, + params types.QueryUSDXMintingRewardsUnsyncedParams) (types.USDXMintingClaims, error) { + bz, err := cdc.MarshalJSON(params) + if err != nil { + return types.USDXMintingClaims{}, err + } + + route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetUSDXMintingRewardsUnsynced) + res, height, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return types.USDXMintingClaims{}, err + } + + cliCtx = cliCtx.WithHeight(height) + + var claims types.USDXMintingClaims + if err := cdc.UnmarshalJSON(res, &claims); err != nil { + return types.USDXMintingClaims{}, 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 bcf371eb..b9098f42 100644 --- a/x/incentive/client/rest/query.go +++ b/x/incentive/client/rest/query.go @@ -3,6 +3,7 @@ package rest import ( "fmt" "net/http" + "strconv" "strings" "github.com/gorilla/mux" @@ -17,6 +18,7 @@ import ( func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc(fmt.Sprintf("/%s/rewards", types.ModuleName), queryRewardsHandlerFn(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/%s/parameters", types.ModuleName), queryParamsHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/%s/reward-factors", types.ModuleName), queryRewardFactorsHandlerFn(cliCtx)).Methods("GET") } func queryRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { @@ -46,17 +48,42 @@ func queryRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { rewardType = strings.ToLower(strings.TrimSpace(x)) } - switch strings.ToLower(rewardType) { - case "hard": - params := types.NewQueryHardRewardsParams(page, limit, owner) - executeHardRewardsQuery(w, cliCtx, params) - case "usdx_minting": - params := types.NewQueryUSDXMintingRewardsParams(page, limit, owner) - executeUSDXMintingRewardsQuery(w, cliCtx, params) - default: - hardParams := types.NewQueryHardRewardsParams(page, limit, owner) - usdxMintingParams := types.NewQueryUSDXMintingRewardsParams(page, limit, owner) - executeBothRewardQueries(w, cliCtx, hardParams, usdxMintingParams) + var unsynced bool + if x := r.URL.Query().Get(types.RestUnsynced); len(x) != 0 { + unsyncedStr := strings.ToLower(strings.TrimSpace(x)) + unsynced, err = strconv.ParseBool(unsyncedStr) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("cannot parse bool from unsynced flag %s", unsyncedStr)) + return + } + } + + if unsynced { + switch strings.ToLower(rewardType) { + case "hard": + params := types.NewQueryHardRewardsUnsyncedParams(page, limit, owner) + executeHardRewardsUnsyncedQuery(w, cliCtx, params) + case "usdx_minting": + params := types.NewQueryUSDXMintingRewardsUnsyncedParams(page, limit, owner) + executeUSDXMintingRewardsUnsyncedQuery(w, cliCtx, params) + default: + hardParams := types.NewQueryHardRewardsUnsyncedParams(page, limit, owner) + usdxMintingParams := types.NewQueryUSDXMintingRewardsUnsyncedParams(page, limit, owner) + executeBothUnsyncedRewardQueries(w, cliCtx, hardParams, usdxMintingParams) + } + } else { + switch strings.ToLower(rewardType) { + case "hard": + params := types.NewQueryHardRewardsParams(page, limit, owner) + executeHardRewardsQuery(w, cliCtx, params) + case "usdx_minting": + params := types.NewQueryUSDXMintingRewardsParams(page, limit, owner) + executeUSDXMintingRewardsQuery(w, cliCtx, params) + default: + hardParams := types.NewQueryHardRewardsParams(page, limit, owner) + usdxMintingParams := types.NewQueryUSDXMintingRewardsParams(page, limit, owner) + executeBothRewardQueries(w, cliCtx, hardParams, usdxMintingParams) + } } } } @@ -81,6 +108,44 @@ func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } } +func queryRewardFactorsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + _, _, _, err := rest.ParseHTTPArgsWithLimit(r, 0) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + // Parse the query height + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + var denom string + + if x := r.URL.Query().Get(RestDenom); len(x) != 0 { + denom = strings.TrimSpace(x) + } + + params := types.NewQueryRewardFactorsParams(denom) + + bz, err := cliCtx.Codec.MarshalJSON(params) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + route := fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryGetRewardFactors) + res, height, err := cliCtx.QueryWithData(route, bz) + cliCtx = cliCtx.WithHeight(height) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + rest.PostProcessResponse(w, cliCtx, res) + } +} + func executeHardRewardsQuery(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryHardRewardsParams) { bz, err := cliCtx.Codec.MarshalJSON(params) if err != nil { @@ -98,6 +163,23 @@ func executeHardRewardsQuery(w http.ResponseWriter, cliCtx context.CLIContext, p rest.PostProcessResponse(w, cliCtx, res) } +func executeHardRewardsUnsyncedQuery(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryHardRewardsUnsyncedParams) { + bz, err := cliCtx.Codec.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.QueryGetHardRewardsUnsynced), bz) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, res) +} + func executeUSDXMintingRewardsQuery(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryUSDXMintingRewardsParams) { bz, err := cliCtx.Codec.MarshalJSON(params) if err != nil { @@ -115,6 +197,23 @@ func executeUSDXMintingRewardsQuery(w http.ResponseWriter, cliCtx context.CLICon rest.PostProcessResponse(w, cliCtx, res) } +func executeUSDXMintingRewardsUnsyncedQuery(w http.ResponseWriter, cliCtx context.CLIContext, params types.QueryUSDXMintingRewardsUnsyncedParams) { + bz, err := cliCtx.Codec.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.QueryGetUSDXMintingRewardsUnsynced), bz) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, res) +} + func executeBothRewardQueries(w http.ResponseWriter, cliCtx context.CLIContext, hardParams types.QueryHardRewardsParams, usdxMintingParams types.QueryUSDXMintingRewardsParams) { hardBz, err := cliCtx.Codec.MarshalJSON(hardParams) @@ -165,3 +264,54 @@ func executeBothRewardQueries(w http.ResponseWriter, cliCtx context.CLIContext, rest.PostProcessResponse(w, cliCtx, resBz) } + +func executeBothUnsyncedRewardQueries(w http.ResponseWriter, cliCtx context.CLIContext, + hardParams types.QueryHardRewardsUnsyncedParams, usdxMintingParams types.QueryUSDXMintingRewardsUnsyncedParams) { + hardBz, err := cliCtx.Codec.MarshalJSON(hardParams) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err)) + return + } + + hardRes, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetHardRewardsUnsynced), hardBz) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + var hardClaims types.HardLiquidityProviderClaims + cliCtx.Codec.MustUnmarshalJSON(hardRes, &hardClaims) + + usdxMintingBz, err := cliCtx.Codec.MarshalJSON(usdxMintingParams) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err)) + return + } + + usdxMintingRes, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetUSDXMintingRewardsUnsynced), usdxMintingBz) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + var usdxMintingClaims types.USDXMintingClaims + cliCtx.Codec.MustUnmarshalJSON(usdxMintingRes, &usdxMintingClaims) + + cliCtx = cliCtx.WithHeight(height) + + type rewardResult struct { + HardClaims types.HardLiquidityProviderClaims `json:"hard_claims" yaml:"hard_claims"` + UsdxMintingClaims types.USDXMintingClaims `json:"usdx_minting_claims" yaml:"usdx_minting_claims"` + } + + res := rewardResult{ + HardClaims: hardClaims, + UsdxMintingClaims: usdxMintingClaims, + } + + resBz, err := cliCtx.Codec.MarshalJSON(res) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal result: %s", err)) + return + } + + rest.PostProcessResponse(w, cliCtx, resBz) +} diff --git a/x/incentive/client/rest/rest.go b/x/incentive/client/rest/rest.go index 9c41f78f..9edcb64b 100644 --- a/x/incentive/client/rest/rest.go +++ b/x/incentive/client/rest/rest.go @@ -4,6 +4,14 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/rest" +) + +// REST variable names +// nolint +const ( + RestDenom = "denom" ) // RegisterRoutes registers incentive-related REST handlers to a router @@ -11,3 +19,10 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { registerQueryRoutes(cliCtx, r) registerTxRoutes(cliCtx, r) } + +// PostClaimReq defines the properties of claim transaction's request body. +type PostClaimReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Sender sdk.AccAddress `json:"sender" yaml:"sender"` + MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"` +} diff --git a/x/incentive/client/rest/tx.go b/x/incentive/client/rest/tx.go index d8948187..17cf8440 100644 --- a/x/incentive/client/rest/tx.go +++ b/x/incentive/client/rest/tx.go @@ -22,7 +22,7 @@ func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { func postClaimCdpHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - var requestBody types.PostClaimReq + var requestBody PostClaimReq if !rest.ReadRESTReq(w, r, cliCtx.Codec, &requestBody) { return } @@ -55,7 +55,7 @@ func postClaimCdpHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { func postClaimHardHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - var requestBody types.PostClaimReq + var requestBody PostClaimReq if !rest.ReadRESTReq(w, r, cliCtx.Codec, &requestBody) { return } diff --git a/x/incentive/keeper/keeper.go b/x/incentive/keeper/keeper.go index 8588a6d3..cad0d32b 100644 --- a/x/incentive/keeper/keeper.go +++ b/x/incentive/keeper/keeper.go @@ -141,6 +141,20 @@ func (k Keeper) SetUSDXMintingRewardFactor(ctx sdk.Context, ctype string, factor store.Set([]byte(ctype), k.cdc.MustMarshalBinaryBare(factor)) } +// IterateUSDXMintingRewardFactors iterates over all USDX Minting reward factor objects in the store and preforms a callback function +func (k Keeper) IterateUSDXMintingRewardFactors(ctx sdk.Context, cb func(denom string, factor sdk.Dec) (stop bool)) { + store := prefix.NewStore(ctx.KVStore(k.key), types.USDXMintingRewardFactorKeyPrefix) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var factor sdk.Dec + k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &factor) + if cb(string(iterator.Key()), factor) { + break + } + } +} + // GetHardLiquidityProviderClaim returns the claim in the store corresponding the the input address collateral type and id and a boolean for if the claim was found func (k Keeper) GetHardLiquidityProviderClaim(ctx sdk.Context, addr sdk.AccAddress) (types.HardLiquidityProviderClaim, bool) { store := prefix.NewStore(ctx.KVStore(k.key), types.HardLiquidityClaimKeyPrefix) @@ -209,6 +223,20 @@ func (k Keeper) GetHardSupplyRewardIndexes(ctx sdk.Context, denom string) (types return rewardIndexes, true } +// IterateHardSupplyRewardIndexes iterates over all Hard supply reward index objects in the store and preforms a callback function +func (k Keeper) IterateHardSupplyRewardIndexes(ctx sdk.Context, cb func(denom string, indexes types.RewardIndexes) (stop bool)) { + store := prefix.NewStore(ctx.KVStore(k.key), types.HardSupplyRewardIndexesKeyPrefix) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var indexes types.RewardIndexes + k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &indexes) + if cb(string(iterator.Key()), indexes) { + break + } + } +} + // SetHardBorrowRewardIndexes sets the current reward indexes for an individual denom func (k Keeper) SetHardBorrowRewardIndexes(ctx sdk.Context, denom string, indexes types.RewardIndexes) { store := prefix.NewStore(ctx.KVStore(k.key), types.HardBorrowRewardIndexesKeyPrefix) @@ -228,6 +256,20 @@ func (k Keeper) GetHardBorrowRewardIndexes(ctx sdk.Context, denom string) (types return rewardIndexes, true } +// IterateHardBorrowRewardIndexes iterates over all Hard borrow reward index objects in the store and preforms a callback function +func (k Keeper) IterateHardBorrowRewardIndexes(ctx sdk.Context, cb func(denom string, indexes types.RewardIndexes) (stop bool)) { + store := prefix.NewStore(ctx.KVStore(k.key), types.HardBorrowRewardIndexesKeyPrefix) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var indexes types.RewardIndexes + k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &indexes) + if cb(string(iterator.Key()), indexes) { + break + } + } +} + // GetHardDelegatorRewardFactor returns the current reward factor for an individual collateral type func (k Keeper) GetHardDelegatorRewardFactor(ctx sdk.Context, ctype string) (factor sdk.Dec, found bool) { store := prefix.NewStore(ctx.KVStore(k.key), types.HardDelegatorRewardFactorKeyPrefix) @@ -245,6 +287,20 @@ func (k Keeper) SetHardDelegatorRewardFactor(ctx sdk.Context, ctype string, fact store.Set([]byte(ctype), k.cdc.MustMarshalBinaryBare(factor)) } +// IterateHardDelegatorRewardFactors iterates over all Hard delegator reward factor objects in the store and preforms a callback function +func (k Keeper) IterateHardDelegatorRewardFactors(ctx sdk.Context, cb func(denom string, factor sdk.Dec) (stop bool)) { + store := prefix.NewStore(ctx.KVStore(k.key), types.HardDelegatorRewardFactorKeyPrefix) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var factor sdk.Dec + k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &factor) + if cb(string(iterator.Key()), factor) { + break + } + } +} + // GetPreviousHardSupplyRewardAccrualTime returns the last time a denom accrued Hard protocol supply-side rewards func (k Keeper) GetPreviousHardSupplyRewardAccrualTime(ctx sdk.Context, denom string) (blockTime time.Time, found bool) { store := prefix.NewStore(ctx.KVStore(k.key), types.PreviousHardSupplyRewardAccrualTimeKeyPrefix) diff --git a/x/incentive/keeper/querier.go b/x/incentive/keeper/querier.go index 70a96e6e..9968c53a 100644 --- a/x/incentive/keeper/querier.go +++ b/x/incentive/keeper/querier.go @@ -19,8 +19,14 @@ func NewQuerier(k Keeper) sdk.Querier { return queryGetParams(ctx, req, k) case types.QueryGetHardRewards: return queryGetHardRewards(ctx, req, k) + case types.QueryGetHardRewardsUnsynced: + return queryGetHardRewardsUnsynced(ctx, req, k) case types.QueryGetUSDXMintingRewards: return queryGetUSDXMintingRewards(ctx, req, k) + case types.QueryGetUSDXMintingRewardsUnsynced: + return queryGetUSDXMintingRewardsUnsynced(ctx, req, k) + case types.QueryGetRewardFactors: + return queryGetRewardFactors(ctx, req, k) default: return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint", types.ModuleName) } @@ -81,6 +87,41 @@ func queryGetHardRewards(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]by return bz, nil } +func queryGetHardRewardsUnsynced(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { + var params types.QueryHardRewardsUnsyncedParams + err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + owner := len(params.Owner) > 0 + + var hardClaims types.HardLiquidityProviderClaims + switch { + case owner: + hardClaim, foundHardClaim := k.GetHardLiquidityProviderClaim(ctx, params.Owner) + if foundHardClaim { + hardClaims = append(hardClaims, hardClaim) + } + default: + hardClaims = k.GetAllHardLiquidityProviderClaims(ctx) + } + + var paginatedHardClaims types.HardLiquidityProviderClaims + startH, endH := client.Paginate(len(hardClaims), params.Page, params.Limit, 100) + if startH < 0 || endH < 0 { + paginatedHardClaims = types.HardLiquidityProviderClaims{} + } else { + paginatedHardClaims = hardClaims[startH:endH] + } + + // Marshal Hard claims + bz, err := codec.MarshalJSONIndent(k.cdc, paginatedHardClaims) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + return bz, nil +} + func queryGetUSDXMintingRewards(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryUSDXMintingRewardsParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) @@ -121,3 +162,128 @@ func queryGetUSDXMintingRewards(ctx sdk.Context, req abci.RequestQuery, k Keeper } return bz, nil } + +func queryGetUSDXMintingRewardsUnsynced(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { + var params types.QueryUSDXMintingRewardsUnsyncedParams + err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + owner := len(params.Owner) > 0 + + var usdxMintingClaims types.USDXMintingClaims + switch { + case owner: + usdxMintingClaim, foundUsdxMintingClaim := k.GetUSDXMintingClaim(ctx, params.Owner) + if foundUsdxMintingClaim { + usdxMintingClaims = append(usdxMintingClaims, usdxMintingClaim) + } + default: + usdxMintingClaims = k.GetAllUSDXMintingClaims(ctx) + } + + var paginatedUsdxMintingClaims types.USDXMintingClaims + startU, endU := client.Paginate(len(usdxMintingClaims), params.Page, params.Limit, 100) + if startU < 0 || endU < 0 { + paginatedUsdxMintingClaims = types.USDXMintingClaims{} + } else { + paginatedUsdxMintingClaims = usdxMintingClaims[startU:endU] + } + + // Marshal USDX minting claims + bz, err := codec.MarshalJSONIndent(k.cdc, paginatedUsdxMintingClaims) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + return bz, nil +} + +func queryGetRewardFactors(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { + var params types.QueryRewardFactorsParams + err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + + var rewardFactors types.RewardFactors + if len(params.Denom) > 0 { + // Fetch reward factors for a single denom + rewardFactor := types.RewardFactor{} + rewardFactor.Denom = params.Denom + + usdxMintingRewardFactor, found := k.GetUSDXMintingRewardFactor(ctx, params.Denom) + if found { + rewardFactor.USDXMintingRewardFactor = usdxMintingRewardFactor + } + hardSupplyRewardIndexes, found := k.GetHardSupplyRewardIndexes(ctx, params.Denom) + if found { + rewardFactor.HardSupplyRewardFactors = hardSupplyRewardIndexes + } + hardBorrowRewardIndexes, found := k.GetHardBorrowRewardIndexes(ctx, params.Denom) + if found { + rewardFactor.HardBorrowRewardFactors = hardBorrowRewardIndexes + } + hardDelegatorRewardFactor, found := k.GetHardDelegatorRewardFactor(ctx, params.Denom) + if found { + rewardFactor.HardDelegatorRewardFactor = hardDelegatorRewardFactor + } + rewardFactors = append(rewardFactors, rewardFactor) + } else { + rewardFactorMap := make(map[string]types.RewardFactor) + + // Populate mapping with usdx minting reward factors + k.IterateUSDXMintingRewardFactors(ctx, func(denom string, factor sdk.Dec) (stop bool) { + rewardFactor := types.RewardFactor{Denom: denom, USDXMintingRewardFactor: factor} + rewardFactorMap[denom] = rewardFactor + return false + }) + + // Populate mapping with Hard supply reward factors + k.IterateHardSupplyRewardIndexes(ctx, func(denom string, indexes types.RewardIndexes) (stop bool) { + rewardFactor, ok := rewardFactorMap[denom] + if !ok { + rewardFactor = types.RewardFactor{Denom: denom, HardSupplyRewardFactors: indexes} + } else { + rewardFactor.HardSupplyRewardFactors = indexes + } + rewardFactorMap[denom] = rewardFactor + return false + }) + + // Populate mapping with Hard borrow reward factors + k.IterateHardBorrowRewardIndexes(ctx, func(denom string, indexes types.RewardIndexes) (stop bool) { + rewardFactor, ok := rewardFactorMap[denom] + if !ok { + rewardFactor = types.RewardFactor{Denom: denom, HardBorrowRewardFactors: indexes} + } else { + rewardFactor.HardBorrowRewardFactors = indexes + } + rewardFactorMap[denom] = rewardFactor + return false + }) + + // Populate mapping with Hard delegator reward factors + k.IterateHardDelegatorRewardFactors(ctx, func(denom string, factor sdk.Dec) (stop bool) { + rewardFactor, ok := rewardFactorMap[denom] + if !ok { + rewardFactor = types.RewardFactor{Denom: denom, HardDelegatorRewardFactor: factor} + } else { + rewardFactor.HardDelegatorRewardFactor = factor + } + rewardFactorMap[denom] = rewardFactor + return false + }) + + // Translate mapping to slice + for _, val := range rewardFactorMap { + rewardFactors = append(rewardFactors, val) + } + } + + bz, err := codec.MarshalJSONIndent(types.ModuleCdc, rewardFactors) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + + return bz, nil +} diff --git a/x/incentive/types/querier.go b/x/incentive/types/querier.go index 724e9ef6..233a145a 100644 --- a/x/incentive/types/querier.go +++ b/x/incentive/types/querier.go @@ -2,20 +2,23 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/rest" ) // Querier routes for the incentive module const ( - QueryGetRewards = "rewards" - QueryGetHardRewards = "hard-rewards" - QueryGetUSDXMintingRewards = "usdx-minting-rewards" - QueryGetParams = "parameters" - QueryGetRewardPeriods = "reward-periods" - QueryGetClaimPeriods = "claim-periods" - RestClaimCollateralType = "collateral_type" - RestClaimOwner = "owner" - RestClaimType = "type" + QueryGetRewards = "rewards" + QueryGetHardRewards = "hard-rewards" + QueryGetHardRewardsUnsynced = "hard-rewards-unsynced" + QueryGetUSDXMintingRewards = "usdx-minting-rewards" + QueryGetUSDXMintingRewardsUnsynced = "usdx-minting-rewards-unsynced" + QueryGetRewardFactors = "reward-factors" + QueryGetParams = "parameters" + QueryGetRewardPeriods = "reward-periods" + QueryGetClaimPeriods = "claim-periods" + RestClaimCollateralType = "collateral_type" + RestClaimOwner = "owner" + RestClaimType = "type" + RestUnsynced = "unsynced" ) // QueryRewardsParams params for query /incentive/rewards @@ -52,6 +55,22 @@ func NewQueryUSDXMintingRewardsParams(page, limit int, owner sdk.AccAddress) Que } } +// QueryUSDXMintingRewardsUnsyncedParams params for query unsynced /incentive/rewards type usdx-minting +type QueryUSDXMintingRewardsUnsyncedParams struct { + Page int `json:"page" yaml:"page"` + Limit int `json:"limit" yaml:"limit"` + Owner sdk.AccAddress +} + +// NewQueryUSDXMintingRewardsUnsyncedParams returns QueryUSDXMintingRewardsUnsyncedParams +func NewQueryUSDXMintingRewardsUnsyncedParams(page, limit int, owner sdk.AccAddress) QueryUSDXMintingRewardsUnsyncedParams { + return QueryUSDXMintingRewardsUnsyncedParams{ + Page: page, + Limit: limit, + Owner: owner, + } +} + // QueryHardRewardsParams params for query /incentive/rewards type hard type QueryHardRewardsParams struct { Page int `json:"page" yaml:"page"` @@ -68,9 +87,54 @@ func NewQueryHardRewardsParams(page, limit int, owner sdk.AccAddress) QueryHardR } } -// PostClaimReq defines the properties of claim transaction's request body. -type PostClaimReq struct { - BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` - Sender sdk.AccAddress `json:"sender" yaml:"sender"` - MultiplierName string `json:"multiplier_name" yaml:"multiplier_name"` +// QueryHardRewardsUnsyncedParams params for query unsynced /incentive/rewards type hard +type QueryHardRewardsUnsyncedParams struct { + Page int `json:"page" yaml:"page"` + Limit int `json:"limit" yaml:"limit"` + Owner sdk.AccAddress } + +// NewQueryHardRewardsUnsyncedParams returns QueryHardRewardsUnsyncedParams +func NewQueryHardRewardsUnsyncedParams(page, limit int, owner sdk.AccAddress) QueryHardRewardsUnsyncedParams { + return QueryHardRewardsUnsyncedParams{ + Page: page, + Limit: limit, + Owner: owner, + } +} + +// QueryRewardFactorsParams is the params for a filtered reward factors query +type QueryRewardFactorsParams struct { + Denom string `json:"denom" yaml:"denom"` +} + +// NewQueryRewardFactorsParams creates a new QueryRewardFactorsParams +func NewQueryRewardFactorsParams(denom string) QueryRewardFactorsParams { + return QueryRewardFactorsParams{ + Denom: denom, + } +} + +// RewardFactor is a unique type returned by reward factor queries +type RewardFactor struct { + Denom string `json:"denom" yaml:"denom"` + USDXMintingRewardFactor sdk.Dec `json:"usdx_minting_reward_factor" yaml:"usdx_minting_reward_factor"` + HardSupplyRewardFactors RewardIndexes `json:"hard_supply_reward_factors" yaml:"hard_supply_reward_factors"` + HardBorrowRewardFactors RewardIndexes `json:"hard_borrow_reward_factors" yaml:"hard_borrow_reward_factors"` + HardDelegatorRewardFactor sdk.Dec `json:"hard_delegator_reward_factor" yaml:"hard_delegator_reward_factor"` +} + +// NewRewardFactor returns a new instance of RewardFactor +func NewRewardFactor(denom string, usdxMintingRewardFactor sdk.Dec, hardSupplyRewardFactors, + hardBorrowRewardFactors RewardIndexes, hardDelegatorRewardFactor sdk.Dec) RewardFactor { + return RewardFactor{ + Denom: denom, + USDXMintingRewardFactor: usdxMintingRewardFactor, + HardSupplyRewardFactors: hardSupplyRewardFactors, + HardBorrowRewardFactors: hardBorrowRewardFactors, + HardDelegatorRewardFactor: hardDelegatorRewardFactor, + } +} + +// RewardFactors is a slice of RewardFactor +type RewardFactors = []RewardFactor