Merge PR #3460: Implement fee distribution RESTful endpoints

This commit is contained in:
Alessio Treglia 2019-02-04 16:45:18 -08:00 committed by Jack Zampolin
parent 254c39a9e2
commit a2b73c8ab4
23 changed files with 985 additions and 157 deletions

View File

@ -6,6 +6,7 @@ BREAKING CHANGES
* [\#3284](https://github.com/cosmos/cosmos-sdk/issues/3284) Rename the `name`
field to `from` in the `base_req` body.
* [\#3485](https://github.com/cosmos/cosmos-sdk/pull/3485) Error responses are now JSON objects.
* [\#3477][distribution] endpoint changed "all_delegation_rewards" -> "delegator_total_rewards"
* Gaia CLI (`gaiacli`)
- [#3399](https://github.com/cosmos/cosmos-sdk/pull/3399) Add `gaiad validate-genesis` command to facilitate checking of genesis files
@ -19,6 +20,7 @@ BREAKING CHANGES
* SDK
* [\#3487](https://github.com/cosmos/cosmos-sdk/pull/3487) Move HTTP/REST utilities out of client/utils into a new dedicated client/rest package.
* [\#3490](https://github.com/cosmos/cosmos-sdk/issues/3490) ReadRESTReq() returns bool to avoid callers to write error responses twice.
* Tendermint
@ -26,6 +28,7 @@ BREAKING CHANGES
FEATURES
* Gaia REST API
* [\#2358](https://github.com/cosmos/cosmos-sdk/issues/2358) Add distribution module REST interface
* Gaia CLI (`gaiacli`)
* [\#3429](https://github.com/cosmos/cosmos-sdk/issues/3429) Support querying
@ -38,6 +41,7 @@ FEATURES
* SDK
* \#3270 [x/staking] limit number of ongoing unbonding delegations /redelegations per pair/trio
* [\#3477][distribution] new query endpoint "delegator_validators"
* Tendermint
@ -54,6 +58,7 @@ IMPROVEMENTS
(auto gas) to work with generate only.
* Gaia CLI (`gaiacli`)
* [\#3476](https://github.com/cosmos/cosmos-sdk/issues/3476) New `withdraw-all-rewards` command to withdraw all delegations rewards for delegators.
* Gaia
* [\#3418](https://github.com/cosmos/cosmos-sdk/issues/3418) Add vesting account

View File

@ -26,6 +26,8 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
"github.com/cosmos/cosmos-sdk/x/bank"
dclcommon "github.com/cosmos/cosmos-sdk/x/distribution/client/common"
distrrest "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
@ -918,3 +920,99 @@ func TestSlashingGetParams(t *testing.T) {
err := cdc.UnmarshalJSON([]byte(body), &params)
require.NoError(t, err)
}
func TestDistributionGetParams(t *testing.T) {
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{})
defer cleanup()
res, body := Request(t, port, "GET", "/distribution/parameters", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &dclcommon.PrettyParams{}))
}
func TestDistributionFlow(t *testing.T) {
addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t))
//addr2, seed2 = CreateAddr(t, name2, pw, GetKeyBase(t))
cleanup, _, valAddrs, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
defer cleanup()
valAddr := valAddrs[0]
operAddr := sdk.AccAddress(valAddr)
var rewards sdk.DecCoins
res, body := Request(t, port, "GET", fmt.Sprintf("/distribution/outstanding_rewards"), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
require.Equal(t, sdk.DecCoins(nil), rewards)
var valDistInfo distrrest.ValidatorDistInfo
res, body = Request(t, port, "GET", "/distribution/validators/"+valAddr.String(), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &valDistInfo))
require.Equal(t, valDistInfo.OperatorAddress.String(), sdk.AccAddress(valAddr).String())
require.Equal(t, valDistInfo.ValidatorCommission, sdk.DecCoins(nil))
require.Equal(t, valDistInfo.SelfBondRewards, sdk.DecCoins(nil))
// Delegate some coins
resultTx := doDelegate(t, port, name1, pw, addr, valAddr, 60, fees)
tests.WaitForHeight(resultTx.Height+1, port)
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
// send some coins
_, resultTx = doTransfer(t, port, seed, name1, memo, pw, addr, fees)
tests.WaitForHeight(resultTx.Height+5, port)
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
// Query outstanding rewards changed
oustandingRewards := mustParseDecCoins("9.80stake")
res, body = Request(t, port, "GET", fmt.Sprintf("/distribution/outstanding_rewards"), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
require.Equal(t, oustandingRewards, rewards)
// Query validator distribution info
res, body = Request(t, port, "GET", "/distribution/validators/"+valAddr.String(), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
valRewards := mustParseDecCoins("6.125stake")
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &valDistInfo))
require.Equal(t, valRewards, valDistInfo.SelfBondRewards)
// Query validator's rewards
res, body = Request(t, port, "GET", fmt.Sprintf("/distribution/validators/%s/rewards", valAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
require.Equal(t, valRewards, rewards)
// Query self-delegation
res, body = Request(t, port, "GET", fmt.Sprintf("/distribution/delegators/%s/rewards/%s", operAddr, valAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
require.Equal(t, valRewards, rewards)
// Query delegation
res, body = Request(t, port, "GET", fmt.Sprintf("/distribution/delegators/%s/rewards/%s", addr, valAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
require.Equal(t, mustParseDecCoins("3.675stake"), rewards)
// Query delegator's rewards total
res, body = Request(t, port, "GET", fmt.Sprintf("/distribution/delegators/%s/rewards", operAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
require.Equal(t, valRewards, rewards)
// Query delegator's withdrawal address
var withdrawAddr string
res, body = Request(t, port, "GET", fmt.Sprintf("/distribution/delegators/%s/withdraw_address", operAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &withdrawAddr))
require.Equal(t, operAddr.String(), withdrawAddr)
// Withdraw delegator's rewards
resultTx = doWithdrawDelegatorAllRewards(t, port, seed, name1, pw, addr, fees)
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
}

View File

@ -18,7 +18,7 @@ tags:
- name: ICS23
description: Slashing module APIs
- name: ICS24
description: WIP - Fee distribution module APIs
description: Fee distribution module APIs
- name: version
description: Query app version
schemes:
@ -1846,9 +1846,9 @@ paths:
type: string
500:
description: Internal Server Error
/distribution/pool:
/distribution/outstanding_rewards:
get:
summary: Fee distribution pool
summary: Fee distribution outstanding rewards
tags:
- ICS24
produces:
@ -1857,7 +1857,9 @@ paths:
200:
description: OK
schema:
$ref: "#/definitions/FeePool"
type: array
items:
$ref: "#/definitions/Coin"
500:
description: Internal Server Error
definitions:
@ -2198,7 +2200,7 @@ definitions:
power:
type: string
example: "1000"
accum:
proposer_priority:
type: string
example: "1000"
TextProposal:
@ -2367,36 +2369,12 @@ definitions:
type: string
shares_dst:
type: string
FeePool:
type: object
properties:
community_pool:
type: array
items:
$ref: "#/definitions/Coin"
val_accum:
$ref: "#/definitions/TotalAccum"
val_pool:
type: array
items:
$ref: "#/definitions/Coin"
TotalAccum:
type: object
properties:
update_height:
type: integer
accum:
type: string
ValidatorDistInfo:
type: object
properties:
operator_addr:
$ref: "#/definitions/ValidatorAddress"
fee_pool_withdrawal_height:
type: integer
del_accum:
$ref: "#/definitions/TotalAccum"
del_pool:
self_bond_rewards:
type: array
items:
$ref: "#/definitions/Coin"

View File

@ -60,6 +60,8 @@ import (
authRest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
bankRest "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
distrRest "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
govRest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
slashingRest "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
stakingRest "github.com/cosmos/cosmos-sdk/x/staking/client/rest"
@ -294,6 +296,11 @@ func InitializeTestLCD(
genesisState.StakingData.Pool.NotBondedTokens = genesisState.StakingData.Pool.NotBondedTokens.Add(sdk.NewInt(100))
}
inflationMin := sdk.MustNewDecFromStr("10000.0")
genesisState.MintData.Minter.Inflation = inflationMin
genesisState.MintData.Params.InflationMax = sdk.MustNewDecFromStr("15000.0")
genesisState.MintData.Params.InflationMin = inflationMin
appState, err := codec.MarshalJSONIndent(cdc, genesisState)
require.NoError(t, err)
genDoc.AppState = appState
@ -390,6 +397,7 @@ func registerRoutes(rs *RestServer) {
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
authRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, auth.StoreKey)
bankRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
distrRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, distr.StoreKey)
stakingRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
slashingRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
govRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
@ -1382,3 +1390,37 @@ func doUnjail(t *testing.T, port, seed, name, password string,
type unjailReq struct {
BaseReq rest.BaseReq `json:"base_req"`
}
// ICS24 - fee distribution
// POST /distribution/delegators/{delgatorAddr}/rewards Withdraw delegator rewards
func doWithdrawDelegatorAllRewards(t *testing.T, port, seed, name, password string,
delegatorAddr sdk.AccAddress, fees sdk.Coins) (resultTx ctypes.ResultBroadcastTxCommit) {
// get the account to get the sequence
acc := getAccount(t, port, delegatorAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)
wr := struct {
BaseReq rest.BaseReq `json:"base_req"`
}{BaseReq: baseReq}
req := cdc.MustMarshalJSON(wr)
res, body := Request(t, port, "POST", fmt.Sprintf("/distribution/delegators/%s/rewards", delegatorAddr), req)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var results ctypes.ResultBroadcastTxCommit
cdc.MustUnmarshalJSON([]byte(body), &results)
return results
}
func mustParseDecCoins(dcstring string) sdk.DecCoins {
dcoins, err := sdk.ParseDecCoins(dcstring)
if err != nil {
panic(err)
}
return dcoins
}

View File

@ -98,7 +98,7 @@ func (br BaseReq) ValidateBasic(w http.ResponseWriter) bool {
/*
ReadRESTReq is a simple convenience wrapper that reads the body and
unmarshals to the req interface.
unmarshals to the req interface. Returns false if errors occurred.
Usage:
type SomeReq struct {
@ -107,20 +107,22 @@ unmarshals to the req interface.
}
req := new(SomeReq)
err := ReadRESTReq(w, r, cdc, req)
if ok := ReadRESTReq(w, r, cdc, req); !ok {
return
}
*/
func ReadRESTReq(w http.ResponseWriter, r *http.Request, cdc *codec.Codec, req interface{}) error {
func ReadRESTReq(w http.ResponseWriter, r *http.Request, cdc *codec.Codec, req interface{}) bool {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return err
return false
}
err = cdc.UnmarshalJSON(body, req)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to decode JSON payload: %s", err))
return err
return false
}
return nil
return true
}

View File

@ -25,7 +25,7 @@ import (
at "github.com/cosmos/cosmos-sdk/x/auth"
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
dist "github.com/cosmos/cosmos-sdk/x/distribution"
dist "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
gv "github.com/cosmos/cosmos-sdk/x/gov"
gov "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
sl "github.com/cosmos/cosmos-sdk/x/slashing"
@ -35,6 +35,7 @@ import (
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
distcmd "github.com/cosmos/cosmos-sdk/x/distribution"
distClient "github.com/cosmos/cosmos-sdk/x/distribution/client"
govClient "github.com/cosmos/cosmos-sdk/x/gov/client"
slashingClient "github.com/cosmos/cosmos-sdk/x/slashing/client"
@ -65,7 +66,7 @@ func main() {
// TODO: Make the lcd command take a list of ModuleClient
mc := []sdk.ModuleClients{
govClient.NewModuleClient(gv.StoreKey, cdc),
distClient.NewModuleClient(dist.StoreKey, cdc),
distClient.NewModuleClient(distcmd.StoreKey, cdc),
stakingClient.NewModuleClient(st.StoreKey, cdc),
slashingClient.NewModuleClient(sl.StoreKey, cdc),
}
@ -161,6 +162,7 @@ func registerRoutes(rs *lcd.RestServer) {
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
auth.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, at.StoreKey)
bank.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
dist.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, distcmd.StoreKey)
staking.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
slashing.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
gov.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)

View File

@ -26,8 +26,7 @@ func SignTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha
return func(w http.ResponseWriter, r *http.Request) {
var m SignBody
if err := rest.ReadRESTReq(w, r, cdc, &m); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
if !rest.ReadRESTReq(w, r, cdc, &m) {
return
}

View File

@ -44,8 +44,7 @@ func SendRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIC
}
var req sendReq
err = rest.ReadRESTReq(w, r, cdc, &req)
if err != nil {
if !rest.ReadRESTReq(w, r, cdc, &req) {
return
}

View File

@ -23,9 +23,10 @@ type (
FeeCollectionKeeper = types.FeeCollectionKeeper
// querier param types
QueryValidatorCommissionParams = keeper.QueryValidatorCommissionParams
QueryValidatorSlashesParams = keeper.QueryValidatorSlashesParams
QueryDelegationRewardsParams = keeper.QueryDelegationRewardsParams
QueryValidatorCommissionParams = keeper.QueryValidatorCommissionParams
QueryValidatorSlashesParams = keeper.QueryValidatorSlashesParams
QueryDelegationRewardsParams = keeper.QueryDelegationRewardsParams
QueryDelegatorWithdrawAddrParams = keeper.QueryDelegatorWithdrawAddrParams
)
const (
@ -49,12 +50,14 @@ var (
NewMsgWithdrawDelegatorReward = types.NewMsgWithdrawDelegatorReward
NewMsgWithdrawValidatorCommission = types.NewMsgWithdrawValidatorCommission
NewKeeper = keeper.NewKeeper
NewQuerier = keeper.NewQuerier
NewQueryValidatorCommissionParams = keeper.NewQueryValidatorCommissionParams
NewQueryValidatorSlashesParams = keeper.NewQueryValidatorSlashesParams
NewQueryDelegationRewardsParams = keeper.NewQueryDelegationRewardsParams
DefaultParamspace = keeper.DefaultParamspace
NewKeeper = keeper.NewKeeper
NewQuerier = keeper.NewQuerier
NewQueryValidatorCommissionParams = keeper.NewQueryValidatorCommissionParams
NewQueryValidatorSlashesParams = keeper.NewQueryValidatorSlashesParams
NewQueryDelegationRewardsParams = keeper.NewQueryDelegationRewardsParams
NewQueryDelegatorParams = keeper.NewQueryDelegatorParams
NewQueryDelegatorWithdrawAddrParams = keeper.NewQueryDelegatorWithdrawAddrParams
DefaultParamspace = keeper.DefaultParamspace
RegisterCodec = types.RegisterCodec
DefaultGenesisState = types.DefaultGenesisState

View File

@ -10,6 +10,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/distribution/client/common"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
)
@ -21,34 +22,10 @@ func GetCmdQueryParams(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Query distribution params",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
route := fmt.Sprintf("custom/%s/params/community_tax", queryRoute)
retCommunityTax, err := cliCtx.QueryWithData(route, []byte{})
params, err := common.QueryParams(cliCtx, queryRoute)
if err != nil {
return err
}
route = fmt.Sprintf("custom/%s/params/base_proposer_reward", queryRoute)
retBaseProposerReward, err := cliCtx.QueryWithData(route, []byte{})
if err != nil {
return err
}
route = fmt.Sprintf("custom/%s/params/bonus_proposer_reward", queryRoute)
retBonusProposerReward, err := cliCtx.QueryWithData(route, []byte{})
if err != nil {
return err
}
route = fmt.Sprintf("custom/%s/params/withdraw_addr_enabled", queryRoute)
retWithdrawAddrEnabled, err := cliCtx.QueryWithData(route, []byte{})
if err != nil {
return err
}
params := NewPrettyParams(retCommunityTax, retBaseProposerReward,
retBonusProposerReward, retWithdrawAddrEnabled)
return cliCtx.PrintOutput(params)
},
}
@ -90,13 +67,7 @@ func GetCmdQueryValidatorCommission(queryRoute string, cdc *codec.Codec) *cobra.
return err
}
bz, err := cdc.MarshalJSON(distr.NewQueryValidatorCommissionParams(validatorAddr))
if err != nil {
return err
}
route := fmt.Sprintf("custom/%s/validator_commission", queryRoute)
res, err := cliCtx.QueryWithData(route, bz)
res, err := common.QueryValidatorCommission(cliCtx, cdc, queryRoute, validatorAddr)
if err != nil {
return err
}
@ -159,42 +130,20 @@ func GetCmdQueryDelegatorRewards(queryRoute string, cdc *codec.Codec) *cobra.Com
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
delegatorAddr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return err
}
var (
route string
params distr.QueryDelegationRewardsParams
result sdk.DecCoins
)
if len(args) == 1 {
// query for all rewards
params = distr.NewQueryDelegationRewardsParams(delegatorAddr, nil)
route = fmt.Sprintf("custom/%s/all_delegation_rewards", queryRoute)
var resp []byte
var err error
if len(args) == 2 {
// query for rewards from a particular delegation
resp, err = common.QueryDelegationRewards(cliCtx, cdc, queryRoute, args[0], args[1])
} else {
// query for rewards from a particular validator
validatorAddr, err := sdk.ValAddressFromBech32(args[1])
if err != nil {
return err
}
params = distr.NewQueryDelegationRewardsParams(delegatorAddr, validatorAddr)
route = fmt.Sprintf("custom/%s/delegation_rewards", queryRoute)
// query for delegator total rewards
resp, err = common.QueryDelegatorTotalRewards(cliCtx, cdc, queryRoute, args[0])
}
bz, err := cdc.MarshalJSON(params)
if err != nil {
return err
}
resp, err := cliCtx.QueryWithData(route, bz)
if err != nil {
return err
}
var result sdk.DecCoins
cdc.MustUnmarshalJSON(resp, &result)
return cliCtx.PrintOutput(result)
},

View File

@ -16,6 +16,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/distribution/client/common"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
)
@ -89,7 +90,39 @@ func GetCmdWithdrawRewards(cdc *codec.Codec) *cobra.Command {
return cmd
}
// GetCmdDelegate implements the delegate command.
// command to withdraw all rewards
func GetCmdWithdrawAllRewards(cdc *codec.Codec, queryRoute string) *cobra.Command {
cmd := &cobra.Command{
Use: "withdraw-all-rewards [delegator-addr]",
Short: "withdraw all delegations rewards for a delegator",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithAccountDecoder(cdc)
delAddr := cliCtx.GetFromAddress()
msgs, err := common.WithdrawAllDelegatorRewards(cliCtx, cdc, queryRoute, delAddr)
if err != nil {
return err
}
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, msgs, false)
}
// build and sign the transaction, then broadcast to Tendermint
return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, msgs)
},
}
cmd.Flags().String(flagOnlyFromValidator, "", "only withdraw from this validator address (in bech)")
cmd.Flags().Bool(flagIsValidator, false, "also withdraw validator's commission")
return cmd
}
// command to replace a delegator's withdrawal address
func GetCmdSetWithdrawAddr(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "set-withdraw-addr [withdraw-addr]",

View File

@ -0,0 +1,145 @@
package common
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
)
// QueryParams actually queries distribution params.
func QueryParams(cliCtx context.CLIContext, queryRoute string) (PrettyParams, error) {
route := fmt.Sprintf("custom/%s/params/community_tax", queryRoute)
retCommunityTax, err := cliCtx.QueryWithData(route, []byte{})
if err != nil {
return PrettyParams{}, err
}
route = fmt.Sprintf("custom/%s/params/base_proposer_reward", queryRoute)
retBaseProposerReward, err := cliCtx.QueryWithData(route, []byte{})
if err != nil {
return PrettyParams{}, err
}
route = fmt.Sprintf("custom/%s/params/bonus_proposer_reward", queryRoute)
retBonusProposerReward, err := cliCtx.QueryWithData(route, []byte{})
if err != nil {
return PrettyParams{}, err
}
route = fmt.Sprintf("custom/%s/params/withdraw_addr_enabled", queryRoute)
retWithdrawAddrEnabled, err := cliCtx.QueryWithData(route, []byte{})
if err != nil {
return PrettyParams{}, err
}
return NewPrettyParams(retCommunityTax, retBaseProposerReward,
retBonusProposerReward, retWithdrawAddrEnabled), nil
}
// QueryDelegatorTotalRewards queries delegator total rewards.
func QueryDelegatorTotalRewards(cliCtx context.CLIContext, cdc *codec.Codec,
queryRoute, delAddr string) ([]byte, error) {
delegatorAddr, err := sdk.AccAddressFromBech32(delAddr)
if err != nil {
return nil, err
}
return cliCtx.QueryWithData(
fmt.Sprintf("custom/%s/delegator_total_rewards", queryRoute),
cdc.MustMarshalJSON(distr.NewQueryDelegatorParams(delegatorAddr)),
)
}
// QueryDelegationRewards queries a delegation rewards.
func QueryDelegationRewards(cliCtx context.CLIContext, cdc *codec.Codec,
queryRoute, delAddr, valAddr string) ([]byte, error) {
delegatorAddr, err := sdk.AccAddressFromBech32(delAddr)
if err != nil {
return nil, err
}
validatorAddr, err := sdk.ValAddressFromBech32(valAddr)
if err != nil {
return nil, err
}
return cliCtx.QueryWithData(
fmt.Sprintf("custom/%s/delegation_rewards", queryRoute),
cdc.MustMarshalJSON(distr.NewQueryDelegationRewardsParams(delegatorAddr, validatorAddr)),
)
}
// QueryDelegatorValidators returns delegator's list of validators
// it submitted delegations to.
func QueryDelegatorValidators(cliCtx context.CLIContext, cdc *codec.Codec,
queryRoute string, delegatorAddr sdk.AccAddress) ([]byte, error) {
return cliCtx.QueryWithData(
fmt.Sprintf("custom/%s/delegator_validators", queryRoute),
cdc.MustMarshalJSON(distr.NewQueryDelegatorParams(delegatorAddr)),
)
}
// QueryValidatorCommission returns a validator's commission.
func QueryValidatorCommission(cliCtx context.CLIContext, cdc *codec.Codec,
queryRoute string, validatorAddr sdk.ValAddress) ([]byte, error) {
return cliCtx.QueryWithData(
fmt.Sprintf("custom/%s/validator_commission", queryRoute),
cdc.MustMarshalJSON(distr.NewQueryValidatorCommissionParams(validatorAddr)),
)
}
// WithdrawAllDelegatorRewards builds a multi-message slice to be used
// to withdraw all delegations rewards for the given delegator.
func WithdrawAllDelegatorRewards(cliCtx context.CLIContext, cdc *codec.Codec,
queryRoute string, delegatorAddr sdk.AccAddress) ([]sdk.Msg, error) {
// retrieve the comprehensive list of all validators which the
// delegator had submitted delegations to
bz, err := QueryDelegatorValidators(cliCtx, cdc, queryRoute, delegatorAddr)
if err != nil {
return nil, err
}
var validators []sdk.ValAddress
if err := cdc.UnmarshalJSON(bz, &validators); err != nil {
return nil, err
}
// build multi-message transaction
var msgs []sdk.Msg
for _, valAddr := range validators {
msg := distr.NewMsgWithdrawDelegatorReward(delegatorAddr, valAddr)
if err := msg.ValidateBasic(); err != nil {
return nil, err
}
msgs = append(msgs, msg)
}
return msgs, nil
}
// WithdrawValidatorRewardsAndCommission builds a two-message message slice to be
// used to withdraw both validation's commission and self-delegation reward.
func WithdrawValidatorRewardsAndCommission(validatorAddr sdk.ValAddress) ([]sdk.Msg, error) {
commissionMsg := distr.NewMsgWithdrawValidatorCommission(validatorAddr)
if err := commissionMsg.ValidateBasic(); err != nil {
return nil, err
}
// build and validate MsgWithdrawDelegatorReward
rewardMsg := distr.NewMsgWithdrawDelegatorReward(
sdk.AccAddress(validatorAddr.Bytes()), validatorAddr)
if err := rewardMsg.ValidateBasic(); err != nil {
return nil, err
}
return []sdk.Msg{commissionMsg, rewardMsg}, nil
}

View File

@ -0,0 +1,35 @@
package common
import (
"testing"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/stretchr/testify/require"
)
func TestQueryDelegationRewardsAddrValidation(t *testing.T) {
cdc := codec.New()
ctx := context.NewCLIContext().WithCodec(cdc)
type args struct {
delAddr string
valAddr string
}
tests := []struct {
name string
args args
want []byte
wantErr bool
}{
{"invalid delegator address", args{"invalid", ""}, nil, true},
{"empty delegator address", args{"", ""}, nil, true},
{"invalid validator address", args{"cosmos1zxcsu7l5qxs53lvp0fqgd09a9r2g6kqrk2cdpa", "invalid"}, nil, true},
{"empty validator address", args{"cosmos1zxcsu7l5qxs53lvp0fqgd09a9r2g6kqrk2cdpa", ""}, nil, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := QueryDelegationRewards(ctx, cdc, "", tt.args.delAddr, tt.args.valAddr)
require.True(t, err != nil, tt.wantErr)
})
}
}

View File

@ -1,4 +1,4 @@
package cli
package common
import (
"encoding/json"

View File

@ -46,6 +46,7 @@ func (mc ModuleClient) GetTxCmd() *cobra.Command {
distTxCmd.AddCommand(client.PostCommands(
distCmds.GetCmdWithdrawRewards(mc.cdc),
distCmds.GetCmdSetWithdrawAddr(mc.cdc),
distCmds.GetCmdWithdrawAllRewards(mc.cdc, mc.storeKey),
)...)
return distTxCmd

View File

@ -0,0 +1,244 @@
package rest
import (
"fmt"
"net/http"
"github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/distribution/client/common"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/rest"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/gorilla/mux"
)
func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router,
cdc *codec.Codec, queryRoute string) {
// Get the total rewards balance from all delegations
r.HandleFunc(
"/distribution/delegators/{delegatorAddr}/rewards",
delegatorRewardsHandlerFn(cliCtx, cdc, queryRoute),
).Methods("GET")
// Query a delegation reward
r.HandleFunc(
"/distribution/delegators/{delegatorAddr}/rewards/{validatorAddr}",
delegationRewardsHandlerFn(cliCtx, cdc, queryRoute),
).Methods("GET")
// Get the rewards withdrawal address
r.HandleFunc(
"/distribution/delegators/{delegatorAddr}/withdraw_address",
delegatorWithdrawalAddrHandlerFn(cliCtx, cdc, queryRoute),
).Methods("GET")
// Validator distribution information
r.HandleFunc(
"/distribution/validators/{validatorAddr}",
validatorInfoHandlerFn(cliCtx, cdc, queryRoute),
).Methods("GET")
// Commission and self-delegation rewards of a single a validator
r.HandleFunc(
"/distribution/validators/{validatorAddr}/rewards",
validatorRewardsHandlerFn(cliCtx, cdc, queryRoute),
).Methods("GET")
// Get the current distribution parameter values
r.HandleFunc(
"/distribution/parameters",
paramsHandlerFn(cliCtx, cdc, queryRoute),
).Methods("GET")
// Get the current distribution pool
r.HandleFunc(
"/distribution/outstanding_rewards",
outstandingRewardsHandlerFn(cliCtx, cdc, queryRoute),
).Methods("GET")
}
// HTTP request handler to query the total rewards balance from all delegations
func delegatorRewardsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec,
queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// query for rewards from a particular delegator
res, ok := checkResponseQueryDelegatorTotalRewards(w, cliCtx, cdc, queryRoute,
mux.Vars(r)["delegatorAddr"])
if !ok {
return
}
rest.PostProcessResponse(w, cdc, res, cliCtx.Indent)
}
}
// HTTP request handler to query a delegation rewards
func delegationRewardsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec,
queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// query for rewards from a particular delegation
res, ok := checkResponseQueryDelegationRewards(w, cliCtx, cdc, queryRoute,
mux.Vars(r)["delegatorAddr"], mux.Vars(r)["validatorAddr"])
if !ok {
return
}
rest.PostProcessResponse(w, cdc, res, cliCtx.Indent)
}
}
// HTTP request handler to query a delegation rewards
func delegatorWithdrawalAddrHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec,
queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
delegatorAddr, ok := checkDelegatorAddressVar(w, r)
if !ok {
return
}
bz := cdc.MustMarshalJSON(distribution.NewQueryDelegatorWithdrawAddrParams(delegatorAddr))
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/withdraw_addr", queryRoute), bz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
rest.PostProcessResponse(w, cdc, res, cliCtx.Indent)
}
}
// ValidatorDistInfo defines the properties of
// validator distribution information response.
type ValidatorDistInfo struct {
OperatorAddress sdk.AccAddress `json:"operator_addr"`
SelfBondRewards sdk.DecCoins `json:"self_bond_rewards"`
ValidatorCommission types.ValidatorAccumulatedCommission `json:"val_commission"`
}
// NewValidatorDistInfo creates a new instance of ValidatorDistInfo.
func NewValidatorDistInfo(operatorAddr sdk.AccAddress, rewards sdk.DecCoins,
commission types.ValidatorAccumulatedCommission) ValidatorDistInfo {
return ValidatorDistInfo{
OperatorAddress: operatorAddr,
SelfBondRewards: rewards,
ValidatorCommission: commission,
}
}
// HTTP request handler to query validator's distribution information
func validatorInfoHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec,
queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
valAddr := mux.Vars(r)["validatorAddr"]
validatorAddr, ok := checkValidatorAddressVar(w, r)
if !ok {
return
}
// query commission
commissionRes, err := common.QueryValidatorCommission(cliCtx, cdc, queryRoute, validatorAddr)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
var valCom types.ValidatorAccumulatedCommission
cdc.MustUnmarshalJSON(commissionRes, &valCom)
// self bond rewards
delAddr := sdk.AccAddress(validatorAddr)
rewardsRes, ok := checkResponseQueryDelegationRewards(w, cliCtx, cdc, queryRoute,
delAddr.String(), valAddr)
if !ok {
return
}
var rewards sdk.DecCoins
cdc.MustUnmarshalJSON(rewardsRes, &rewards)
// Prepare response
res := cdc.MustMarshalJSON(NewValidatorDistInfo(delAddr, rewards, valCom))
rest.PostProcessResponse(w, cdc, res, cliCtx.Indent)
}
}
// HTTP request handler to query validator's commission and self-delegation rewards
func validatorRewardsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec,
queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
valAddr := mux.Vars(r)["validatorAddr"]
validatorAddr, ok := checkValidatorAddressVar(w, r)
if !ok {
return
}
delAddr := sdk.AccAddress(validatorAddr).String()
res, ok := checkResponseQueryDelegationRewards(w, cliCtx, cdc, queryRoute, delAddr, valAddr)
if !ok {
return
}
rest.PostProcessResponse(w, cdc, res, cliCtx.Indent)
}
}
// HTTP request handler to query the distribution params values
func paramsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec,
queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
params, err := common.QueryParams(cliCtx, queryRoute)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
rest.PostProcessResponse(w, cdc, params, cliCtx.Indent)
}
}
// HTTP request handler to query the outstanding rewards
func outstandingRewardsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec,
queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/outstanding_rewards", queryRoute), []byte{})
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
rest.PostProcessResponse(w, cdc, res, cliCtx.Indent)
}
}
func checkResponseQueryDelegatorTotalRewards(w http.ResponseWriter, cliCtx context.CLIContext, cdc *codec.Codec,
queryRoute, delAddr string) (res []byte, ok bool) {
res, err := common.QueryDelegatorTotalRewards(cliCtx, cdc, queryRoute, delAddr)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return nil, false
}
return res, true
}
func checkResponseQueryDelegationRewards(w http.ResponseWriter, cliCtx context.CLIContext, cdc *codec.Codec,
queryRoute, delAddr, valAddr string) (res []byte, ok bool) {
res, err := common.QueryDelegationRewards(cliCtx, cdc, queryRoute, delAddr, valAddr)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return nil, false
}
return res, true
}

