Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create Vesting Account Message #7209

Merged
merged 36 commits into from
Sep 8, 2020
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
8afbeda
init commit
alexanderbez Aug 31, 2020
923c844
Merge branch 'master' into bez/4287-create-vesting-acc-msg
alexanderbez Aug 31, 2020
a9d99b2
lint++
alexanderbez Aug 31, 2020
4796f5b
updates
alexanderbez Sep 1, 2020
060adee
implement vesting app module
alexanderbez Sep 2, 2020
5106648
move file
alexanderbez Sep 2, 2020
3c3d96b
undo
alexanderbez Sep 2, 2020
ef094f9
undo
alexanderbez Sep 2, 2020
48467ba
lint++
alexanderbez Sep 2, 2020
b7d23b6
undo
alexanderbez Sep 2, 2020
143932a
undo
alexanderbez Sep 2, 2020
076067d
undo
alexanderbez Sep 2, 2020
7c6207a
update simapp
alexanderbez Sep 2, 2020
544de23
add vesting root cmd to simapp
alexanderbez Sep 2, 2020
cb9fc0e
update module
alexanderbez Sep 2, 2020
72c9eb1
add msg to registry
alexanderbez Sep 2, 2020
99a5708
add tx cmd
alexanderbez Sep 2, 2020
e0f6d10
add handler tests
alexanderbez Sep 3, 2020
c5417c5
add CLI tests
alexanderbez Sep 3, 2020
b386ef8
cl++
alexanderbez Sep 3, 2020
603b4f5
Merge branch 'master' into bez/4287-create-vesting-acc-msg
alexanderbez Sep 3, 2020
d34ef20
move checks
alexanderbez Sep 3, 2020
599beb7
Merge branch 'bez/4287-create-vesting-acc-msg' of github.com:cosmos/c…
alexanderbez Sep 3, 2020
90bd67e
Merge branch 'master' into bez/4287-create-vesting-acc-msg
alexanderbez Sep 3, 2020
ecd836f
Merge branch 'master' into bez/4287-create-vesting-acc-msg
alexanderbez Sep 4, 2020
b9af229
move checks
alexanderbez Sep 4, 2020
e72918d
Merge branch 'bez/4287-create-vesting-acc-msg' of github.com:cosmos/c…
alexanderbez Sep 4, 2020
13d17b5
Merge branch 'master' into bez/4287-create-vesting-acc-msg
alexanderbez Sep 4, 2020
a737f4f
Merge branch 'master' into bez/4287-create-vesting-acc-msg
cwgoes Sep 5, 2020
8088adb
Merge branch 'master' into bez/4287-create-vesting-acc-msg
cwgoes Sep 7, 2020
1c542eb
Merge branch 'master' into bez/4287-create-vesting-acc-msg
alexanderbez Sep 7, 2020
dd77ed4
fix build
alexanderbez Sep 7, 2020
ecdfa7d
attempt sim fix
alexanderbez Sep 7, 2020
5dbe622
Merge branch 'master' into bez/4287-create-vesting-acc-msg
cwgoes Sep 8, 2020
0232cc8
revert DRY changes
alexanderbez Sep 8, 2020
24d8c0c
Merge branch 'master' into bez/4287-create-vesting-acc-msg
alexanderbez Sep 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,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;
}
2 changes: 2 additions & 0 deletions 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 @@ -299,6 +300,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
2 changes: 2 additions & 0 deletions simapp/simd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,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 @@ -148,6 +149,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
}
78 changes: 78 additions & 0 deletions x/auth/vesting/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package vesting

import (
"github.com/armon/go-metrics"

"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/keeper"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
)

// NewHandler returns a handler for x/auth message types.
func NewHandler(ak keeper.AccountKeeper, bk types.BankKeeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())

switch msg := msg.(type) {
case *types.MsgCreateVestingAccount:
return handleMsgCreateVestingAccount(ctx, ak, bk, msg)

default:
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", types.ModuleName, msg)
}
}
}

func handleMsgCreateVestingAccount(ctx sdk.Context, ak keeper.AccountKeeper, bk types.BankKeeper, msg *types.MsgCreateVestingAccount) (*sdk.Result, error) {
if acc := ak.GetAccount(ctx, msg.ToAddress); acc != nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "account %s already exists", msg.ToAddress)
}

baseAccount := ak.NewAccountWithAddress(ctx, msg.ToAddress)
if _, ok := baseAccount.(*authtypes.BaseAccount); !ok {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid account type; expected: BaseAccount, got: %T", baseAccount)
}

baseVestingAccount := types.NewBaseVestingAccount(baseAccount.(*authtypes.BaseAccount), msg.Amount.Sort(), msg.EndTime)

var acc authtypes.AccountI

if msg.Delayed {
acc = types.NewDelayedVestingAccountRaw(baseVestingAccount)
} else {
acc = types.NewContinuousVestingAccountRaw(baseVestingAccount, ctx.BlockTime().Unix())
}

ak.SetAccount(ctx, acc)

defer func() {
telemetry.IncrCounter(1, "new", "account")

for _, a := range msg.Amount {
if a.Amount.IsInt64() {
telemetry.SetGaugeWithLabels(
[]string{"tx", "msg", "create_vesting_account"},
float32(a.Amount.Int64()),
[]metrics.Label{telemetry.NewLabel("denom", a.Denom)},
)
}
}
}()

err := bk.SendCoins(ctx, msg.FromAddress, msg.ToAddress, msg.Amount)
if err != nil {
return nil, err
}

ctx.EventManager().EmitEvent(
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
),
)

return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil
}
Loading