diff --git a/proto/cosmos/vesting/v1beta1/tx.proto b/proto/cosmos/vesting/v1beta1/tx.proto index 732fe12536b2..128d38ad03f3 100644 --- a/proto/cosmos/vesting/v1beta1/tx.proto +++ b/proto/cosmos/vesting/v1beta1/tx.proto @@ -42,6 +42,8 @@ message MsgCreateVestingAccount { // end of vesting as unix time (in seconds). int64 end_time = 4; bool delayed = 5; + // start of vesting as unix time (in seconds). + int64 start_time = 6; } // MsgCreateVestingAccountResponse defines the Msg/CreateVestingAccount response type. diff --git a/x/auth/spec/07_client.md b/x/auth/spec/07_client.md index bcfdc6f6faee..cbc518b770cc 100644 --- a/x/auth/spec/07_client.md +++ b/x/auth/spec/07_client.md @@ -408,7 +408,7 @@ simd tx vesting create-periodic-vesting-account cosmos1.. periods.json #### create-vesting-account -The `create-vesting-account` command creates 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. +The `create-vesting-account` command creates 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 accounts created will have their start time set by the committed block's time unless specified explicitly using the `--start-time`flag. The `end_time` must be provided as a UNIX epoch timestamp. ```bash simd tx vesting create-vesting-account [to_address] [amount] [end_time] [flags] diff --git a/x/auth/vesting/client/cli/tx.go b/x/auth/vesting/client/cli/tx.go index f2ef3ba67fe7..72dd455f59e1 100644 --- a/x/auth/vesting/client/cli/tx.go +++ b/x/auth/vesting/client/cli/tx.go @@ -17,7 +17,8 @@ import ( // Transaction command flags const ( - FlagDelayed = "delayed" + FlagDelayed = "delayed" + FlagStartTime = "start-time" ) // GetTxCmd returns vesting module's transaction commands. @@ -72,14 +73,18 @@ timestamp.`, } delayed, _ := cmd.Flags().GetBool(FlagDelayed) + startTime, err := cmd.Flags().GetInt64(FlagStartTime) + if err != nil { + return err + } - msg := types.NewMsgCreateVestingAccount(clientCtx.GetFromAddress(), toAddr, amount, endTime, delayed) - + msg := types.NewMsgCreateVestingAccount(clientCtx.GetFromAddress(), toAddr, amount, startTime, endTime, delayed) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } cmd.Flags().Bool(FlagDelayed, false, "Create a delayed vesting account if true") + cmd.Flags().Int64(FlagStartTime, 0, "Optional start time (as a UNIX epoch timestamp) for continuous vesting accounts. If 0 (default), the block's time of the block this tx is committed to will be used.") flags.AddTxFlagsToCmd(cmd) return cmd diff --git a/x/auth/vesting/client/testutil/suite.go b/x/auth/vesting/client/testutil/suite.go index 7f56de2c1cc2..829a0a8ba35a 100644 --- a/x/auth/vesting/client/testutil/suite.go +++ b/x/auth/vesting/client/testutil/suite.go @@ -63,6 +63,21 @@ func (s *IntegrationTestSuite) TestNewMsgCreateVestingAccountCmd() { expectedCode: 0, respType: &sdk.TxResponse{}, }, + "create a continuous vesting account with start time": { + args: []string{ + sdk.AccAddress("addr2_______________").String(), + sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String(), + "4070908800", + fmt.Sprintf("--%s=%d", cli.FlagStartTime, 4070808800), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }, + expectErr: false, + expectedCode: 0, + respType: &sdk.TxResponse{}, + }, "create a delayed vesting account": { args: []string{ sdk.AccAddress("addr3_______________").String(), diff --git a/x/auth/vesting/msg_server.go b/x/auth/vesting/msg_server.go index c3dd5785163d..1d52a4f5d25a 100644 --- a/x/auth/vesting/msg_server.go +++ b/x/auth/vesting/msg_server.go @@ -44,6 +44,14 @@ func (s msgServer) CreateVestingAccount(goCtx context.Context, msg *types.MsgCre return nil, err } + if msg.EndTime <= 0 { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid end time") + } + + if msg.EndTime <= msg.StartTime { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid start and end time (must be start < end)") + } + if bk.BlockedAddr(to) { return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", msg.ToAddress) } @@ -60,7 +68,11 @@ func (s msgServer) CreateVestingAccount(goCtx context.Context, msg *types.MsgCre if msg.Delayed { vestingAccount = types.NewDelayedVestingAccountRaw(baseVestingAccount) } else { - vestingAccount = types.NewContinuousVestingAccountRaw(baseVestingAccount, ctx.BlockTime().Unix()) + start := ctx.BlockTime().Unix() + if msg.StartTime != 0 { + start = msg.StartTime + } + vestingAccount = types.NewContinuousVestingAccountRaw(baseVestingAccount, start) } ak.SetAccount(ctx, vestingAccount) diff --git a/x/auth/vesting/types/msgs.go b/x/auth/vesting/types/msgs.go index f2194af5690b..20e37fe1734e 100644 --- a/x/auth/vesting/types/msgs.go +++ b/x/auth/vesting/types/msgs.go @@ -25,11 +25,12 @@ var _ sdk.Msg = &MsgCreatePeriodicVestingAccount{} // NewMsgCreateVestingAccount returns a reference to a new MsgCreateVestingAccount. // //nolint:interfacer -func NewMsgCreateVestingAccount(fromAddr, toAddr sdk.AccAddress, amount sdk.Coins, endTime int64, delayed bool) *MsgCreateVestingAccount { +func NewMsgCreateVestingAccount(fromAddr, toAddr sdk.AccAddress, amount sdk.Coins, startTime, endTime int64, delayed bool) *MsgCreateVestingAccount { return &MsgCreateVestingAccount{ FromAddress: fromAddr.String(), ToAddress: toAddr.String(), Amount: amount, + StartTime: startTime, EndTime: endTime, Delayed: delayed, } diff --git a/x/auth/vesting/types/tx.pb.go b/x/auth/vesting/types/tx.pb.go index 0165ea83312e..8fe34a78dfde 100644 --- a/x/auth/vesting/types/tx.pb.go +++ b/x/auth/vesting/types/tx.pb.go @@ -41,6 +41,8 @@ type MsgCreateVestingAccount struct { // end of vesting as unix time (in seconds). EndTime int64 `protobuf:"varint,4,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"` Delayed bool `protobuf:"varint,5,opt,name=delayed,proto3" json:"delayed,omitempty"` + // start of vesting as unix time (in seconds). + StartTime int64 `protobuf:"varint,6,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` } func (m *MsgCreateVestingAccount) Reset() { *m = MsgCreateVestingAccount{} } @@ -111,6 +113,13 @@ func (m *MsgCreateVestingAccount) GetDelayed() bool { return false } +func (m *MsgCreateVestingAccount) GetStartTime() int64 { + if m != nil { + return m.StartTime + } + return 0 +} + // MsgCreateVestingAccountResponse defines the Msg/CreateVestingAccount response type. type MsgCreateVestingAccountResponse struct { } @@ -380,46 +389,46 @@ func init() { func init() { proto.RegisterFile("cosmos/vesting/v1beta1/tx.proto", fileDescriptor_5338ca97811f9792) } var fileDescriptor_5338ca97811f9792 = []byte{ - // 609 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x94, 0xb1, 0x6f, 0xd3, 0x40, - 0x14, 0xc6, 0x73, 0x75, 0x68, 0x9b, 0x2b, 0x02, 0x61, 0x52, 0xe2, 0x44, 0xd4, 0x4e, 0x2d, 0x24, - 0x0c, 0x52, 0x6d, 0x52, 0x90, 0x2a, 0x85, 0x01, 0x35, 0x1d, 0x21, 0x12, 0x32, 0x88, 0x81, 0x25, - 0x72, 0xec, 0xc3, 0xb5, 0x5a, 0xfb, 0x22, 0xdf, 0xa5, 0x6a, 0x36, 0xc4, 0x5f, 0xc0, 0xc8, 0xc8, - 0xcc, 0xc4, 0xc0, 0x8c, 0x18, 0x3b, 0x56, 0x4c, 0x4c, 0x01, 0x25, 0x03, 0x9d, 0xfb, 0x07, 0x20, - 0x64, 0xdf, 0x39, 0x34, 0xe9, 0x25, 0x29, 0x0c, 0x4c, 0x4e, 0xee, 0x7d, 0xdf, 0xdd, 0xbb, 0x9f, - 0xbf, 0x67, 0xa8, 0xb9, 0x98, 0x84, 0x98, 0x58, 0x07, 0x88, 0xd0, 0x20, 0xf2, 0xad, 0x83, 0x5a, - 0x1b, 0x51, 0xa7, 0x66, 0xd1, 0x43, 0xb3, 0x13, 0x63, 0x8a, 0xe5, 0x1b, 0x4c, 0x60, 0x72, 0x81, - 0xc9, 0x05, 0x95, 0xa2, 0x8f, 0x7d, 0x9c, 0x4a, 0xac, 0xe4, 0x17, 0x53, 0x57, 0x54, 0xbe, 0x5d, - 0xdb, 0x21, 0x68, 0xb4, 0x97, 0x8b, 0x83, 0x88, 0xd7, 0xcb, 0xac, 0xde, 0x62, 0x46, 0xbe, 0x35, - 0x2b, 0xdd, 0x9a, 0xd2, 0x49, 0x76, 0x30, 0x53, 0x95, 0xb8, 0x2a, 0x24, 0x89, 0x22, 0x79, 0xb0, - 0x82, 0xfe, 0x65, 0x01, 0x96, 0x9a, 0xc4, 0xdf, 0x89, 0x91, 0x43, 0xd1, 0x0b, 0xe6, 0xd9, 0x76, - 0x5d, 0xdc, 0x8d, 0xa8, 0xfc, 0x10, 0x5e, 0x7e, 0x15, 0xe3, 0xb0, 0xe5, 0x78, 0x5e, 0x8c, 0x08, - 0x51, 0x40, 0x15, 0x18, 0x85, 0x86, 0xf2, 0xf5, 0xd3, 0x46, 0x91, 0xb7, 0xb0, 0xcd, 0x2a, 0xcf, - 0x68, 0x1c, 0x44, 0xbe, 0xbd, 0x92, 0xa8, 0xf9, 0x92, 0xbc, 0x05, 0x21, 0xc5, 0x23, 0xeb, 0xc2, - 0x1c, 0x6b, 0x81, 0xe2, 0xcc, 0xe8, 0xc2, 0x45, 0x27, 0x4c, 0xce, 0x57, 0xa4, 0xaa, 0x64, 0xac, - 0x6c, 0x96, 0x4d, 0xee, 0x48, 0xe0, 0x64, 0x1c, 0xcd, 0x1d, 0x1c, 0x44, 0x8d, 0x7b, 0x47, 0x7d, - 0x2d, 0xf7, 0xe1, 0xbb, 0x66, 0xf8, 0x01, 0xdd, 0xed, 0xb6, 0x4d, 0x17, 0x87, 0x1c, 0x0e, 0x7f, - 0x6c, 0x10, 0x6f, 0xcf, 0xa2, 0xbd, 0x0e, 0x22, 0xa9, 0x81, 0xd8, 0x7c, 0x6b, 0xb9, 0x0c, 0x97, - 0x51, 0xe4, 0xb5, 0x68, 0x10, 0x22, 0x25, 0x5f, 0x05, 0x86, 0x64, 0x2f, 0xa1, 0xc8, 0x7b, 0x1e, - 0x84, 0x48, 0x56, 0xe0, 0x92, 0x87, 0xf6, 0x9d, 0x1e, 0xf2, 0x94, 0x4b, 0x55, 0x60, 0x2c, 0xdb, - 0xd9, 0xdf, 0xfa, 0xea, 0xc9, 0x7b, 0x0d, 0xbc, 0xf9, 0xf9, 0xf1, 0xee, 0x18, 0x16, 0x7d, 0x1d, - 0x6a, 0x53, 0x08, 0xda, 0x88, 0x74, 0x70, 0x44, 0x90, 0xfe, 0x0b, 0x9c, 0xd1, 0x3c, 0x45, 0x71, - 0xe8, 0x44, 0x28, 0xa2, 0x4f, 0xb0, 0xbb, 0x87, 0xbc, 0x8c, 0x76, 0x5d, 0x48, 0xbb, 0x74, 0xda, - 0xd7, 0xae, 0xf7, 0x9c, 0x70, 0xbf, 0xae, 0x8f, 0x1d, 0x3a, 0x0e, 0xfb, 0x81, 0x00, 0xf6, 0xea, - 0x69, 0x5f, 0xbb, 0xc6, 0x9c, 0x7f, 0x6a, 0xfa, 0xff, 0x26, 0x5d, 0xcf, 0x27, 0xd0, 0xf4, 0x3b, - 0xf0, 0xf6, 0x9c, 0xfb, 0x8f, 0x58, 0x9d, 0x4c, 0xb0, 0x0a, 0xb0, 0x17, 0xb8, 0x13, 0xc9, 0x5c, - 0x17, 0xb1, 0x1a, 0x47, 0xb2, 0x76, 0x1e, 0xc9, 0xd9, 0xbb, 0xaf, 0x41, 0x48, 0xa8, 0x13, 0x53, - 0x16, 0x01, 0x29, 0x8d, 0x40, 0x21, 0x5d, 0x49, 0x43, 0xd0, 0x84, 0x57, 0xf9, 0x00, 0xb5, 0x3a, - 0x69, 0x0b, 0x44, 0xc9, 0xa7, 0x8c, 0x54, 0x53, 0x3c, 0xd8, 0x26, 0xeb, 0xb4, 0x91, 0x4f, 0x40, - 0xd9, 0x57, 0x78, 0x95, 0x2d, 0x92, 0x34, 0x39, 0xb9, 0xf3, 0xc9, 0x99, 0xa0, 0x22, 0xb8, 0x69, - 0x46, 0x65, 0xf3, 0xb3, 0x04, 0xa5, 0x26, 0xf1, 0xe5, 0xd7, 0x00, 0x16, 0x85, 0xc3, 0x6a, 0x4d, - 0x6b, 0x6c, 0x4a, 0x36, 0x2b, 0x5b, 0x7f, 0x69, 0xc8, 0x5a, 0x91, 0xdf, 0x01, 0x78, 0x73, 0x66, - 0x92, 0xe7, 0xef, 0x2c, 0x36, 0x56, 0x1e, 0xfd, 0xa3, 0x51, 0xdc, 0x9a, 0x28, 0x38, 0x17, 0x6a, - 0x4d, 0x60, 0xbc, 0x58, 0x6b, 0x33, 0x5e, 0x60, 0xe3, 0xf1, 0xd1, 0x40, 0x05, 0xc7, 0x03, 0x15, - 0xfc, 0x18, 0xa8, 0xe0, 0xed, 0x50, 0xcd, 0x1d, 0x0f, 0xd5, 0xdc, 0xb7, 0xa1, 0x9a, 0x7b, 0x59, - 0x9b, 0x39, 0x53, 0x87, 0x96, 0xd3, 0xa5, 0xbb, 0xa3, 0xcf, 0x7b, 0x3a, 0x62, 0xed, 0xc5, 0xf4, - 0xe3, 0x7d, 0xff, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3d, 0xa4, 0x06, 0x42, 0x87, 0x06, 0x00, - 0x00, + // 614 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x54, 0x31, 0x6f, 0xd3, 0x40, + 0x14, 0xce, 0xd5, 0xa1, 0x6d, 0xae, 0x08, 0x84, 0x49, 0x89, 0x13, 0x51, 0x3b, 0xb5, 0x90, 0x08, + 0x48, 0xb5, 0x49, 0x41, 0xaa, 0x14, 0x06, 0xd4, 0x74, 0x84, 0x48, 0xc8, 0x20, 0x06, 0x96, 0xc8, + 0xb1, 0x0f, 0xd7, 0x6a, 0xed, 0x8b, 0x7c, 0x97, 0xaa, 0xd9, 0x10, 0xbf, 0x80, 0x91, 0x91, 0x99, + 0x89, 0x81, 0x99, 0xb9, 0x63, 0xc5, 0xc4, 0x94, 0xa2, 0x64, 0xa0, 0x73, 0x7f, 0x00, 0x42, 0xf6, + 0x9d, 0x43, 0x9d, 0x5e, 0x92, 0xc2, 0xc0, 0x74, 0xf6, 0xbd, 0xef, 0x7b, 0xf7, 0xdd, 0xf7, 0xde, + 0x3b, 0xa8, 0x39, 0x98, 0x04, 0x98, 0x98, 0x07, 0x88, 0x50, 0x3f, 0xf4, 0xcc, 0x83, 0x7a, 0x07, + 0x51, 0xbb, 0x6e, 0xd2, 0x43, 0xa3, 0x1b, 0x61, 0x8a, 0xe5, 0x5b, 0x0c, 0x60, 0x70, 0x80, 0xc1, + 0x01, 0x95, 0xa2, 0x87, 0x3d, 0x9c, 0x40, 0xcc, 0xf8, 0x8b, 0xa1, 0x2b, 0x2a, 0x4f, 0xd7, 0xb1, + 0x09, 0x1a, 0xe7, 0x72, 0xb0, 0x1f, 0xf2, 0x78, 0x99, 0xc5, 0xdb, 0x8c, 0xc8, 0x53, 0xb3, 0xd0, + 0x9d, 0x29, 0x4a, 0xd2, 0x83, 0x19, 0xaa, 0xc4, 0x51, 0x01, 0x89, 0x11, 0xf1, 0xc2, 0x02, 0xfa, + 0xc9, 0x02, 0x2c, 0xb5, 0x88, 0xb7, 0x13, 0x21, 0x9b, 0xa2, 0x57, 0x8c, 0xb3, 0xed, 0x38, 0xb8, + 0x17, 0x52, 0xf9, 0x31, 0xbc, 0xfa, 0x26, 0xc2, 0x41, 0xdb, 0x76, 0xdd, 0x08, 0x11, 0xa2, 0x80, + 0x2a, 0xa8, 0x15, 0x9a, 0xca, 0xb7, 0x2f, 0x1b, 0x45, 0x2e, 0x61, 0x9b, 0x45, 0x5e, 0xd0, 0xc8, + 0x0f, 0x3d, 0x6b, 0x25, 0x46, 0xf3, 0x2d, 0x79, 0x0b, 0x42, 0x8a, 0xc7, 0xd4, 0x85, 0x39, 0xd4, + 0x02, 0xc5, 0x29, 0xd1, 0x81, 0x8b, 0x76, 0x10, 0x9f, 0xaf, 0x48, 0x55, 0xa9, 0xb6, 0xb2, 0x59, + 0x36, 0x38, 0x23, 0x36, 0x27, 0xf5, 0xd1, 0xd8, 0xc1, 0x7e, 0xd8, 0x7c, 0x70, 0x34, 0xd0, 0x72, + 0x9f, 0x4e, 0xb4, 0x9a, 0xe7, 0xd3, 0xdd, 0x5e, 0xc7, 0x70, 0x70, 0xc0, 0xcd, 0xe1, 0xcb, 0x06, + 0x71, 0xf7, 0x4c, 0xda, 0xef, 0x22, 0x92, 0x10, 0x88, 0xc5, 0x53, 0xcb, 0x65, 0xb8, 0x8c, 0x42, + 0xb7, 0x4d, 0xfd, 0x00, 0x29, 0xf9, 0x2a, 0xa8, 0x49, 0xd6, 0x12, 0x0a, 0xdd, 0x97, 0x7e, 0x80, + 0x64, 0x05, 0x2e, 0xb9, 0x68, 0xdf, 0xee, 0x23, 0x57, 0xb9, 0x52, 0x05, 0xb5, 0x65, 0x2b, 0xfd, + 0x95, 0xd7, 0x20, 0x24, 0xd4, 0x8e, 0x28, 0xa3, 0x2d, 0x26, 0xb4, 0x42, 0xb2, 0x13, 0x13, 0x1b, + 0xab, 0xa7, 0x1f, 0x35, 0xf0, 0xee, 0xe7, 0xe7, 0xfb, 0x19, 0xd7, 0xf4, 0x75, 0xa8, 0x4d, 0x31, + 0xd8, 0x42, 0xa4, 0x8b, 0x43, 0x82, 0xf4, 0x5f, 0xe0, 0x1c, 0xe6, 0x39, 0x8a, 0x02, 0x3b, 0x44, + 0x21, 0x7d, 0x86, 0x9d, 0x3d, 0xe4, 0xa6, 0xc5, 0x68, 0x08, 0x8b, 0x51, 0x3a, 0x1b, 0x68, 0x37, + 0xfb, 0x76, 0xb0, 0xdf, 0xd0, 0x33, 0x87, 0x66, 0x6b, 0xf1, 0x48, 0x50, 0x8b, 0xd5, 0xb3, 0x81, + 0x76, 0x83, 0x31, 0xff, 0xc4, 0xf4, 0xff, 0x5d, 0x88, 0x46, 0x3e, 0x36, 0x4d, 0xbf, 0x07, 0xef, + 0xce, 0xb9, 0xff, 0xd8, 0xab, 0xd3, 0x09, 0xaf, 0x7c, 0xec, 0xfa, 0xce, 0x44, 0xe3, 0xae, 0x8b, + 0xbc, 0xca, 0x5a, 0xb2, 0x76, 0xd1, 0x92, 0xf3, 0x77, 0xcf, 0x96, 0x5a, 0x9a, 0x28, 0xb5, 0xdc, + 0x82, 0xd7, 0xf9, 0x7c, 0xb5, 0xbb, 0x89, 0x04, 0xa2, 0xe4, 0x13, 0x8f, 0x54, 0x43, 0x3c, 0xf7, + 0x06, 0x53, 0xda, 0xcc, 0xc7, 0x46, 0x59, 0xd7, 0x78, 0x94, 0x6d, 0x92, 0xa4, 0x73, 0x72, 0x17, + 0x3b, 0x67, 0xc2, 0x15, 0xc1, 0x4d, 0x53, 0x57, 0x36, 0xbf, 0x4a, 0x50, 0x6a, 0x11, 0x4f, 0x7e, + 0x0b, 0x60, 0x51, 0x38, 0xcb, 0xe6, 0x34, 0x61, 0x53, 0x7a, 0xb3, 0xb2, 0xf5, 0x97, 0x84, 0x54, + 0x8a, 0xfc, 0x01, 0xc0, 0xdb, 0x33, 0x3b, 0x79, 0x7e, 0x66, 0x31, 0xb1, 0xf2, 0xe4, 0x1f, 0x89, + 0x62, 0x69, 0xa2, 0xc6, 0xb9, 0x94, 0x34, 0x01, 0xf1, 0x72, 0xd2, 0x66, 0x14, 0xb0, 0xf9, 0xf4, + 0x68, 0xa8, 0x82, 0xe3, 0xa1, 0x0a, 0x7e, 0x0c, 0x55, 0xf0, 0x7e, 0xa4, 0xe6, 0x8e, 0x47, 0x6a, + 0xee, 0xfb, 0x48, 0xcd, 0xbd, 0xae, 0xcf, 0x9c, 0xa9, 0x43, 0xd3, 0xee, 0xd1, 0xdd, 0xf1, 0xeb, + 0x9f, 0x8c, 0x58, 0x67, 0x31, 0x79, 0xdb, 0x1f, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xab, 0xdc, + 0x57, 0xe2, 0xa6, 0x06, 0x00, 0x00, } func (this *MsgCreateVestingAccount) Equal(that interface{}) bool { @@ -461,6 +470,9 @@ func (this *MsgCreateVestingAccount) Equal(that interface{}) bool { if this.Delayed != that1.Delayed { return false } + if this.StartTime != that1.StartTime { + return false + } return true } func (this *MsgCreatePermanentLockedAccount) Equal(that interface{}) bool { @@ -691,6 +703,11 @@ func (m *MsgCreateVestingAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l + if m.StartTime != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.StartTime)) + i-- + dAtA[i] = 0x30 + } if m.Delayed { i-- if m.Delayed { @@ -950,6 +967,9 @@ func (m *MsgCreateVestingAccount) Size() (n int) { if m.Delayed { n += 2 } + if m.StartTime != 0 { + n += 1 + sovTx(uint64(m.StartTime)) + } return n } @@ -1201,6 +1221,25 @@ func (m *MsgCreateVestingAccount) Unmarshal(dAtA []byte) error { } } m.Delayed = bool(v != 0) + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) + } + m.StartTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/x/auth/vesting/types/vesting_account_test.go b/x/auth/vesting/types/vesting_account_test.go index 56ae59b05b01..ca630182ee1f 100644 --- a/x/auth/vesting/types/vesting_account_test.go +++ b/x/auth/vesting/types/vesting_account_test.go @@ -38,67 +38,95 @@ func (s *VestingAccountTestSuite) SetupTest() { func TestGetVestedCoinsContVestingAcc(t *testing.T) { now := tmtime.Now() - endTime := now.Add(24 * time.Hour) + startTime := now.Add(24 * time.Hour) + endTime := startTime.Add(24 * time.Hour) bacc, origCoins := initBaseAccount() - cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + cva := types.NewContinuousVestingAccount(bacc, origCoins, startTime.Unix(), endTime.Unix()) - // require no coins vested in the very beginning of the vesting schedule + // require no coins vested _before_ the start time of the vesting schedule vestedCoins := cva.GetVestedCoins(now) require.Nil(t, vestedCoins) + // require no coins vested _before_ the very beginning of the vesting schedule + vestedCoins = cva.GetVestedCoins(startTime.Add(-1)) + require.Nil(t, vestedCoins) + // require all coins vested at the end of the vesting schedule vestedCoins = cva.GetVestedCoins(endTime) require.Equal(t, origCoins, vestedCoins) // require 50% of coins vested - vestedCoins = cva.GetVestedCoins(now.Add(12 * time.Hour)) + vestedCoins = cva.GetVestedCoins(startTime.Add(12 * time.Hour)) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, vestedCoins) + // require 75% of coins vested + vestedCoins = cva.GetVestedCoins(startTime.Add(18 * time.Hour)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 750), sdk.NewInt64Coin(stakeDenom, 75)}, vestedCoins) + // require 100% of coins vested - vestedCoins = cva.GetVestedCoins(now.Add(48 * time.Hour)) + vestedCoins = cva.GetVestedCoins(endTime) require.Equal(t, origCoins, vestedCoins) } func TestGetVestingCoinsContVestingAcc(t *testing.T) { now := tmtime.Now() - endTime := now.Add(24 * time.Hour) + startTime := now.Add(24 * time.Hour) + endTime := startTime.Add(24 * time.Hour) bacc, origCoins := initBaseAccount() - cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + cva := types.NewContinuousVestingAccount(bacc, origCoins, startTime.Unix(), endTime.Unix()) - // require all coins vesting in the beginning of the vesting schedule + // require all coins vesting before the start time of the vesting schedule vestingCoins := cva.GetVestingCoins(now) require.Equal(t, origCoins, vestingCoins) + // require all coins vesting right before the start time of the vesting schedule + vestingCoins = cva.GetVestingCoins(startTime.Add(-1)) + require.Equal(t, origCoins, vestingCoins) + // require no coins vesting at the end of the vesting schedule vestingCoins = cva.GetVestingCoins(endTime) require.Nil(t, vestingCoins) - // require 50% of coins vesting - vestingCoins = cva.GetVestingCoins(now.Add(12 * time.Hour)) + // require 50% of coins vesting in the middle between start and end time + vestingCoins = cva.GetVestingCoins(startTime.Add(12 * time.Hour)) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, vestingCoins) + + // require 25% of coins vesting after 3/4 of the time between start and end time has passed + vestingCoins = cva.GetVestingCoins(startTime.Add(18 * time.Hour)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}, vestingCoins) } func TestSpendableCoinsContVestingAcc(t *testing.T) { now := tmtime.Now() - endTime := now.Add(24 * time.Hour) + startTime := now.Add(24 * time.Hour) + endTime := startTime.Add(24 * time.Hour) bacc, origCoins := initBaseAccount() - cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + cva := types.NewContinuousVestingAccount(bacc, origCoins, startTime.Unix(), endTime.Unix()) - // require that all original coins are locked at the end of the vesting + // require that all original coins are locked before the beginning of the vesting // schedule lockedCoins := cva.LockedCoins(now) require.Equal(t, origCoins, lockedCoins) - // require that there exist no locked coins in the beginning of the + // require that all original coins are locked at the beginning of the vesting + // schedule + lockedCoins = cva.LockedCoins(startTime) + require.Equal(t, origCoins, lockedCoins) + + // require that there exist no locked coins in the end of the vesting schedule lockedCoins = cva.LockedCoins(endTime) require.Equal(t, sdk.NewCoins(), lockedCoins) // require that all vested coins (50%) are spendable - lockedCoins = cva.LockedCoins(now.Add(12 * time.Hour)) + lockedCoins = cva.LockedCoins(startTime.Add(12 * time.Hour)) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) + + // require 25% of coins vesting after 3/4 of the time between start and end time has passed + lockedCoins = cva.LockedCoins(startTime.Add(18 * time.Hour)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}, lockedCoins) } func TestTrackDelegationContVestingAcc(t *testing.T) {