View File

@ -0,0 +1,13 @@
package rest
import (
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/gorilla/mux"
)
// RegisterRoutes register distribution REST routes.
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec, queryRoute string) {
registerQueryRoutes(cliCtx, r, cdc, queryRoute)
registerTxRoutes(cliCtx, r, cdc, queryRoute)
}

View File

@ -0,0 +1,222 @@
package rest
import (
"net/http"
"github.com/cosmos/cosmos-sdk/client/rest"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/distribution/client/common"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router,
cdc *codec.Codec, queryRoute string) {
// Withdraw all delegator rewards
r.HandleFunc(
"/distribution/delegators/{delegatorAddr}/rewards",
withdrawDelegatorRewardsHandlerFn(cdc, cliCtx, queryRoute),
).Methods("POST")
// Withdraw delegation rewards
r.HandleFunc(
"/distribution/delegators/{delegatorAddr}/rewards/{validatorAddr}",
withdrawDelegationRewardsHandlerFn(cdc, cliCtx),
).Methods("POST")
// Replace the rewards withdrawal address
r.HandleFunc(
"/distribution/delegators/{delegatorAddr}/withdraw_address",
setDelegatorWithdrawalAddrHandlerFn(cdc, cliCtx),
).Methods("POST")
// Withdraw validator rewards and commission
r.HandleFunc(
"/distribution/validators/{validatorAddr}/rewards",
withdrawValidatorRewardsHandlerFn(cdc, cliCtx),
).Methods("POST")
}
type (
withdrawRewardsReq struct {
BaseReq rest.BaseReq `json:"base_req"`
}
setWithdrawalAddrReq struct {
BaseReq rest.BaseReq `json:"base_req"`
WithdrawAddress sdk.AccAddress `json:"withdraw_address"`
}
)
// Withdraw delegator rewards
func withdrawDelegatorRewardsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext,
queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req withdrawRewardsReq
if !rest.ReadRESTReq(w, r, cdc, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
// read and validate URL's variables
delAddr, ok := checkDelegatorAddressVar(w, r)
if !ok {
return
}
msgs, err := common.WithdrawAllDelegatorRewards(cliCtx, cdc, queryRoute, delAddr)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
if req.BaseReq.GenerateOnly {
rest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, msgs)
return
}
rest.CompleteAndBroadcastTxREST(w, r, cliCtx, req.BaseReq, msgs, cdc)
}
}
// Withdraw delegation rewards
func withdrawDelegationRewardsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req withdrawRewardsReq
if !rest.ReadRESTReq(w, r, cdc, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
// read and validate URL's variables
delAddr, ok := checkDelegatorAddressVar(w, r)
if !ok {
return
}
valAddr, ok := checkValidatorAddressVar(w, r)
if !ok {
return
}
msg := types.NewMsgWithdrawDelegatorReward(delAddr, valAddr)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
if req.BaseReq.GenerateOnly {
rest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
return
}
rest.CompleteAndBroadcastTxREST(w, r, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc)
}
}
// Replace the rewards withdrawal address
func setDelegatorWithdrawalAddrHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req setWithdrawalAddrReq
if !rest.ReadRESTReq(w, r, cdc, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
// read and validate URL's variables
delAddr, ok := checkDelegatorAddressVar(w, r)
if !ok {
return
}
msg := types.NewMsgSetWithdrawAddress(delAddr, req.WithdrawAddress)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
if req.BaseReq.GenerateOnly {
rest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
return
}
rest.CompleteAndBroadcastTxREST(w, r, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc)
}
}
// Withdraw validator rewards and commission
func withdrawValidatorRewardsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req withdrawRewardsReq
if !rest.ReadRESTReq(w, r, cdc, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
// read and validate URL's variable
valAddr, ok := checkValidatorAddressVar(w, r)
if !ok {
return
}
// prepare multi-message transaction
msgs, err := common.WithdrawValidatorRewardsAndCommission(valAddr)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
if req.BaseReq.GenerateOnly {
rest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, msgs)
return
}
rest.CompleteAndBroadcastTxREST(w, r, cliCtx, req.BaseReq, msgs, cdc)
}
}
// Auxiliary
func checkDelegatorAddressVar(w http.ResponseWriter, r *http.Request) (sdk.AccAddress, bool) {
addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["delegatorAddr"])
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return nil, false
}
return addr, true
}
func checkValidatorAddressVar(w http.ResponseWriter, r *http.Request) (sdk.ValAddress, bool) {
addr, err := sdk.ValAddressFromBech32(mux.Vars(r)["validatorAddr"])
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return nil, false
}
return addr, true
}

