Skip to content

Commit

Permalink
feat: split commands for withdrawal of rewards and commission (#108)
Browse files Browse the repository at this point in the history
  • Loading branch information
forcodedancing authored Feb 16, 2023
1 parent 97c6273 commit e694aed
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 24 deletions.
49 changes: 38 additions & 11 deletions x/distribution/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (

// Transaction flags for the x/distribution module
var (
FlagCommission = "commission"
FlagMaxMessagesPerTx = "max-msgs"
)

Expand All @@ -38,6 +37,7 @@ func NewTxCmd() *cobra.Command {

distTxCmd.AddCommand(
NewWithdrawRewardsCmd(),
NewWithdrawCommission(),
NewWithdrawAllRewardsCmd(),
NewSetWithdrawAddrCmd(),
NewFundCommunityPoolCmd(),
Expand Down Expand Up @@ -76,20 +76,16 @@ func newSplitAndApply(

// NewWithdrawRewardsCmd returns a CLI command handler for creating a MsgWithdrawDelegatorReward transaction.
func NewWithdrawRewardsCmd() *cobra.Command {
// bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix()

cmd := &cobra.Command{
Use: "withdraw-rewards [validator-addr]",
Short: "Withdraw rewards from a given delegation address, and optionally withdraw validator commission if the delegation address given is a validator operator",
Short: "Withdraw rewards from a given delegation address",
Long: strings.TrimSpace(
fmt.Sprintf(`Withdraw rewards from a given delegation address,
and optionally withdraw validator commission if the delegation address given is a validator operator.
fmt.Sprintf(`Withdraw rewards from a given delegation address.
Example:
$ %s tx distribution withdraw-rewards 0x91D7d.. --from mykey
$ %s tx distribution withdraw-rewards 0x91D7d.. --from mykey --commission
`,
version.AppName, version.AppName,
version.AppName,
),
),
Args: cobra.ExactArgs(1),
Expand All @@ -106,15 +102,46 @@ $ %s tx distribution withdraw-rewards 0x91D7d.. --from mykey --commission

msgs := []sdk.Msg{types.NewMsgWithdrawDelegatorReward(delAddr, valAddr)}

if commission, _ := cmd.Flags().GetBool(FlagCommission); commission {
msgs = append(msgs, types.NewMsgWithdrawValidatorCommission(valAddr))
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msgs...)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}

// NewWithdrawCommission returns a CLI command handler for creating a MsgWithdrawValidatorCommission transaction.
func NewWithdrawCommission() *cobra.Command {
cmd := &cobra.Command{
Use: "withdraw-commission [validator-addr]",
Short: "Withdraw validator commission",
Long: strings.TrimSpace(
fmt.Sprintf(`Withdraw validator commission if the delegation address given is a validator operator.
Example:
$ %s tx distribution withdraw-commission 0x91D7d.. --from mykey
`,
version.AppName,
),
),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
valAddr, err := sdk.AccAddressFromHexUnsafe(args[0])
if err != nil {
return err
}

msgs := []sdk.Msg{types.NewMsgWithdrawValidatorCommission(valAddr)}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msgs...)
},
}

cmd.Flags().Bool(FlagCommission, false, "Withdraw the validator's commission in addition to the rewards")
flags.AddTxFlagsToCmd(cmd)

return cmd
Expand Down
22 changes: 22 additions & 0 deletions x/distribution/client/testutil/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,25 @@ func MsgWithdrawDelegatorRewardExec(clientCtx client.Context, valAddr fmt.String

return buf.Bytes(), nil
}

func MsgWithdrawCommissionExec(clientCtx client.Context, valAddr fmt.Stringer, extraArgs ...string) ([]byte, error) {
buf := new(bytes.Buffer)
clientCtx = clientCtx.WithOutput(buf)

ctx := context.Background()
ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)

args := []string{valAddr.String()}
args = append(args, extraArgs...)

cmd := distrcli.NewWithdrawCommission()
cmd.SetErr(buf)
cmd.SetOut(buf)
cmd.SetArgs(args)

if err := cmd.ExecuteContext(ctx); err != nil {
return nil, err
}

return buf.Bytes(), nil
}
69 changes: 56 additions & 13 deletions x/distribution/client/testutil/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,19 +489,70 @@ func (s *IntegrationTestSuite) TestNewWithdrawRewardsCmd() {
"/cosmos.distribution.v1beta1.MsgWithdrawDelegatorRewardResponse",
},
},
}

for _, tc := range testCases {
tc := tc

s.Run(tc.name, func() {
clientCtx := val.ClientCtx

_, _ = s.network.WaitForHeightWithTimeout(10, time.Minute)
bz, err := MsgWithdrawDelegatorRewardExec(clientCtx, tc.valAddr, tc.args...)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz, tc.respType), string(bz))

txResp := tc.respType.(*sdk.TxResponse)
s.Require().Equal(tc.expectedCode, txResp.Code)

data, err := hex.DecodeString(txResp.Data)
s.Require().NoError(err)

txMsgData := sdk.TxMsgData{}
err = s.cfg.Codec.Unmarshal(data, &txMsgData)
s.Require().NoError(err)
for responseIdx, msgResponse := range txMsgData.MsgResponses {
s.Require().Equal(tc.expectedResponseType[responseIdx], msgResponse.TypeUrl)
if msgResponse.TypeUrl == "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorRewardResponse" {
var resp distrtypes.MsgWithdrawDelegatorRewardResponse
// can't use unpackAny as response types are not registered.
err = s.cfg.Codec.Unmarshal(msgResponse.Value, &resp)
s.Require().NoError(err)
s.Require().True(resp.Amount.IsAllGT(sdk.NewCoins(sdk.NewCoin("stake", sdk.OneInt()))),
fmt.Sprintf("expected a positive coin value, got %v", resp.Amount))
}
}
}
})
}
}

func (s *IntegrationTestSuite) TestNewWithdrawCommissionCmd() {
val := s.network.Validators[0]

testCases := []struct {
name string
valAddr fmt.Stringer
args []string
expectErr bool
expectedCode uint32
respType proto.Message
expectedResponseType []string
}{
{
"valid transaction (with commission)",
"valid transaction",
val.Address,
[]string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=true", cli.FlagCommission),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
false, 0, &sdk.TxResponse{},
[]string{
"/cosmos.distribution.v1beta1.MsgWithdrawDelegatorRewardResponse",
"/cosmos.distribution.v1beta1.MsgWithdrawValidatorCommissionResponse",
},
},
Expand All @@ -514,7 +565,7 @@ func (s *IntegrationTestSuite) TestNewWithdrawRewardsCmd() {
clientCtx := val.ClientCtx

_, _ = s.network.WaitForHeightWithTimeout(10, time.Minute)
bz, err := MsgWithdrawDelegatorRewardExec(clientCtx, tc.valAddr, tc.args...)
bz, err := MsgWithdrawCommissionExec(clientCtx, tc.valAddr, tc.args...)
if tc.expectErr {
s.Require().Error(err)
} else {
Expand All @@ -532,15 +583,7 @@ func (s *IntegrationTestSuite) TestNewWithdrawRewardsCmd() {
s.Require().NoError(err)
for responseIdx, msgResponse := range txMsgData.MsgResponses {
s.Require().Equal(tc.expectedResponseType[responseIdx], msgResponse.TypeUrl)
switch msgResponse.TypeUrl {
case "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorRewardResponse":
var resp distrtypes.MsgWithdrawDelegatorRewardResponse
// can't use unpackAny as response types are not registered.
err = s.cfg.Codec.Unmarshal(msgResponse.Value, &resp)
s.Require().NoError(err)
s.Require().True(resp.Amount.IsAllGT(sdk.NewCoins(sdk.NewCoin("stake", sdk.OneInt()))),
fmt.Sprintf("expected a positive coin value, got %v", resp.Amount))
case "/cosmos.distribution.v1beta1.MsgWithdrawValidatorCommissionResponse":
if msgResponse.TypeUrl == "/cosmos.distribution.v1beta1.MsgWithdrawValidatorCommissionResponse" {
var resp distrtypes.MsgWithdrawValidatorCommissionResponse
// can't use unpackAny as response types are not registered.
err = s.cfg.Codec.Unmarshal(msgResponse.Value, &resp)
Expand Down

0 comments on commit e694aed

Please sign in to comment.