diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 0adbc5fa1e..a173ac0e27 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -590,6 +590,10 @@ func TestBonding(t *testing.T) { require.Equal(t, "30", summary.UnbondingDelegations[0].Balance.Amount.String()) require.Equal(t, "30", summary.Redelegations[0].Balance.Amount.String()) + validatorUbds := getValidatorUnbondingDelegations(t, port, operAddrs[0]) + require.Len(t, validatorUbds, 1) + require.Equal(t, "30", validatorUbds[0].Balance.Amount.String()) + validatorReds := getValidatorRedelegations(t, port, operAddrs[0]) require.Len(t, validatorReds, 1) require.Equal(t, "30", validatorReds[0].Balance.Amount.String()) @@ -1182,6 +1186,17 @@ func getValidator(t *testing.T, port string, validatorAddr sdk.ValAddress) stake return validator } +func getValidatorUnbondingDelegations(t *testing.T, port string, validatorAddr sdk.ValAddress) []stake.UnbondingDelegation { + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s/unbonding_delegations", validatorAddr.String()), nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + var ubds []stake.UnbondingDelegation + err := cdc.UnmarshalJSON([]byte(body), &ubds) + require.Nil(t, err) + + return ubds +} + func getValidatorRedelegations(t *testing.T, port string, validatorAddr sdk.ValAddress) []stake.Redelegation { res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s/redelegations", validatorAddr.String()), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index fbe48d1681..14de0b8e81 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -66,6 +66,12 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Co validatorHandlerFn(cliCtx, cdc), ).Methods("GET") + // Get all unbonding delegations from a validator + r.HandleFunc( + "/stake/validators/{validatorAddr}/unbonding_delegations", + validatorUnbondingDelegationsHandlerFn(cliCtx, cdc), + ).Methods("GET") + // Get all outgoing redelegations from a validator r.HandleFunc( "/stake/validators/{validatorAddr}/redelegations", @@ -199,6 +205,11 @@ func validatorHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.Handle return queryValidator(cliCtx, cdc, "custom/stake/validator") } +// HTTP request handler to query all unbonding delegations from a validator +func validatorUnbondingDelegationsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { + return queryValidator(cliCtx, cdc, "custom/stake/validatorUnbondingDelegations") +} + // HTTP request handler to query all redelegations from a source validator func validatorRedelegationsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { return queryValidator(cliCtx, cdc, "custom/stake/validatorRedelegations") diff --git a/x/stake/querier/queryable.go b/x/stake/querier/queryable.go index 2d54de976d..ace001fce8 100644 --- a/x/stake/querier/queryable.go +++ b/x/stake/querier/queryable.go @@ -10,16 +10,17 @@ import ( // query endpoints supported by the staking Querier const ( - QueryValidators = "validators" - QueryValidator = "validator" - QueryValidatorRedelegations = "validatorRedelegations" - QueryDelegator = "delegator" - QueryDelegation = "delegation" - QueryUnbondingDelegation = "unbondingDelegation" - QueryDelegatorValidators = "delegatorValidators" - QueryDelegatorValidator = "delegatorValidator" - QueryPool = "pool" - QueryParameters = "parameters" + QueryValidators = "validators" + QueryValidator = "validator" + QueryValidatorUnbondingDelegations = "validatorUnbondingDelegations" + QueryValidatorRedelegations = "validatorRedelegations" + QueryDelegator = "delegator" + QueryDelegation = "delegation" + QueryUnbondingDelegation = "unbondingDelegation" + QueryDelegatorValidators = "delegatorValidators" + QueryDelegatorValidator = "delegatorValidator" + QueryPool = "pool" + QueryParameters = "parameters" ) // creates a querier for staking REST endpoints @@ -30,6 +31,8 @@ func NewQuerier(k keep.Keeper, cdc *codec.Codec) sdk.Querier { return queryValidators(ctx, cdc, k) case QueryValidator: return queryValidator(ctx, cdc, req, k) + case QueryValidatorUnbondingDelegations: + return queryValidatorUnbondingDelegations(ctx, cdc, req, k) case QueryValidatorRedelegations: return queryValidatorRedelegations(ctx, cdc, req, k) case QueryDelegator: @@ -61,6 +64,7 @@ type QueryDelegatorParams struct { // defines the params for the following queries: // - 'custom/stake/validator' +// - 'custom/stake/validatorUnbondingDelegations' // - 'custom/stake/validatorRedelegations' type QueryValidatorParams struct { ValidatorAddr sdk.ValAddress @@ -106,6 +110,23 @@ func queryValidator(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k return res, nil } +func queryValidatorUnbondingDelegations(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { + var params QueryValidatorParams + + errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + if errRes != nil { + return []byte{}, sdk.ErrUnknownAddress("") + } + + unbonds := k.GetUnbondingDelegationsFromValidator(ctx, params.ValidatorAddr) + + res, errRes = codec.MarshalJSONIndent(cdc, unbonds) + if errRes != nil { + return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", errRes.Error())) + } + return res, nil +} + func queryValidatorRedelegations(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { var params QueryValidatorParams diff --git a/x/stake/querier/queryable_test.go b/x/stake/querier/queryable_test.go index c4b1fc21da..2a86084175 100644 --- a/x/stake/querier/queryable_test.go +++ b/x/stake/querier/queryable_test.go @@ -82,6 +82,9 @@ func TestNewQuerier(t *testing.T) { _, err = querier(ctx, []string{"validator"}, query) require.Nil(t, err) + _, err = querier(ctx, []string{"validatorUnbondingDelegations"}, query) + require.Nil(t, err) + _, err = querier(ctx, []string{"validatorRedelegations"}, query) require.Nil(t, err) }