View File

@ -12,12 +12,14 @@ import (
// nolint
const (
QueryParams = "params"
QueryOutstandingRewards = "outstanding_rewards"
QueryValidatorCommission = "validator_commission"
QueryValidatorSlashes = "validator_slashes"
QueryDelegationRewards = "delegation_rewards"
QueryAllDelegationRewards = "all_delegation_rewards"
QueryParams = "params"
QueryOutstandingRewards = "outstanding_rewards"
QueryValidatorCommission = "validator_commission"
QueryValidatorSlashes = "validator_slashes"
QueryDelegationRewards = "delegation_rewards"
QueryDelegatorTotalRewards = "delegator_total_rewards"
QueryDelegatorValidators = "delegator_validators"
QueryWithdrawAddr = "withdraw_addr"
ParamCommunityTax = "community_tax"
ParamBaseProposerReward = "base_proposer_reward"
@ -43,8 +45,14 @@ func NewQuerier(k Keeper) sdk.Querier {
case QueryDelegationRewards:
return queryDelegationRewards(ctx, path[1:], req, k)
case QueryAllDelegationRewards:
return queryAllDelegationRewards(ctx, path[1:], req, k)
case QueryDelegatorTotalRewards:
return queryDelegatorTotalRewards(ctx, path[1:], req, k)
case QueryDelegatorValidators:
return queryDelegatorValidators(ctx, path[1:], req, k)
case QueryWithdrawAddr:
return queryDelegatorWithdrawAddress(ctx, path[1:], req, k)
default:
return nil, sdk.ErrUnknownRequest("unknown distr query endpoint")
@ -190,8 +198,20 @@ func queryDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuery,
return bz, nil
}
func queryAllDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) {
var params QueryDelegationRewardsParams
// params for query 'custom/distr/delegator_total_rewards' and 'custom/distr/delegator_validators'
type QueryDelegatorParams struct {
DelegatorAddr sdk.AccAddress `json:"delegator_addr"`
}
// creates a new instance of QueryDelegationRewardsParams
func NewQueryDelegatorParams(delegatorAddr sdk.AccAddress) QueryDelegatorParams {
return QueryDelegatorParams{
DelegatorAddr: delegatorAddr,
}
}
func queryDelegatorTotalRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) {
var params QueryDelegatorParams
err := k.cdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error()))
@ -221,3 +241,59 @@ func queryAllDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuer
return bz, nil
}
func queryDelegatorValidators(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) {
var params QueryDelegatorParams
err := k.cdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error()))
}
// cache-wrap context as to not persist state changes during querying
ctx, _ = ctx.CacheContext()
var validators []sdk.ValAddress
k.stakingKeeper.IterateDelegations(
ctx, params.DelegatorAddr,
func(_ int64, del sdk.Delegation) (stop bool) {
validators = append(validators[:], del.GetValidatorAddr())
return false
},
)
bz, err := codec.MarshalJSONIndent(k.cdc, validators)
if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error()))
}
return bz, nil
}
// params for query 'custom/distr/withdraw_addr'
type QueryDelegatorWithdrawAddrParams struct {
DelegatorAddr sdk.AccAddress `json:"delegator_addr"`
}
// NewQueryDelegatorWithdrawAddrParams creates a new instance of QueryDelegatorWithdrawAddrParams.
func NewQueryDelegatorWithdrawAddrParams(delegatorAddr sdk.AccAddress) QueryDelegatorWithdrawAddrParams {
return QueryDelegatorWithdrawAddrParams{DelegatorAddr: delegatorAddr}
}
func queryDelegatorWithdrawAddress(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) {
var params QueryDelegatorWithdrawAddrParams
err := k.cdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error()))
}
// cache-wrap context as to not persist state changes during querying
ctx, _ = ctx.CacheContext()
withdrawAddr := k.GetDelegatorWithdrawAddr(ctx, params.DelegatorAddr)
bz, err := codec.MarshalJSONIndent(k.cdc, withdrawAddr)
if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error()))
}
return bz, nil
}

