From 656c5a80b8c92967d26e8f3bce7df8001b295b30 Mon Sep 17 00:00:00 2001 From: Denali Marsh Date: Mon, 22 Mar 2021 18:57:07 +0100 Subject: [PATCH] Additional Hard module queries (#884) * unsynced deposits/borrows queriers * cli queriers * rest querier * implement interest factor querier * querier cli * querier rest * fix typo in comment --- x/hard/client/cli/query.go | 164 ++++++++++++++++++++++++++++++++++ x/hard/client/rest/query.go | 137 ++++++++++++++++++++++++++++ x/hard/keeper/keeper.go | 30 +++++++ x/hard/keeper/querier.go | 173 ++++++++++++++++++++++++++++++++++++ x/hard/types/querier.go | 86 ++++++++++++++++-- 5 files changed, 582 insertions(+), 8 deletions(-) diff --git a/x/hard/client/cli/query.go b/x/hard/client/cli/query.go index 1b06ad88..f8d7f711 100644 --- a/x/hard/client/cli/query.go +++ b/x/hard/client/cli/query.go @@ -38,11 +38,14 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { queryParamsCmd(queryRoute, cdc), queryModAccountsCmd(queryRoute, cdc), queryDepositsCmd(queryRoute, cdc), + queryUnsyncedDepositsCmd(queryRoute, cdc), queryTotalDepositedCmd(queryRoute, cdc), queryBorrowsCmd(queryRoute, cdc), + queryUnsyncedBorrowsCmd(queryRoute, cdc), queryTotalBorrowedCmd(queryRoute, cdc), queryInterestRateCmd(queryRoute, cdc), queryReserves(queryRoute, cdc), + queryInterestFactorsCmd(queryRoute, cdc), )...) return hardQueryCmd @@ -115,6 +118,66 @@ func queryModAccountsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { } } +func queryUnsyncedDepositsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "unsynced-deposits", + Short: "query hard module unsynced deposits with optional filters", + Long: strings.TrimSpace(`query for all hard module unsynced deposits or a specific unsynced deposit using flags: + + Example: + $ kvcli q hard unsynced-deposits + $ kvcli q hard unsynced-deposits --owner kava1l0xsq2z7gqd7yly0g40y5836g0appumark77ny --denom bnb + $ kvcli q hard unsynced-deposits --denom ukava + $ kvcli q hard unsynced-deposits --denom btcb`, + ), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + var owner sdk.AccAddress + + ownerBech := viper.GetString(flagOwner) + denom := viper.GetString(flagDenom) + + if len(ownerBech) != 0 { + depositOwner, err := sdk.AccAddressFromBech32(ownerBech) + if err != nil { + return err + } + owner = depositOwner + } + + page := viper.GetInt(flags.FlagPage) + limit := viper.GetInt(flags.FlagLimit) + + params := types.NewQueryUnsyncedDepositsParams(page, limit, denom, owner) + bz, err := cdc.MarshalJSON(params) + if err != nil { + return err + } + + route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetUnsyncedDeposits) + res, height, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return err + } + cliCtx = cliCtx.WithHeight(height) + + var deposits types.Deposits + if err := cdc.UnmarshalJSON(res, &deposits); err != nil { + return fmt.Errorf("failed to unmarshal deposits: %w", err) + } + return cliCtx.PrintOutput(deposits) + }, + } + + cmd.Flags().Int(flags.FlagPage, 1, "pagination page to query for") + cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit (max 100)") + cmd.Flags().String(flagOwner, "", "(optional) filter for unsynced deposits by owner address") + cmd.Flags().String(flagDenom, "", "(optional) filter for unsynced deposits by denom") + return cmd +} + func queryDepositsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "deposits", @@ -175,6 +238,64 @@ func queryDepositsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { return cmd } +func queryUnsyncedBorrowsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "unsynced-borrows", + Short: "query hard module unsynced borrows with optional filters", + Long: strings.TrimSpace(`query for all hard module unsynced borrows or a specific unsynced borrow using flags: + + Example: + $ kvcli q hard unsynced-borrows + $ kvcli q hard unsynced-borrows --owner kava1l0xsq2z7gqd7yly0g40y5836g0appumark77ny + $ kvcli q hard unsynced-borrows --denom bnb`, + ), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + var owner sdk.AccAddress + + ownerBech := viper.GetString(flagOwner) + denom := viper.GetString(flagDenom) + + if len(ownerBech) != 0 { + borrowOwner, err := sdk.AccAddressFromBech32(ownerBech) + if err != nil { + return err + } + owner = borrowOwner + } + + page := viper.GetInt(flags.FlagPage) + limit := viper.GetInt(flags.FlagLimit) + + params := types.NewQueryUnsyncedBorrowsParams(page, limit, owner, denom) + bz, err := cdc.MarshalJSON(params) + if err != nil { + return err + } + + route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetUnsyncedBorrows) + res, height, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return err + } + cliCtx = cliCtx.WithHeight(height) + + var borrows types.Borrows + if err := cdc.UnmarshalJSON(res, &borrows); err != nil { + return fmt.Errorf("failed to unmarshal borrows: %w", err) + } + return cliCtx.PrintOutput(borrows) + }, + } + cmd.Flags().Int(flags.FlagPage, 1, "pagination page to query for") + cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit (max 100)") + cmd.Flags().String(flagOwner, "", "(optional) filter for unsynced borrows by owner address") + cmd.Flags().String(flagDenom, "", "(optional) filter for unsynced borrows by denom") + return cmd +} + func queryBorrowsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "borrows", @@ -404,3 +525,46 @@ func queryReserves(queryRoute string, cdc *codec.Codec) *cobra.Command { cmd.Flags().String(flagDenom, "", "(optional) filter reserve coins by denom") return cmd } + +func queryInterestFactorsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "interest-factors", + Short: "get current global interest factors", + Long: strings.TrimSpace(`get current global interest factors: + + Example: + $ kvcli q hard interest-factors + $ kvcli q hard interest-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.NewQueryInterestFactorsParams(denom) + bz, err := cdc.MarshalJSON(params) + if err != nil { + return err + } + + // Execute query + route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetInterestFactors) + res, height, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return err + } + cliCtx = cliCtx.WithHeight(height) + + // Decode and print results + var interestFactors types.InterestFactors + if err := cdc.UnmarshalJSON(res, &interestFactors); err != nil { + return fmt.Errorf("failed to unmarshal interest factors: %w", err) + } + return cliCtx.PrintOutput(interestFactors) + }, + } + cmd.Flags().String(flagDenom, "", "(optional) filter interest factors by denom") + return cmd +} diff --git a/x/hard/client/rest/query.go b/x/hard/client/rest/query.go index 8131a226..a3b27188 100644 --- a/x/hard/client/rest/query.go +++ b/x/hard/client/rest/query.go @@ -16,13 +16,16 @@ import ( func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc(fmt.Sprintf("/%s/parameters", types.ModuleName), queryParamsHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/%s/unsynced-deposits", types.ModuleName), queryUnsyncedDepositsHandlerFn(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/%s/deposits", types.ModuleName), queryDepositsHandlerFn(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/%s/total-deposited", types.ModuleName), queryTotalDepositedHandlerFn(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/%s/accounts", types.ModuleName), queryModAccountsHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/%s/unsynced-borrows", types.ModuleName), queryUnsyncedBorrowsHandlerFn(cliCtx)).Methods("GET") 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") + r.HandleFunc(fmt.Sprintf("/%s/interest-factors", types.ModuleName), queryInterestFactorsHandlerFn(cliCtx)).Methods("GET") } func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { @@ -93,6 +96,54 @@ func queryDepositsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } } +func queryUnsyncedDepositsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + _, page, limit, 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 + var owner sdk.AccAddress + + if x := r.URL.Query().Get(RestDenom); len(x) != 0 { + denom = strings.TrimSpace(x) + } + + if x := r.URL.Query().Get(RestOwner); len(x) != 0 { + ownerStr := strings.ToLower(strings.TrimSpace(x)) + owner, err = sdk.AccAddressFromBech32(ownerStr) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("cannot parse address from deposit owner %s", ownerStr)) + return + } + } + + params := types.NewQueryUnsyncedDepositsParams(page, limit, denom, owner) + + 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.QueryGetUnsyncedDeposits) + 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 queryTotalDepositedHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { _, _, _, err := rest.ParseHTTPArgsWithLimit(r, 0) @@ -179,6 +230,54 @@ func queryBorrowsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } } +func queryUnsyncedBorrowsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + _, page, limit, 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 + var owner sdk.AccAddress + + if x := r.URL.Query().Get(RestDenom); len(x) != 0 { + denom = strings.TrimSpace(x) + } + + if x := r.URL.Query().Get(RestOwner); len(x) != 0 { + ownerStr := strings.ToLower(strings.TrimSpace(x)) + owner, err = sdk.AccAddressFromBech32(ownerStr) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("cannot parse address from borrow owner %s", ownerStr)) + return + } + } + + params := types.NewQueryUnsyncedBorrowsParams(page, limit, owner, 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.QueryGetUnsyncedBorrows) + 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 queryTotalBorrowedHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { _, _, _, err := rest.ParseHTTPArgsWithLimit(r, 0) @@ -330,3 +429,41 @@ func queryReservesHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { rest.PostProcessResponse(w, cliCtx, res) } } + +func queryInterestFactorsHandlerFn(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.NewQueryInterestFactorsParams(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.QueryGetInterestFactors) + 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/keeper.go b/x/hard/keeper/keeper.go index 9386fe2a..c728519d 100644 --- a/x/hard/keeper/keeper.go +++ b/x/hard/keeper/keeper.go @@ -306,6 +306,21 @@ func (k Keeper) SetBorrowInterestFactor(ctx sdk.Context, denom string, borrowInt store.Set([]byte(denom), bz) } +// IterateBorrowInterestFactors iterates over all borrow interest factors in the store and returns +// both the borrow interest factor and the key (denom) it's stored under +func (k Keeper) IterateBorrowInterestFactors(ctx sdk.Context, cb func(denom string, factor sdk.Dec) (stop bool)) { + store := prefix.NewStore(ctx.KVStore(k.key), types.BorrowInterestFactorPrefix) + 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 + } + } +} + // GetSupplyInterestFactor returns the current supply interest factor for an individual market func (k Keeper) GetSupplyInterestFactor(ctx sdk.Context, denom string) (sdk.Dec, bool) { store := prefix.NewStore(ctx.KVStore(k.key), types.SupplyInterestFactorPrefix) @@ -324,3 +339,18 @@ func (k Keeper) SetSupplyInterestFactor(ctx sdk.Context, denom string, supplyInt bz := k.cdc.MustMarshalBinaryBare(supplyInterestFactor) store.Set([]byte(denom), bz) } + +// IterateSupplyInterestFactors iterates over all supply interest factors in the store and returns +// both the supply interest factor and the key (denom) it's stored under +func (k Keeper) IterateSupplyInterestFactors(ctx sdk.Context, cb func(denom string, factor sdk.Dec) (stop bool)) { + store := prefix.NewStore(ctx.KVStore(k.key), types.SupplyInterestFactorPrefix) + 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 + } + } +} diff --git a/x/hard/keeper/querier.go b/x/hard/keeper/querier.go index 5c547131..880e1a36 100644 --- a/x/hard/keeper/querier.go +++ b/x/hard/keeper/querier.go @@ -22,16 +22,22 @@ func NewQuerier(k Keeper) sdk.Querier { return queryGetModAccounts(ctx, req, k) case types.QueryGetDeposits: return queryGetDeposits(ctx, req, k) + case types.QueryGetUnsyncedDeposits: + return queryGetUnsyncedDeposits(ctx, req, k) case types.QueryGetTotalDeposited: return queryGetTotalDeposited(ctx, req, k) case types.QueryGetBorrows: return queryGetBorrows(ctx, req, k) + case types.QueryGetUnsyncedBorrows: + return queryGetUnsyncedBorrows(ctx, req, k) case types.QueryGetTotalBorrowed: return queryGetTotalBorrowed(ctx, req, k) case types.QueryGetInterestRate: return queryGetInterestRate(ctx, req, k) case types.QueryGetReserves: return queryGetReserves(ctx, req, k) + case types.QueryGetInterestFactors: + return queryGetInterestFactors(ctx, req, k) default: return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint", types.ModuleName) } @@ -147,6 +153,62 @@ func queryGetDeposits(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, return bz, nil } +func queryGetUnsyncedDeposits(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { + + var params types.QueryUnsyncedDepositsParams + err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + denom := len(params.Denom) > 0 + owner := len(params.Owner) > 0 + + var deposits types.Deposits + switch { + case owner && denom: + deposit, found := k.GetDeposit(ctx, params.Owner) + if found { + for _, coin := range deposit.Amount { + if coin.Denom == params.Denom { + deposits = append(deposits, deposit) + } + } + } + case owner: + deposit, found := k.GetDeposit(ctx, params.Owner) + if found { + deposits = append(deposits, deposit) + } + case denom: + k.IterateDeposits(ctx, func(deposit types.Deposit) (stop bool) { + if deposit.Amount.AmountOf(params.Denom).IsPositive() { + deposits = append(deposits, deposit) + } + return false + }) + default: + k.IterateDeposits(ctx, func(deposit types.Deposit) (stop bool) { + deposits = append(deposits, deposit) + return false + }) + } + + var bz []byte + + start, end := client.Paginate(len(deposits), params.Page, params.Limit, 100) + if start < 0 || end < 0 { + deposits = types.Deposits{} + } else { + deposits = deposits[start:end] + } + + bz, err = codec.MarshalJSONIndent(types.ModuleCdc, deposits) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + return bz, nil +} + func queryGetBorrows(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryBorrowsParams @@ -219,6 +281,62 @@ func queryGetBorrows(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, return bz, nil } +func queryGetUnsyncedBorrows(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { + + var params types.QueryUnsyncedBorrowsParams + err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + denom := len(params.Denom) > 0 + owner := len(params.Owner) > 0 + + var borrows types.Borrows + switch { + case owner && denom: + borrow, found := k.GetBorrow(ctx, params.Owner) + if found { + for _, coin := range borrow.Amount { + if coin.Denom == params.Denom { + borrows = append(borrows, borrow) + } + } + } + case owner: + borrow, found := k.GetBorrow(ctx, params.Owner) + if found { + borrows = append(borrows, borrow) + } + case denom: + k.IterateBorrows(ctx, func(borrow types.Borrow) (stop bool) { + if borrow.Amount.AmountOf(params.Denom).IsPositive() { + borrows = append(borrows, borrow) + } + return false + }) + default: + k.IterateBorrows(ctx, func(borrow types.Borrow) (stop bool) { + borrows = append(borrows, borrow) + return false + }) + } + + var bz []byte + + start, end := client.Paginate(len(borrows), params.Page, params.Limit, 100) + if start < 0 || end < 0 { + borrows = types.Borrows{} + } else { + borrows = borrows[start:end] + } + + bz, err = codec.MarshalJSONIndent(types.ModuleCdc, borrows) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + return bz, nil +} + func queryGetTotalBorrowed(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryTotalBorrowedParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) @@ -355,3 +473,58 @@ func queryGetReserves(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, return bz, nil } + +func queryGetInterestFactors(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { + var params types.QueryInterestFactorsParams + err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + + var interestFactors types.InterestFactors + if len(params.Denom) > 0 { + // Fetch supply/borrow interest factors for a single denom + interestFactor := types.InterestFactor{} + interestFactor.Denom = params.Denom + supplyInterestFactor, found := k.GetSupplyInterestFactor(ctx, params.Denom) + if found { + interestFactor.SupplyInterestFactor = supplyInterestFactor + } + borrowInterestFactor, found := k.GetBorrowInterestFactor(ctx, params.Denom) + if found { + interestFactor.BorrowInterestFactor = borrowInterestFactor + } + interestFactors = append(interestFactors, interestFactor) + } else { + interestFactorMap := make(map[string]types.InterestFactor) + // Populate mapping with supply interest factors + k.IterateSupplyInterestFactors(ctx, func(denom string, factor sdk.Dec) (stop bool) { + interestFactor := types.InterestFactor{Denom: denom, SupplyInterestFactor: factor} + interestFactorMap[denom] = interestFactor + return false + }) + // Populate mapping with borrow interest factors + k.IterateBorrowInterestFactors(ctx, func(denom string, factor sdk.Dec) (stop bool) { + interestFactor, ok := interestFactorMap[denom] + if !ok { + newInterestFactor := types.InterestFactor{Denom: denom, BorrowInterestFactor: factor} + interestFactorMap[denom] = newInterestFactor + } else { + interestFactor.BorrowInterestFactor = factor + interestFactorMap[denom] = interestFactor + } + return false + }) + // Translate mapping to slice + for _, val := range interestFactorMap { + interestFactors = append(interestFactors, val) + } + } + + bz, err := codec.MarshalJSONIndent(types.ModuleCdc, interestFactors) + 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 a603d361..99485e4c 100644 --- a/x/hard/types/querier.go +++ b/x/hard/types/querier.go @@ -6,14 +6,17 @@ import ( // Querier routes for the hard module const ( - QueryGetParams = "params" - QueryGetModuleAccounts = "accounts" - QueryGetDeposits = "deposits" - QueryGetTotalDeposited = "total-deposited" - QueryGetBorrows = "borrows" - QueryGetTotalBorrowed = "total-borrowed" - QueryGetInterestRate = "interest-rate" - QueryGetReserves = "reserves" + QueryGetParams = "params" + QueryGetModuleAccounts = "accounts" + QueryGetDeposits = "deposits" + QueryGetUnsyncedDeposits = "unsynced-deposits" + QueryGetTotalDeposited = "total-deposited" + QueryGetBorrows = "borrows" + QueryGetUnsyncedBorrows = "unsynced-borrows" + QueryGetTotalBorrowed = "total-borrowed" + QueryGetInterestRate = "interest-rate" + QueryGetReserves = "reserves" + QueryGetInterestFactors = "interest-factors" ) // QueryDepositsParams is the params for a filtered deposit query @@ -34,6 +37,24 @@ func NewQueryDepositsParams(page, limit int, denom string, owner sdk.AccAddress) } } +// QueryUnsyncedDepositsParams is the params for a filtered unsynced deposit query. +type QueryUnsyncedDepositsParams struct { + Page int `json:"page" yaml:"page"` + Limit int `json:"limit" yaml:"limit"` + Denom string `json:"denom" yaml:"denom"` + Owner sdk.AccAddress `json:"owner" yaml:"owner"` +} + +// NewQueryUnsyncedDepositsParams creates a new QueryUnsyncedDepositsParams +func NewQueryUnsyncedDepositsParams(page, limit int, denom string, owner sdk.AccAddress) QueryUnsyncedDepositsParams { + return QueryUnsyncedDepositsParams{ + Page: page, + Limit: limit, + Denom: denom, + Owner: owner, + } +} + // QueryAccountParams is the params for a filtered module account query type QueryAccountParams struct { Page int `json:"page" yaml:"page"` @@ -68,6 +89,24 @@ func NewQueryBorrowsParams(page, limit int, owner sdk.AccAddress, denom string) } } +// QueryUnsyncedBorrowsParams is the params for a filtered unsynced borrows query +type QueryUnsyncedBorrowsParams struct { + Page int `json:"page" yaml:"page"` + Limit int `json:"limit" yaml:"limit"` + Owner sdk.AccAddress `json:"owner" yaml:"owner"` + Denom string `json:"denom" yaml:"denom"` +} + +// NewQueryUnsyncedBorrowsParams creates a new QueryUnsyncedBorrowsParams +func NewQueryUnsyncedBorrowsParams(page, limit int, owner sdk.AccAddress, denom string) QueryUnsyncedBorrowsParams { + return QueryUnsyncedBorrowsParams{ + Page: page, + Limit: limit, + Owner: owner, + Denom: denom, + } +} + // QueryTotalBorrowedParams is the params for a filtered total borrowed coins query type QueryTotalBorrowedParams struct { Denom string `json:"denom" yaml:"denom"` @@ -134,3 +173,34 @@ func NewQueryReservesParams(denom string) QueryReservesParams { Denom: denom, } } + +// QueryInterestFactorsParams is the params for a filtered interest factors query +type QueryInterestFactorsParams struct { + Denom string `json:"denom" yaml:"denom"` +} + +// NewQueryInterestFactorsParams creates a new QueryInterestFactorsParams +func NewQueryInterestFactorsParams(denom string) QueryInterestFactorsParams { + return QueryInterestFactorsParams{ + Denom: denom, + } +} + +// InterestFactor is a unique type returned by interest factor queries +type InterestFactor struct { + Denom string `json:"denom" yaml:"denom"` + BorrowInterestFactor sdk.Dec `json:"borrow_interest_factor" yaml:"borrow_interest_factor"` + SupplyInterestFactor sdk.Dec `json:"supply_interest_factor" yaml:"supply_interest_factor"` +} + +// NewInterestFactor returns a new instance of InterestFactor +func NewInterestFactor(denom string, supplyInterestFactor, borrowInterestFactor sdk.Dec) InterestFactor { + return InterestFactor{ + Denom: denom, + SupplyInterestFactor: supplyInterestFactor, + BorrowInterestFactor: borrowInterestFactor, + } +} + +// InterestFactors is a slice of InterestFactor +type InterestFactors = []InterestFactor