From 1499a89ce5ffa87a6ab94f4fbcb48ca8b2c6542c Mon Sep 17 00:00:00 2001 From: Denali Marsh Date: Mon, 22 Feb 2021 21:48:52 +0100 Subject: [PATCH] Query Hard module reserves (#843) * implement CLI reserves query * implement REST reserves query --- x/hard/client/cli/query.go | 44 +++++++++++++++++++++++++++++++++++++ x/hard/client/rest/query.go | 39 ++++++++++++++++++++++++++++++++ x/hard/keeper/querier.go | 27 +++++++++++++++++++++++ x/hard/types/querier.go | 13 +++++++++++ 4 files changed, 123 insertions(+) diff --git a/x/hard/client/cli/query.go b/x/hard/client/cli/query.go index df125f0d..1b06ad88 100644 --- a/x/hard/client/cli/query.go +++ b/x/hard/client/cli/query.go @@ -42,6 +42,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { queryBorrowsCmd(queryRoute, cdc), queryTotalBorrowedCmd(queryRoute, cdc), queryInterestRateCmd(queryRoute, cdc), + queryReserves(queryRoute, cdc), )...) return hardQueryCmd @@ -360,3 +361,46 @@ func queryInterestRateCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { cmd.Flags().String(flagDenom, "", "(optional) filter interest rates by denom") return cmd } + +func queryReserves(queryRoute string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "reserves", + Short: "get total current Hard module reserves", + Long: strings.TrimSpace(`get the total amount of coins currently held as reserve by the Hard module: + + Example: + $ kvcli q hard reserves + $ kvcli q hard reserves --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.NewQueryReservesParams(denom) + bz, err := cdc.MarshalJSON(params) + if err != nil { + return err + } + + // Execute query + route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetReserves) + res, height, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return err + } + cliCtx = cliCtx.WithHeight(height) + + // Decode and print results + var reserves sdk.Coins + if err := cdc.UnmarshalJSON(res, &reserves); err != nil { + return fmt.Errorf("failed to unmarshal reserve coins: %w", err) + } + return cliCtx.PrintOutput(reserves) + }, + } + cmd.Flags().String(flagDenom, "", "(optional) filter reserve coins by denom") + return cmd +} diff --git a/x/hard/client/rest/query.go b/x/hard/client/rest/query.go index 24b8929f..8131a226 100644 --- a/x/hard/client/rest/query.go +++ b/x/hard/client/rest/query.go @@ -22,6 +22,7 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc(fmt.Sprintf("/%s/borrows", types.ModuleName), queryBorrowsHandlerFn(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/%s/total-borrowed", types.ModuleName), queryTotalBorrowedHandlerFn(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/%s/interest-rate", types.ModuleName), queryInterestRateHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/%s/reserves", types.ModuleName), queryReservesHandlerFn(cliCtx)).Methods("GET") } func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { @@ -291,3 +292,41 @@ func queryModAccountsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { rest.PostProcessResponse(w, cliCtx, res) } } + +func queryReservesHandlerFn(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.NewQueryReservesParams(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.QueryGetReserves) + 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) + } +} diff --git a/x/hard/keeper/querier.go b/x/hard/keeper/querier.go index 4065ff5b..5c547131 100644 --- a/x/hard/keeper/querier.go +++ b/x/hard/keeper/querier.go @@ -30,6 +30,8 @@ func NewQuerier(k Keeper) sdk.Querier { return queryGetTotalBorrowed(ctx, req, k) case types.QueryGetInterestRate: return queryGetInterestRate(ctx, req, k) + case types.QueryGetReserves: + return queryGetReserves(ctx, req, k) default: return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint", types.ModuleName) } @@ -328,3 +330,28 @@ func queryGetInterestRate(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]b return bz, nil } + +func queryGetReserves(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { + var params types.QueryReservesParams + err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + + reserveCoins, found := k.GetTotalReserves(ctx) + if !found { + reserveCoins = sdk.Coins{} + } + + // If user specified a denom only return coins of that denom type + if len(params.Denom) > 0 { + reserveCoins = sdk.NewCoins(sdk.NewCoin(params.Denom, reserveCoins.AmountOf(params.Denom))) + } + + bz, err := codec.MarshalJSONIndent(types.ModuleCdc, reserveCoins) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + + return bz, nil +} diff --git a/x/hard/types/querier.go b/x/hard/types/querier.go index c799ff07..a603d361 100644 --- a/x/hard/types/querier.go +++ b/x/hard/types/querier.go @@ -13,6 +13,7 @@ const ( QueryGetBorrows = "borrows" QueryGetTotalBorrowed = "total-borrowed" QueryGetInterestRate = "interest-rate" + QueryGetReserves = "reserves" ) // QueryDepositsParams is the params for a filtered deposit query @@ -121,3 +122,15 @@ func NewMoneyMarketInterestRate(denom string, supplyInterestRate, borrowInterest // MoneyMarketInterestRates is a slice of MoneyMarketInterestRate type MoneyMarketInterestRates []MoneyMarketInterestRate + +// QueryReservesParams is the params for a filtered reserves query +type QueryReservesParams struct { + Denom string `json:"denom" yaml:"denom"` +} + +// NewQueryReservesParams creates a new QueryReservesParams +func NewQueryReservesParams(denom string) QueryReservesParams { + return QueryReservesParams{ + Denom: denom, + } +}