View File

@ -77,9 +77,7 @@ type voteReq struct {
func postProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req postProposalReq
err := rest.ReadRESTReq(w, r, cdc, &req)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
if !rest.ReadRESTReq(w, r, cdc, &req) {
return
}
@ -96,8 +94,7 @@ func postProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han
// create the message
msg := gov.NewMsgSubmitProposal(req.Title, req.Description, proposalType, req.Proposer, req.InitialDeposit)
err = msg.ValidateBasic()
if err != nil {
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
@ -128,8 +125,7 @@ func depositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerF
}
var req depositReq
err := rest.ReadRESTReq(w, r, cdc, &req)
if err != nil {
if !rest.ReadRESTReq(w, r, cdc, &req) {
return
}
@ -140,8 +136,7 @@ func depositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerF
// create the message
msg := gov.NewMsgDeposit(req.Depositor, proposalID, req.Amount)
err = msg.ValidateBasic()
if err != nil {
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
@ -172,8 +167,7 @@ func voteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc
}
var req voteReq
err := rest.ReadRESTReq(w, r, cdc, &req)
if err != nil {
if !rest.ReadRESTReq(w, r, cdc, &req) {
return
}
@ -190,8 +184,7 @@ func voteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc
// create the message
msg := gov.NewMsgVote(req.Voter, proposalID, voteOption)
err = msg.ValidateBasic()
if err != nil {
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}

View File

@ -39,8 +39,7 @@ func TransferRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.
}
var req transferReq
err = rest.ReadRESTReq(w, r, cdc, &req)
if err != nil {
if !rest.ReadRESTReq(w, r, cdc, &req) {
return
}

View File

@ -34,8 +34,7 @@ func unjailRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CL
bech32validator := vars["validatorAddr"]
var req UnjailReq
err := rest.ReadRESTReq(w, r, cdc, &req)
if err != nil {
if !rest.ReadRESTReq(w, r, cdc, &req) {
return
}

View File

@ -58,9 +58,7 @@ func postDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.
return func(w http.ResponseWriter, r *http.Request) {
var req msgDelegationsInput
err := rest.ReadRESTReq(w, r, cdc, &req)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
if !rest.ReadRESTReq(w, r, cdc, &req) {
return
}
@ -70,8 +68,7 @@ func postDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.
}
msg := staking.NewMsgDelegate(req.DelegatorAddr, req.ValidatorAddr, req.Delegation)
err = msg.ValidateBasic()
if err != nil {
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
@ -103,9 +100,7 @@ func postRedelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx contex
return func(w http.ResponseWriter, r *http.Request) {
var req msgBeginRedelegateInput
err := rest.ReadRESTReq(w, r, cdc, &req)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
if !rest.ReadRESTReq(w, r, cdc, &req) {
return
}
@ -115,8 +110,7 @@ func postRedelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx contex
}
msg := staking.NewMsgBeginRedelegate(req.DelegatorAddr, req.ValidatorSrcAddr, req.ValidatorDstAddr, req.SharesAmount)
err = msg.ValidateBasic()
if err != nil {
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
@ -148,9 +142,7 @@ func postUnbondingDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx
return func(w http.ResponseWriter, r *http.Request) {
var req msgUndelegateInput
err := rest.ReadRESTReq(w, r, cdc, &req)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
if !rest.ReadRESTReq(w, r, cdc, &req) {
return
}
@ -160,8 +152,7 @@ func postUnbondingDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx
}
msg := staking.NewMsgUndelegate(req.DelegatorAddr, req.ValidatorAddr, req.SharesAmount)
err = msg.ValidateBasic()
if err != nil {
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}