Skip to content

Commit

Permalink
Merge PR #7209: Create Vesting Account Message
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez authored Sep 8, 2020
1 parent fcf5186 commit 325be6f
Show file tree
Hide file tree
Showing 19 changed files with 1,234 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ be used to retrieve the actual proposal `Content`. Also the `NewMsgSubmitProposa

### Features

* (vesting) [\#7209](https://github.com/cosmos/cosmos-sdk/pull/7209) Create new `MsgCreateVestingAccount` message type along with CLI handler that allows for the creation of delayed and continuous vesting types.
* (events) [\#7121](https://github.com/cosmos/cosmos-sdk/pull/7121) The application now drives what events are indexed by Tendermint via the `index-events` configuration in `app.toml`, which is a list of events taking the form `{eventType}.{attributeKey}`.
* [\#6089](https://github.com/cosmos/cosmos-sdk/pull/6089) Transactions can now have a `TimeoutHeight` set which allows the transaction to be rejected if it's committed at a height greater than the timeout.
* (tests) [\#6489](https://github.com/cosmos/cosmos-sdk/pull/6489) Introduce package `testutil`, new in-process testing network framework for use in integration and unit tests.
Expand Down
27 changes: 27 additions & 0 deletions proto/cosmos/vesting/v1beta1/tx.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
syntax = "proto3";
package cosmos.vesting.v1beta1;

import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/auth/vesting/types";

// MsgCreateVestingAccount defines a message that enables creating a vesting
// account.
message MsgCreateVestingAccount {
option (gogoproto.equal) = true;

bytes from_address = 1 [
(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress",
(gogoproto.moretags) = "yaml:\"from_address\""
];
bytes to_address = 2 [
(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress",
(gogoproto.moretags) = "yaml:\"to_address\""
];
repeated cosmos.base.v1beta1.Coin amount = 3
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];

int64 end_time = 4 [(gogoproto.moretags) = "yaml:\"end_time\""];
bool delayed = 5;
}
4 changes: 3 additions & 1 deletion simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
"github.com/cosmos/cosmos-sdk/x/bank"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
Expand Down Expand Up @@ -301,6 +302,7 @@ func NewSimApp(
encodingConfig.TxConfig,
),
auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts),
vesting.NewAppModule(app.AccountKeeper, app.BankKeeper),
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
crisis.NewAppModule(&app.CrisisKeeper),
Expand Down Expand Up @@ -332,7 +334,7 @@ func NewSimApp(
// so that other modules that want to create or claim capabilities afterwards in InitChain
// can do so safely.
app.mm.SetOrderInitGenesis(
capabilitytypes.ModuleName, authtypes.ModuleName, distrtypes.ModuleName, stakingtypes.ModuleName, banktypes.ModuleName,
capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName, stakingtypes.ModuleName,
slashingtypes.ModuleName, govtypes.ModuleName, minttypes.ModuleName, crisistypes.ModuleName,
ibchost.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, ibctransfertypes.ModuleName,
)
Expand Down
2 changes: 2 additions & 0 deletions simapp/simd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/cosmos/cosmos-sdk/x/auth/types"
vestingcli "github.com/cosmos/cosmos-sdk/x/auth/vesting/client/cli"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
)
Expand Down Expand Up @@ -150,6 +151,7 @@ func txCommand() *cobra.Command {
authcmd.GetEncodeCommand(),
authcmd.GetDecodeCommand(),
flags.LineBreak,
vestingcli.GetTxCmd(),
)

simapp.ModuleBasics.AddTxCommands(cmd)
Expand Down
3 changes: 3 additions & 0 deletions types/module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,13 @@ type AppModule interface {

// routes
Route() sdk.Route

// Deprecated: use RegisterQueryService
QuerierRoute() string

// Deprecated: use RegisterQueryService
LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier

// RegisterQueryService allows a module to register a gRPC query service
RegisterQueryService(grpc.Server)

Expand Down
137 changes: 137 additions & 0 deletions x/auth/vesting/client/cli/cli_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package cli_test

import (
"fmt"
"testing"

"github.com/gogo/protobuf/proto"
"github.com/stretchr/testify/suite"

"github.com/cosmos/cosmos-sdk/client/flags"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/vesting/client/cli"
)

type IntegrationTestSuite struct {
suite.Suite

cfg network.Config
network *network.Network
}

func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")

cfg := network.DefaultConfig()
cfg.NumValidators = 1

s.cfg = cfg
s.network = network.New(s.T(), cfg)

_, err := s.network.WaitForHeight(1)
s.Require().NoError(err)
}

func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
s.network.Cleanup()
}

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

testCases := map[string]struct {
args []string
expectErr bool
respType proto.Message
expectedCode uint32
}{
"create a continuous vesting account": {
args: []string{
sdk.AccAddress("addr2_______________").String(),
sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String(),
"4070908800",
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
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()),
},
expectErr: false,
respType: &sdk.TxResponse{},
expectedCode: 0,
},
"create a delayed vesting account": {
args: []string{
sdk.AccAddress("addr3_______________").String(),
sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String(),
"4070908800",
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
fmt.Sprintf("--%s=true", cli.FlagDelayed),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
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()),
},
expectErr: false,
respType: &sdk.TxResponse{},
expectedCode: 0,
},
"invalid address": {
args: []string{
sdk.AccAddress("addr4").String(),
sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String(),
"4070908800",
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
},
expectErr: true,
respType: &sdk.TxResponse{},
expectedCode: 0,
},
"invalid coins": {
args: []string{
sdk.AccAddress("addr4_______________").String(),
"fooo",
"4070908800",
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
},
expectErr: true,
respType: &sdk.TxResponse{},
expectedCode: 0,
},
"invalid end time": {
args: []string{
sdk.AccAddress("addr4_______________").String(),
sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String(),
"-4070908800",
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address),
},
expectErr: true,
respType: &sdk.TxResponse{},
expectedCode: 0,
},
}

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

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

bw, err := clitestutil.ExecTestCLICmd(clientCtx, cli.NewMsgCreateVestingAccountCmd(), tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(bw.Bytes(), tc.respType), bw.String())

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

func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}
86 changes: 86 additions & 0 deletions x/auth/vesting/client/cli/tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package cli

import (
"strconv"

"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
)

// Transaction command flags
const (
FlagDelayed = "delayed"
)

// GetTxCmd returns vesting module's transaction commands.
func GetTxCmd() *cobra.Command {
txCmd := &cobra.Command{
Use: types.ModuleName,
Short: "Vesting transaction subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

txCmd.AddCommand(
NewMsgCreateVestingAccountCmd(),
)

return txCmd
}

// NewMsgCreateVestingAccountCmd returns a CLI command handler for creating a
// MsgCreateVestingAccount transaction.
func NewMsgCreateVestingAccountCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create-vesting-account [to_address] [amount] [end_time]",
Short: "Create a new vesting account funded with an allocation of tokens.",
Long: `Create a new vesting account funded with an allocation of tokens. The
account can either be a delayed or continuous vesting account, which is determined
by the '--delayed' flag. All vesting accouts created will have their start time
set by the committed block's time. The end_time must be provided as a UNIX epoch
timestamp.`,
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}

toAddr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return err
}

amount, err := sdk.ParseCoins(args[1])
if err != nil {
return err
}

endTime, err := strconv.ParseInt(args[2], 10, 64)
if err != nil {
return err
}

delayed, _ := cmd.Flags().GetBool(FlagDelayed)

msg := types.NewMsgCreateVestingAccount(clientCtx.GetFromAddress(), toAddr, amount, endTime, delayed)
if err := msg.ValidateBasic(); err != nil {
return err
}

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

cmd.Flags().Bool(FlagDelayed, false, "Create a delayed vesting account if true")
flags.AddTxFlagsToCmd(cmd)

return cmd
}
Loading

0 comments on commit 325be6f

Please sign in to comment.