package rest import ( "fmt" "net/http" "strconv" "strings" "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/x/staking/types" ) func registerQueryRoutes(clientCtx client.Context, r *mux.Router) { // Get all delegations from a delegator r.HandleFunc( "/staking/delegators/{delegatorAddr}/delegations", delegatorDelegationsHandlerFn(clientCtx), ).Methods("GET") // Get all unbonding delegations from a delegator r.HandleFunc( "/staking/delegators/{delegatorAddr}/unbonding_delegations", delegatorUnbondingDelegationsHandlerFn(clientCtx), ).Methods("GET") // Get all staking txs (i.e msgs) from a delegator r.HandleFunc( "/staking/delegators/{delegatorAddr}/txs", delegatorTxsHandlerFn(clientCtx), ).Methods("GET") // Query all validators that a delegator is bonded to r.HandleFunc( "/staking/delegators/{delegatorAddr}/validators", delegatorValidatorsHandlerFn(clientCtx), ).Methods("GET") // Query a validator that a delegator is bonded to r.HandleFunc( "/staking/delegators/{delegatorAddr}/validators/{validatorAddr}", delegatorValidatorHandlerFn(clientCtx), ).Methods("GET") // Query a delegation between a delegator and a validator r.HandleFunc( "/staking/delegators/{delegatorAddr}/delegations/{validatorAddr}", delegationHandlerFn(clientCtx), ).Methods("GET") // Query all unbonding delegations between a delegator and a validator r.HandleFunc( "/staking/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr}", unbondingDelegationHandlerFn(clientCtx), ).Methods("GET") // Query redelegations (filters in query params) r.HandleFunc( "/staking/redelegations", redelegationsHandlerFn(clientCtx), ).Methods("GET") // Get all validators r.HandleFunc( "/staking/validators", validatorsHandlerFn(clientCtx), ).Methods("GET") // Get a single validator info r.HandleFunc( "/staking/validators/{validatorAddr}", validatorHandlerFn(clientCtx), ).Methods("GET") // Get all delegations to a validator r.HandleFunc( "/staking/validators/{validatorAddr}/delegations", validatorDelegationsHandlerFn(clientCtx), ).Methods("GET") // Get all unbonding delegations from a validator r.HandleFunc( "/staking/validators/{validatorAddr}/unbonding_delegations", validatorUnbondingDelegationsHandlerFn(clientCtx), ).Methods("GET") // Get HistoricalInfo at a given height r.HandleFunc( "/staking/historical_info/{height}", historicalInfoHandlerFn(clientCtx), ).Methods("GET") // Get the current state of the staking pool r.HandleFunc( "/staking/pool", poolHandlerFn(clientCtx), ).Methods("GET") // Get the current staking parameter values r.HandleFunc( "/staking/parameters", paramsHandlerFn(clientCtx), ).Methods("GET") } // HTTP request handler to query a delegator delegations func delegatorDelegationsHandlerFn(clientCtx client.Context) http.HandlerFunc { return queryDelegator(clientCtx, fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryDelegatorDelegations)) } // HTTP request handler to query a delegator unbonding delegations func delegatorUnbondingDelegationsHandlerFn(cliCtx client.Context) http.HandlerFunc { return queryDelegator(cliCtx, fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryDelegatorUnbondingDelegations)) } // HTTP request handler to query all staking txs (msgs) from a delegator func delegatorTxsHandlerFn(clientCtx client.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var typesQuerySlice []string vars := mux.Vars(r) delegatorAddr := vars["delegatorAddr"] if _, err := sdk.AccAddressFromBech32(delegatorAddr); rest.CheckBadRequestError(w, err) { return } clientCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, clientCtx, r) if !ok { return } typesQuery := r.URL.Query().Get("type") trimmedQuery := strings.TrimSpace(typesQuery) if len(trimmedQuery) != 0 { typesQuerySlice = strings.Split(trimmedQuery, " ") } noQuery := len(typesQuerySlice) == 0 isBondTx := contains(typesQuerySlice, "bond") isUnbondTx := contains(typesQuerySlice, "unbond") isRedTx := contains(typesQuerySlice, "redelegate") var ( txs []*sdk.SearchTxsResult actions []string ) switch { case isBondTx: actions = append(actions, types.MsgDelegate{}.Type()) case isUnbondTx: actions = append(actions, types.MsgUndelegate{}.Type()) case isRedTx: actions = append(actions, types.MsgBeginRedelegate{}.Type()) case noQuery: actions = append(actions, types.MsgDelegate{}.Type()) actions = append(actions, types.MsgUndelegate{}.Type()) actions = append(actions, types.MsgBeginRedelegate{}.Type()) default: w.WriteHeader(http.StatusNoContent) return } for _, action := range actions { foundTxs, errQuery := queryTxs(clientCtx, action, delegatorAddr) if rest.CheckInternalServerError(w, errQuery) { return } txs = append(txs, foundTxs) } res, err := clientCtx.JSONMarshaler.MarshalJSON(txs) if rest.CheckInternalServerError(w, err) { return } rest.PostProcessResponseBare(w, clientCtx, res) } } // HTTP request handler to query an unbonding-delegation func unbondingDelegationHandlerFn(cliCtx client.Context) http.HandlerFunc { return queryBonds(cliCtx, fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryUnbondingDelegation)) } // HTTP request handler to query redelegations func redelegationsHandlerFn(clientCtx client.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var params types.QueryRedelegationParams clientCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, clientCtx, r) if !ok { return } bechDelegatorAddr := r.URL.Query().Get("delegator") bechSrcValidatorAddr := r.URL.Query().Get("validator_from") bechDstValidatorAddr := r.URL.Query().Get("validator_to") if len(bechDelegatorAddr) != 0 { delegatorAddr, err := sdk.AccAddressFromBech32(bechDelegatorAddr) if rest.CheckBadRequestError(w, err) { return } params.DelegatorAddr = delegatorAddr } if len(bechSrcValidatorAddr) != 0 { srcValidatorAddr, err := sdk.ValAddressFromBech32(bechSrcValidatorAddr) if rest.CheckBadRequestError(w, err) { return } params.SrcValidatorAddr = srcValidatorAddr } if len(bechDstValidatorAddr) != 0 { dstValidatorAddr, err := sdk.ValAddressFromBech32(bechDstValidatorAddr) if rest.CheckBadRequestError(w, err) { return } params.DstValidatorAddr = dstValidatorAddr } bz, err := clientCtx.JSONMarshaler.MarshalJSON(params) if rest.CheckBadRequestError(w, err) { return } res, height, err := clientCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryRedelegations), bz) if rest.CheckInternalServerError(w, err) { return } clientCtx = clientCtx.WithHeight(height) rest.PostProcessResponse(w, clientCtx, res) } } // HTTP request handler to query a delegation func delegationHandlerFn(clientCtx client.Context) http.HandlerFunc { return queryBonds(clientCtx, fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryDelegation)) } // HTTP request handler to query all delegator bonded validators func delegatorValidatorsHandlerFn(cliCtx client.Context) http.HandlerFunc { return queryDelegator(cliCtx, fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryDelegatorValidators)) } // HTTP request handler to get information from a currently bonded validator func delegatorValidatorHandlerFn(cliCtx client.Context) http.HandlerFunc { return queryBonds(cliCtx, fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryDelegatorValidator)) } // HTTP request handler to query list of validators func validatorsHandlerFn(clientCtx client.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { _, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0) if rest.CheckBadRequestError(w, err) { return } clientCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, clientCtx, r) if !ok { return } status := r.FormValue("status") if status == "" { status = sdk.BondStatusBonded } params := types.NewQueryValidatorsParams(page, limit, status) bz, err := clientCtx.JSONMarshaler.MarshalJSON(params) if rest.CheckBadRequestError(w, err) { return } route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryValidators) res, height, err := clientCtx.QueryWithData(route, bz) if rest.CheckInternalServerError(w, err) { return } clientCtx = clientCtx.WithHeight(height) rest.PostProcessResponse(w, clientCtx, res) } } // HTTP request handler to query the validator information from a given validator address func validatorHandlerFn(cliCtx client.Context) http.HandlerFunc { return queryValidator(cliCtx, fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryValidator)) } // HTTP request handler to query all unbonding delegations from a validator func validatorDelegationsHandlerFn(clientCtx client.Context) http.HandlerFunc { return queryValidator(clientCtx, fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryValidatorDelegations)) } // HTTP request handler to query all unbonding delegations from a validator func validatorUnbondingDelegationsHandlerFn(cliCtx client.Context) http.HandlerFunc { return queryValidator(cliCtx, fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryValidatorUnbondingDelegations)) } // HTTP request handler to query historical info at a given height func historicalInfoHandlerFn(clientCtx client.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) heightStr := vars["height"] height, err := strconv.ParseInt(heightStr, 10, 64) if err != nil || height < 0 { rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("Must provide non-negative integer for height: %v", err)) return } params := types.NewQueryHistoricalInfoParams(height) bz, err := clientCtx.JSONMarshaler.MarshalJSON(params) if rest.CheckInternalServerError(w, err) { return } res, height, err := clientCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryHistoricalInfo), bz) if rest.CheckBadRequestError(w, err) { return } clientCtx = clientCtx.WithHeight(height) rest.PostProcessResponse(w, clientCtx, res) } } // HTTP request handler to query the pool information func poolHandlerFn(clientCtx client.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { clientCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, clientCtx, r) if !ok { return } res, height, err := clientCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryPool), nil) if rest.CheckInternalServerError(w, err) { return } clientCtx = clientCtx.WithHeight(height) rest.PostProcessResponse(w, clientCtx, res) } } // HTTP request handler to query the staking params values func paramsHandlerFn(clientCtx client.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { clientCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, clientCtx, r) if !ok { return } res, height, err := clientCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryParameters), nil) if rest.CheckInternalServerError(w, err) { return } clientCtx = clientCtx.WithHeight(height) rest.PostProcessResponse(w, clientCtx, res) } }