From 784f81bac99c58ce5223675a16347c56d450210c Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Thu, 16 May 2024 08:02:16 +0200 Subject: [PATCH 01/18] refactor(vesting): update proto according to vesting latest version --- proto/vesting/module/v1/module.proto | 12 +++ proto/vesting/v1beta1/tx.proto | 7 +- proto/vesting/v1beta1/vesting.proto | 13 ++- x/vesting/types/tx.pb.go | 104 +++++++++++------------ x/vesting/types/vesting.pb.go | 120 ++++++++++++++------------- 5 files changed, 139 insertions(+), 117 deletions(-) create mode 100644 proto/vesting/module/v1/module.proto diff --git a/proto/vesting/module/v1/module.proto b/proto/vesting/module/v1/module.proto new file mode 100644 index 000000000..088ae3a53 --- /dev/null +++ b/proto/vesting/module/v1/module.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +package vesting.module.v1; + +import "cosmos/app/v1alpha1/module.proto"; + +// Module is the config object of the vesting module. +message Module { + option (cosmos.app.v1alpha1.module) = { + go_import: "github.com/axone-protocol/axoned/x/vesting" + }; +} diff --git a/proto/vesting/v1beta1/tx.proto b/proto/vesting/v1beta1/tx.proto index 0cf73a547..d82d7ea35 100644 --- a/proto/vesting/v1beta1/tx.proto +++ b/proto/vesting/v1beta1/tx.proto @@ -46,11 +46,13 @@ message MsgCreateVestingAccount { repeated cosmos.base.v1beta1.Coin amount = 3 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true, + (amino.encoding) = "legacy_coins", (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; + // end of vesting as unix time (in seconds). int64 end_time = 4; - bool delayed = 6; + bool delayed = 5; } // MsgCreateVestingAccountResponse defines the Msg/CreateVestingAccount response type. @@ -70,6 +72,7 @@ message MsgCreatePermanentLockedAccount { repeated cosmos.base.v1beta1.Coin amount = 3 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true, + (amino.encoding) = "legacy_coins", (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; } @@ -85,7 +88,7 @@ message MsgCreatePermanentLockedAccountResponse {} // Since: cosmos-sdk 0.46 message MsgCreatePeriodicVestingAccount { option (cosmos.msg.v1.signer) = "from_address"; - option (amino.name) = "cosmos-sdk/MsgCreatePeriodicVestingAccount"; + option (amino.name) = "cosmos-sdk/MsgCreatePeriodVestAccount"; option (gogoproto.equal) = false; diff --git a/proto/vesting/v1beta1/vesting.proto b/proto/vesting/v1beta1/vesting.proto index 765c4d02f..b4c4ed5b7 100644 --- a/proto/vesting/v1beta1/vesting.proto +++ b/proto/vesting/v1beta1/vesting.proto @@ -14,22 +14,24 @@ option go_package = "github.com/axone-protocol/axoned/x/vesting/types"; message BaseVestingAccount { option (amino.name) = "cosmos-sdk/BaseVestingAccount"; option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; cosmos.auth.v1beta1.BaseAccount base_account = 1 [(gogoproto.embed) = true]; repeated cosmos.base.v1beta1.Coin original_vesting = 2 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true, + (amino.encoding) = "legacy_coins", (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; repeated cosmos.base.v1beta1.Coin delegated_free = 3 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true, + (amino.encoding) = "legacy_coins", (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; repeated cosmos.base.v1beta1.Coin delegated_vesting = 4 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true, + (amino.encoding) = "legacy_coins", (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; // Vesting end time, as unix timestamp (in seconds). @@ -41,7 +43,6 @@ message BaseVestingAccount { message ContinuousVestingAccount { option (amino.name) = "cosmos-sdk/ContinuousVestingAccount"; option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; BaseVestingAccount base_vesting_account = 1 [(gogoproto.embed) = true]; // Vesting start time, as unix timestamp (in seconds). @@ -54,19 +55,18 @@ message ContinuousVestingAccount { message DelayedVestingAccount { option (amino.name) = "cosmos-sdk/DelayedVestingAccount"; option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; BaseVestingAccount base_vesting_account = 1 [(gogoproto.embed) = true]; } // Period defines a length of time and amount of coins that will vest. message Period { - option (gogoproto.goproto_stringer) = false; - + // Period duration in seconds. int64 length = 1; repeated cosmos.base.v1beta1.Coin amount = 2 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true, + (amino.encoding) = "legacy_coins", (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; } @@ -76,7 +76,6 @@ message Period { message PeriodicVestingAccount { option (amino.name) = "cosmos-sdk/PeriodicVestingAccount"; option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; BaseVestingAccount base_vesting_account = 1 [(gogoproto.embed) = true]; int64 start_time = 2; @@ -94,7 +93,6 @@ message PeriodicVestingAccount { message PermanentLockedAccount { option (amino.name) = "cosmos-sdk/PermanentLockedAccount"; option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; BaseVestingAccount base_vesting_account = 1 [(gogoproto.embed) = true]; } @@ -104,7 +102,6 @@ message PermanentLockedAccount { message CliffVestingAccount { option (amino.name) = "cosmos-sdk/CliffVestingAccount"; option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; // base_vesting_account implements the VestingAccount interface. It contains // all the necessary fields needed for any vesting account implementation diff --git a/x/vesting/types/tx.pb.go b/x/vesting/types/tx.pb.go index 3ccee8038..19735cedb 100644 --- a/x/vesting/types/tx.pb.go +++ b/x/vesting/types/tx.pb.go @@ -39,8 +39,9 @@ type MsgCreateVestingAccount struct { FromAddress string `protobuf:"bytes,1,opt,name=from_address,json=fromAddress,proto3" json:"from_address,omitempty"` ToAddress string `protobuf:"bytes,2,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` - EndTime int64 `protobuf:"varint,4,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"` - Delayed bool `protobuf:"varint,6,opt,name=delayed,proto3" json:"delayed,omitempty"` + // 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"` } func (m *MsgCreateVestingAccount) Reset() { *m = MsgCreateVestingAccount{} } @@ -497,53 +498,54 @@ func init() { func init() { proto.RegisterFile("vesting/v1beta1/tx.proto", fileDescriptor_c66d8e2aee35e411) } var fileDescriptor_c66d8e2aee35e411 = []byte{ - // 728 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x96, 0x3d, 0x6c, 0xd3, 0x40, - 0x14, 0xc7, 0xe3, 0xa4, 0x5f, 0xb9, 0x22, 0x50, 0x4d, 0x51, 0x9c, 0xa8, 0xb1, 0x53, 0x0b, 0x68, - 0x88, 0x14, 0xbb, 0x2d, 0x54, 0xa0, 0x80, 0x84, 0x9a, 0x32, 0x01, 0x95, 0x50, 0x40, 0x0c, 0x2c, - 0x91, 0x63, 0x5f, 0x5d, 0xab, 0xb1, 0x2f, 0xf2, 0x5d, 0xab, 0x76, 0x03, 0xc6, 0x4e, 0x2c, 0xac, - 0xa8, 0x23, 0x62, 0xea, 0xc0, 0xcc, 0xdc, 0xb1, 0x62, 0x62, 0x2a, 0xa8, 0x1d, 0xda, 0x81, 0xa9, - 0x0b, 0x2b, 0xb2, 0xef, 0x1c, 0x92, 0xf4, 0xec, 0xd2, 0x09, 0x89, 0x25, 0xce, 0xdd, 0xff, 0xbd, - 0xbb, 0xe7, 0xdf, 0xfb, 0x90, 0x81, 0xb4, 0x01, 0x31, 0x71, 0x3c, 0x5b, 0xdf, 0x98, 0x6b, 0x41, - 0x62, 0xcc, 0xe9, 0x64, 0x53, 0xeb, 0xf8, 0x88, 0x20, 0xf1, 0x0a, 0x53, 0x34, 0xa6, 0x14, 0x26, - 0x0c, 0xd7, 0xf1, 0x90, 0x1e, 0xfe, 0x52, 0x9b, 0x82, 0x6c, 0x22, 0xec, 0x22, 0xac, 0xb7, 0x0c, - 0x0c, 0xbb, 0x27, 0x98, 0xc8, 0xf1, 0x98, 0x9e, 0x63, 0xba, 0x8b, 0x83, 0x0b, 0x82, 0x07, 0x13, - 0xf2, 0x54, 0x68, 0x86, 0x2b, 0x9d, 0x2e, 0x98, 0x34, 0x69, 0x23, 0x1b, 0xd1, 0xfd, 0xe0, 0x1f, - 0xdb, 0x2d, 0x0e, 0xc6, 0x19, 0x45, 0x17, 0xca, 0xea, 0xcf, 0x34, 0xc8, 0x2d, 0x63, 0x7b, 0xc9, - 0x87, 0x06, 0x81, 0x2f, 0xa9, 0xb4, 0x68, 0x9a, 0x68, 0xdd, 0x23, 0xe2, 0x7d, 0x70, 0x69, 0xc5, - 0x47, 0x6e, 0xd3, 0xb0, 0x2c, 0x1f, 0x62, 0x2c, 0x09, 0x25, 0xa1, 0x9c, 0xad, 0x4b, 0x5f, 0x3f, - 0x57, 0x27, 0xd9, 0xc5, 0x8b, 0x54, 0x79, 0x4e, 0x7c, 0xc7, 0xb3, 0x1b, 0xe3, 0x81, 0x35, 0xdb, - 0x12, 0xef, 0x02, 0x40, 0x50, 0xd7, 0x35, 0x7d, 0x8e, 0x6b, 0x96, 0xa0, 0xc8, 0x71, 0x15, 0x8c, - 0x18, 0x6e, 0x70, 0xbf, 0x94, 0x29, 0x65, 0xca, 0xe3, 0xf3, 0x79, 0x8d, 0x79, 0x04, 0xac, 0x22, - 0xa6, 0xda, 0x12, 0x72, 0xbc, 0xfa, 0xc2, 0xde, 0x81, 0x92, 0xfa, 0xf4, 0x5d, 0x29, 0xdb, 0x0e, - 0x59, 0x5d, 0x6f, 0x69, 0x26, 0x72, 0x19, 0x12, 0xf6, 0xa8, 0x62, 0x6b, 0x4d, 0x27, 0x5b, 0x1d, - 0x88, 0x43, 0x07, 0xfc, 0xf1, 0x78, 0xb7, 0x22, 0x34, 0xd8, 0xf9, 0x62, 0x1e, 0x8c, 0x41, 0xcf, - 0x6a, 0x12, 0xc7, 0x85, 0xd2, 0x50, 0x49, 0x28, 0x67, 0x1a, 0xa3, 0xd0, 0xb3, 0x5e, 0x38, 0x2e, - 0x14, 0x25, 0x30, 0x6a, 0xc1, 0xb6, 0xb1, 0x05, 0x2d, 0x69, 0xa4, 0x24, 0x94, 0xc7, 0x1a, 0xd1, - 0xb2, 0xf6, 0xe0, 0x64, 0x47, 0x11, 0xde, 0x1e, 0xef, 0x56, 0xfa, 0xd8, 0x6c, 0x1f, 0xef, 0x56, - 0xd4, 0x9e, 0x3b, 0x63, 0x90, 0xaa, 0xd3, 0x40, 0x89, 0x91, 0x1a, 0x10, 0x77, 0x90, 0x87, 0xa1, - 0xfa, 0x25, 0xdd, 0x63, 0xf3, 0x0c, 0xfa, 0xae, 0xe1, 0x41, 0x8f, 0x3c, 0x45, 0xe6, 0x1a, 0xb4, - 0xa2, 0xcc, 0xd4, 0xb8, 0x99, 0xc9, 0x9d, 0x1e, 0x28, 0x57, 0xb7, 0x0c, 0xb7, 0x5d, 0x53, 0x7b, - 0x55, 0xb5, 0x3f, 0x31, 0x77, 0x38, 0x89, 0xb9, 0x76, 0x7a, 0xa0, 0x4c, 0x50, 0xcf, 0x3f, 0x9a, - 0xfa, 0x4f, 0xb2, 0x52, 0x7b, 0x18, 0x0b, 0xf8, 0x06, 0x0f, 0x70, 0x40, 0xa8, 0x0f, 0x8e, 0x7a, - 0x0b, 0xcc, 0x9c, 0xc3, 0xaf, 0xcb, 0xfa, 0xfd, 0x00, 0x6b, 0x07, 0x59, 0x8e, 0x39, 0xd0, 0x05, - 0xd3, 0x3c, 0xd6, 0xfd, 0x48, 0x8b, 0x67, 0x91, 0xf6, 0xb2, 0x2b, 0x02, 0x80, 0x89, 0xe1, 0x13, - 0x5a, 0x69, 0x99, 0xb0, 0xd2, 0xb2, 0xe1, 0x4e, 0x58, 0x6b, 0x4f, 0x40, 0x34, 0x31, 0x9a, 0x9d, - 0x30, 0x04, 0x2c, 0x0d, 0x85, 0x8c, 0x73, 0xda, 0xc0, 0x24, 0xd1, 0x68, 0x88, 0xf5, 0x6c, 0x40, - 0x98, 0x52, 0xbb, 0xcc, 0x4c, 0xa8, 0x82, 0x6b, 0x8f, 0x4e, 0x76, 0x94, 0x14, 0x97, 0x5e, 0x25, - 0x86, 0x1e, 0xe7, 0x9d, 0x07, 0x11, 0x72, 0x4c, 0xba, 0x08, 0x7f, 0xa5, 0xc1, 0x54, 0xd7, 0x76, - 0xa9, 0xed, 0xac, 0xac, 0x0c, 0xf0, 0xfb, 0x8f, 0x6b, 0x35, 0x69, 0x82, 0x14, 0x01, 0x30, 0x03, - 0x1a, 0x54, 0x1c, 0xa6, 0x49, 0x0f, 0x77, 0x02, 0xb9, 0xb6, 0x18, 0x5b, 0xe5, 0x33, 0xbc, 0x3c, - 0x71, 0xc0, 0xaa, 0x37, 0xc1, 0xf5, 0x24, 0x3d, 0xca, 0xd0, 0xfc, 0x87, 0x21, 0x90, 0x59, 0xc6, - 0xb6, 0xe8, 0x83, 0x49, 0xee, 0x98, 0x2f, 0x9f, 0x29, 0xb3, 0x98, 0x11, 0x55, 0x98, 0xfd, 0x5b, - 0xcb, 0xe8, 0x6e, 0x71, 0x5b, 0x00, 0x53, 0x89, 0x93, 0x2c, 0xe1, 0x48, 0xbe, 0x47, 0xe1, 0xde, - 0x45, 0x3d, 0xf8, 0xc1, 0xf0, 0x5a, 0x3d, 0x39, 0x18, 0x8e, 0xc7, 0x39, 0xc1, 0x24, 0xf4, 0x8d, - 0xf8, 0x46, 0x00, 0xf9, 0xf8, 0xa6, 0xa9, 0xc6, 0x9f, 0xcb, 0x31, 0x2f, 0x2c, 0x5c, 0xc8, 0x3c, - 0x8a, 0xa1, 0x30, 0xfc, 0x3a, 0xa8, 0xe6, 0xfa, 0xe3, 0xbd, 0x43, 0x59, 0xd8, 0x3f, 0x94, 0x85, - 0x1f, 0x87, 0xb2, 0xf0, 0xee, 0x48, 0x4e, 0xed, 0x1f, 0xc9, 0xa9, 0x6f, 0x47, 0x72, 0xea, 0xd5, - 0x6c, 0x4f, 0x5b, 0x18, 0x9b, 0xc8, 0x83, 0xd5, 0xf0, 0xab, 0xc1, 0x44, 0x6d, 0xba, 0xb4, 0xf4, - 0xcd, 0xe8, 0x7b, 0x82, 0x36, 0x49, 0x6b, 0x24, 0x34, 0xb8, 0xfd, 0x3b, 0x00, 0x00, 0xff, 0xff, - 0x66, 0x5a, 0xdc, 0x17, 0x1f, 0x09, 0x00, 0x00, + // 748 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x96, 0xbd, 0x6f, 0xd3, 0x4e, + 0x18, 0xc7, 0xe3, 0xa4, 0x6f, 0xb9, 0x56, 0xbf, 0x9f, 0x6a, 0x8a, 0xe2, 0x44, 0x8d, 0x93, 0x5a, + 0x40, 0x43, 0xa5, 0xd8, 0x6d, 0xa1, 0x02, 0x05, 0x24, 0xd4, 0x54, 0x62, 0x00, 0x2a, 0xa1, 0x80, + 0x18, 0x58, 0x22, 0xc7, 0xbe, 0xba, 0x56, 0x63, 0x5f, 0xe4, 0xbb, 0x56, 0xcd, 0x06, 0x8c, 0x9d, + 0x3a, 0x33, 0x20, 0x46, 0xc4, 0xd4, 0x81, 0x3f, 0xa2, 0x1b, 0x15, 0x13, 0x53, 0x41, 0xed, 0x50, + 0xe6, 0x2e, 0x4c, 0x48, 0xe8, 0x7c, 0xe7, 0x90, 0xa6, 0xe7, 0xb4, 0x59, 0x10, 0x4b, 0x9c, 0xbb, + 0xef, 0xf3, 0xdc, 0x3d, 0xf9, 0x3c, 0x2f, 0x31, 0x50, 0xb6, 0x20, 0x26, 0xae, 0xef, 0x18, 0x5b, + 0x0b, 0x0d, 0x48, 0xcc, 0x05, 0x83, 0x6c, 0xeb, 0xad, 0x00, 0x11, 0x24, 0xff, 0xcf, 0x15, 0x9d, + 0x2b, 0xb9, 0x49, 0xd3, 0x73, 0x7d, 0x64, 0x84, 0x9f, 0xcc, 0x26, 0xa7, 0x5a, 0x08, 0x7b, 0x08, + 0x1b, 0x0d, 0x13, 0xc3, 0xce, 0x09, 0x16, 0x72, 0x7d, 0xae, 0x67, 0xb8, 0xee, 0x61, 0x7a, 0x01, + 0x7d, 0x70, 0x21, 0xcb, 0x84, 0x7a, 0xb8, 0x32, 0xd8, 0x82, 0x4b, 0x53, 0x0e, 0x72, 0x10, 0xdb, + 0xa7, 0xdf, 0xf8, 0x6e, 0xbe, 0x37, 0xce, 0x28, 0xba, 0x50, 0xd6, 0x7e, 0x25, 0x41, 0x66, 0x15, + 0x3b, 0x2b, 0x01, 0x34, 0x09, 0x7c, 0xc1, 0xa4, 0x65, 0xcb, 0x42, 0x9b, 0x3e, 0x91, 0xef, 0x81, + 0x89, 0xb5, 0x00, 0x79, 0x75, 0xd3, 0xb6, 0x03, 0x88, 0xb1, 0x22, 0x15, 0xa5, 0x52, 0xba, 0xaa, + 0x7c, 0xf9, 0x54, 0x9e, 0xe2, 0x17, 0x2f, 0x33, 0xe5, 0x19, 0x09, 0x5c, 0xdf, 0xa9, 0x8d, 0x53, + 0x6b, 0xbe, 0x25, 0xdf, 0x01, 0x80, 0xa0, 0x8e, 0x6b, 0xf2, 0x02, 0xd7, 0x34, 0x41, 0x91, 0x63, + 0x1b, 0x8c, 0x98, 0x1e, 0xbd, 0x5f, 0x49, 0x15, 0x53, 0xa5, 0xf1, 0xc5, 0xac, 0xce, 0x3d, 0x28, + 0xab, 0x88, 0xa9, 0xbe, 0x82, 0x5c, 0xbf, 0xfa, 0x70, 0xff, 0xb0, 0x90, 0xf8, 0xf8, 0xad, 0x50, + 0x72, 0x5c, 0xb2, 0xbe, 0xd9, 0xd0, 0x2d, 0xe4, 0x71, 0x24, 0xfc, 0x51, 0xc6, 0xf6, 0x86, 0x41, + 0xda, 0x2d, 0x88, 0x43, 0x07, 0xfc, 0xf6, 0x64, 0x6f, 0x6e, 0xa2, 0x09, 0x1d, 0xd3, 0x6a, 0xd7, + 0x29, 0x6d, 0xfc, 0xe1, 0x64, 0x6f, 0x4e, 0xaa, 0xf1, 0x0b, 0xe5, 0x2c, 0x18, 0x83, 0xbe, 0x5d, + 0x27, 0xae, 0x07, 0x95, 0xa1, 0xa2, 0x54, 0x4a, 0xd5, 0x46, 0xa1, 0x6f, 0x3f, 0x77, 0x3d, 0x28, + 0x2b, 0x60, 0xd4, 0x86, 0x4d, 0xb3, 0x0d, 0x6d, 0x65, 0xb8, 0x28, 0x95, 0xc6, 0x6a, 0xd1, 0xb2, + 0x72, 0xff, 0xc7, 0xfb, 0x82, 0xf4, 0x86, 0x1e, 0xdc, 0x0d, 0x6b, 0xe7, 0x64, 0x6f, 0x4e, 0xeb, + 0x0a, 0x22, 0x86, 0xb1, 0x36, 0x03, 0x0a, 0x31, 0x52, 0x0d, 0xe2, 0x16, 0xf2, 0x31, 0xd4, 0x3e, + 0x27, 0xbb, 0x6c, 0x9e, 0xc2, 0xc0, 0x33, 0x7d, 0xe8, 0x93, 0x27, 0xc8, 0xda, 0x80, 0x76, 0x94, + 0xaa, 0x8a, 0x30, 0x55, 0x99, 0xd3, 0xc3, 0xc2, 0x95, 0xb6, 0xe9, 0x35, 0x2b, 0x5a, 0xb7, 0xaa, + 0x9d, 0xcd, 0xd4, 0x6d, 0x41, 0xa6, 0xae, 0x9e, 0x1e, 0x16, 0x26, 0x99, 0xe7, 0x1f, 0x4d, 0xfb, + 0x37, 0xd2, 0x54, 0x79, 0x10, 0x4b, 0xfc, 0xba, 0x88, 0x38, 0x45, 0x76, 0x86, 0x96, 0x76, 0x13, + 0xcc, 0x5e, 0x00, 0xb4, 0x03, 0x7f, 0xb7, 0x07, 0xbe, 0x8b, 0x6c, 0xd7, 0xea, 0xe9, 0x93, 0x19, + 0x11, 0xfc, 0xb3, 0x8c, 0xf3, 0xe7, 0x19, 0x77, 0xc3, 0xcc, 0x03, 0x80, 0x89, 0x19, 0x10, 0x56, + 0x7a, 0xa9, 0xb0, 0xf4, 0xd2, 0xe1, 0x4e, 0x58, 0x7c, 0x8f, 0x41, 0x34, 0x53, 0xea, 0xad, 0x30, + 0x04, 0xac, 0x0c, 0x85, 0xd0, 0x33, 0x7a, 0xcf, 0xac, 0xd1, 0x59, 0x88, 0xd5, 0x34, 0x45, 0xce, + 0xa8, 0xfd, 0xc7, 0x4d, 0x98, 0x82, 0x43, 0x7a, 0x89, 0x81, 0xe8, 0xb9, 0xc8, 0xa6, 0xbf, 0x38, + 0x86, 0x9e, 0x80, 0x48, 0x87, 0xde, 0xcf, 0x24, 0x98, 0xee, 0xd8, 0xae, 0x34, 0xdd, 0xb5, 0xb5, + 0x1e, 0x74, 0x7f, 0xbf, 0x6e, 0xd7, 0x2f, 0x5f, 0xb7, 0x4b, 0x83, 0xd6, 0xed, 0xa5, 0xa7, 0x49, + 0x1e, 0x00, 0x8b, 0xd2, 0x60, 0xe2, 0x30, 0xcb, 0x77, 0xb8, 0x43, 0xe5, 0xca, 0x72, 0x6c, 0x81, + 0xcf, 0x8a, 0x52, 0x24, 0x00, 0xab, 0xdd, 0x00, 0xd7, 0xfa, 0xe9, 0x51, 0x86, 0x16, 0xdf, 0x0d, + 0x81, 0xd4, 0x2a, 0x76, 0xe4, 0x00, 0x4c, 0x09, 0xff, 0x03, 0x4a, 0xe7, 0x2a, 0x2c, 0x66, 0x5c, + 0xe5, 0xe6, 0x2f, 0x6b, 0x19, 0xdd, 0x2d, 0xef, 0x48, 0x60, 0xba, 0xef, 0x54, 0xeb, 0x73, 0xa4, + 0xd8, 0x23, 0x77, 0x77, 0x50, 0x0f, 0x71, 0x30, 0xa2, 0x2e, 0xef, 0x1f, 0x8c, 0xc0, 0xe3, 0x82, + 0x60, 0xfa, 0xf4, 0x8d, 0xfc, 0x5a, 0x02, 0xd9, 0xf8, 0xa6, 0x29, 0xc7, 0x9f, 0x2b, 0x30, 0xcf, + 0x2d, 0x0d, 0x64, 0x1e, 0xc5, 0x90, 0x1b, 0x7e, 0x45, 0xab, 0xb9, 0xfa, 0x68, 0xff, 0x48, 0x95, + 0x0e, 0x8e, 0x54, 0xe9, 0xfb, 0x91, 0x2a, 0xed, 0x1e, 0xab, 0x89, 0x83, 0x63, 0x35, 0xf1, 0xf5, + 0x58, 0x4d, 0xbc, 0x9c, 0xef, 0x6a, 0x0b, 0x73, 0x1b, 0xf9, 0xb0, 0x1c, 0xbe, 0x52, 0x58, 0xa8, + 0xc9, 0x96, 0xb6, 0xb1, 0x1d, 0xbd, 0x6c, 0xb0, 0x26, 0x69, 0x8c, 0x84, 0x06, 0xb7, 0x7e, 0x07, + 0x00, 0x00, 0xff, 0xff, 0xb9, 0x7d, 0x98, 0x73, 0x3c, 0x09, 0x00, 0x00, } func (this *MsgCreateVestingAccount) Equal(that interface{}) bool { @@ -904,7 +906,7 @@ func (m *MsgCreateVestingAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) dAtA[i] = 0 } i-- - dAtA[i] = 0x30 + dAtA[i] = 0x28 } if m.EndTime != 0 { i = encodeVarintTx(dAtA, i, uint64(m.EndTime)) @@ -1508,7 +1510,7 @@ func (m *MsgCreateVestingAccount) Unmarshal(dAtA []byte) error { break } } - case 6: + case 5: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field Delayed", wireType) } diff --git a/x/vesting/types/vesting.pb.go b/x/vesting/types/vesting.pb.go index c64b60843..959cb92fe 100644 --- a/x/vesting/types/vesting.pb.go +++ b/x/vesting/types/vesting.pb.go @@ -38,8 +38,9 @@ type BaseVestingAccount struct { EndTime int64 `protobuf:"varint,5,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"` } -func (m *BaseVestingAccount) Reset() { *m = BaseVestingAccount{} } -func (*BaseVestingAccount) ProtoMessage() {} +func (m *BaseVestingAccount) Reset() { *m = BaseVestingAccount{} } +func (m *BaseVestingAccount) String() string { return proto.CompactTextString(m) } +func (*BaseVestingAccount) ProtoMessage() {} func (*BaseVestingAccount) Descriptor() ([]byte, []int) { return fileDescriptor_eac461ec52018387, []int{0} } @@ -78,8 +79,9 @@ type ContinuousVestingAccount struct { StartTime int64 `protobuf:"varint,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` } -func (m *ContinuousVestingAccount) Reset() { *m = ContinuousVestingAccount{} } -func (*ContinuousVestingAccount) ProtoMessage() {} +func (m *ContinuousVestingAccount) Reset() { *m = ContinuousVestingAccount{} } +func (m *ContinuousVestingAccount) String() string { return proto.CompactTextString(m) } +func (*ContinuousVestingAccount) ProtoMessage() {} func (*ContinuousVestingAccount) Descriptor() ([]byte, []int) { return fileDescriptor_eac461ec52018387, []int{1} } @@ -117,8 +119,9 @@ type DelayedVestingAccount struct { *BaseVestingAccount `protobuf:"bytes,1,opt,name=base_vesting_account,json=baseVestingAccount,proto3,embedded=base_vesting_account" json:"base_vesting_account,omitempty"` } -func (m *DelayedVestingAccount) Reset() { *m = DelayedVestingAccount{} } -func (*DelayedVestingAccount) ProtoMessage() {} +func (m *DelayedVestingAccount) Reset() { *m = DelayedVestingAccount{} } +func (m *DelayedVestingAccount) String() string { return proto.CompactTextString(m) } +func (*DelayedVestingAccount) ProtoMessage() {} func (*DelayedVestingAccount) Descriptor() ([]byte, []int) { return fileDescriptor_eac461ec52018387, []int{2} } @@ -151,12 +154,14 @@ var xxx_messageInfo_DelayedVestingAccount proto.InternalMessageInfo // Period defines a length of time and amount of coins that will vest. type Period struct { + // Period duration in seconds. Length int64 `protobuf:"varint,1,opt,name=length,proto3" json:"length,omitempty"` Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` } -func (m *Period) Reset() { *m = Period{} } -func (*Period) ProtoMessage() {} +func (m *Period) Reset() { *m = Period{} } +func (m *Period) String() string { return proto.CompactTextString(m) } +func (*Period) ProtoMessage() {} func (*Period) Descriptor() ([]byte, []int) { return fileDescriptor_eac461ec52018387, []int{3} } @@ -209,8 +214,9 @@ type PeriodicVestingAccount struct { VestingPeriods []Period `protobuf:"bytes,3,rep,name=vesting_periods,json=vestingPeriods,proto3" json:"vesting_periods"` } -func (m *PeriodicVestingAccount) Reset() { *m = PeriodicVestingAccount{} } -func (*PeriodicVestingAccount) ProtoMessage() {} +func (m *PeriodicVestingAccount) Reset() { *m = PeriodicVestingAccount{} } +func (m *PeriodicVestingAccount) String() string { return proto.CompactTextString(m) } +func (*PeriodicVestingAccount) ProtoMessage() {} func (*PeriodicVestingAccount) Descriptor() ([]byte, []int) { return fileDescriptor_eac461ec52018387, []int{4} } @@ -250,8 +256,9 @@ type PermanentLockedAccount struct { *BaseVestingAccount `protobuf:"bytes,1,opt,name=base_vesting_account,json=baseVestingAccount,proto3,embedded=base_vesting_account" json:"base_vesting_account,omitempty"` } -func (m *PermanentLockedAccount) Reset() { *m = PermanentLockedAccount{} } -func (*PermanentLockedAccount) ProtoMessage() {} +func (m *PermanentLockedAccount) Reset() { *m = PermanentLockedAccount{} } +func (m *PermanentLockedAccount) String() string { return proto.CompactTextString(m) } +func (*PermanentLockedAccount) ProtoMessage() {} func (*PermanentLockedAccount) Descriptor() ([]byte, []int) { return fileDescriptor_eac461ec52018387, []int{5} } @@ -293,8 +300,9 @@ type CliffVestingAccount struct { CliffTime int64 `protobuf:"varint,3,opt,name=cliff_time,json=cliffTime,proto3" json:"cliff_time,omitempty"` } -func (m *CliffVestingAccount) Reset() { *m = CliffVestingAccount{} } -func (*CliffVestingAccount) ProtoMessage() {} +func (m *CliffVestingAccount) Reset() { *m = CliffVestingAccount{} } +func (m *CliffVestingAccount) String() string { return proto.CompactTextString(m) } +func (*CliffVestingAccount) ProtoMessage() {} func (*CliffVestingAccount) Descriptor() ([]byte, []int) { return fileDescriptor_eac461ec52018387, []int{6} } @@ -338,48 +346,48 @@ func init() { func init() { proto.RegisterFile("vesting/v1beta1/vesting.proto", fileDescriptor_eac461ec52018387) } var fileDescriptor_eac461ec52018387 = []byte{ - // 644 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0x3f, 0x6f, 0xd3, 0x4e, - 0x18, 0xf6, 0x35, 0xf9, 0xe5, 0x47, 0xaf, 0xd0, 0x3f, 0xa6, 0x94, 0xb4, 0x52, 0x9c, 0xe0, 0x2e, - 0x51, 0x51, 0xed, 0xb6, 0x88, 0x25, 0x1b, 0x29, 0x42, 0xe2, 0xcf, 0x80, 0x22, 0xc4, 0x00, 0x43, - 0x74, 0xb6, 0xaf, 0xce, 0xa9, 0xf6, 0x5d, 0xe5, 0xbb, 0x94, 0x56, 0x88, 0x1d, 0x31, 0x95, 0x0d, - 0x89, 0xa5, 0x12, 0x42, 0x42, 0x4c, 0xfd, 0x18, 0x1d, 0x3b, 0xb2, 0x50, 0x50, 0x3b, 0xf4, 0x6b, - 0x20, 0xdf, 0x9d, 0x5d, 0x2b, 0x29, 0x6c, 0xa9, 0xba, 0x24, 0x7e, 0xef, 0xbd, 0x7b, 0x9f, 0xe7, - 0x79, 0xfd, 0xbc, 0x3e, 0x58, 0xdb, 0xc6, 0x5c, 0x10, 0x1a, 0xba, 0xdb, 0xab, 0x1e, 0x16, 0x68, - 0xd5, 0xd5, 0xb1, 0xb3, 0x95, 0x30, 0xc1, 0xcc, 0xa9, 0x2c, 0xd4, 0xe9, 0x85, 0x19, 0x14, 0x13, - 0xca, 0x5c, 0xf9, 0xab, 0xf6, 0x2c, 0x58, 0x3e, 0xe3, 0x31, 0xe3, 0x2e, 0xea, 0x8b, 0x5e, 0x5e, - 0x26, 0x0d, 0x06, 0xf2, 0x1e, 0xe2, 0x38, 0xcf, 0xfb, 0x8c, 0x50, 0x9d, 0x9f, 0x0d, 0x59, 0xc8, - 0xe4, 0xa3, 0x9b, 0x3e, 0xa9, 0x55, 0xfb, 0x73, 0x19, 0x9a, 0x6d, 0xc4, 0xf1, 0x4b, 0x45, 0xe0, - 0x81, 0xef, 0xb3, 0x3e, 0x15, 0xe6, 0x63, 0x78, 0x3d, 0xad, 0xd3, 0x45, 0x2a, 0xae, 0x82, 0x06, - 0x68, 0x4e, 0xac, 0x35, 0x1c, 0x85, 0xe1, 0x48, 0x58, 0x8d, 0xe1, 0xa4, 0xc7, 0xf5, 0xb9, 0x76, - 0xf9, 0xe8, 0xb8, 0x0e, 0x3a, 0x13, 0xde, 0xf9, 0x92, 0xf9, 0x16, 0x4e, 0xb3, 0x84, 0x84, 0x84, - 0xa2, 0xa8, 0xab, 0x65, 0x56, 0xc7, 0x1a, 0xa5, 0xe6, 0xc4, 0xda, 0x7c, 0x56, 0x2e, 0xdd, 0x9e, - 0x97, 0x5b, 0x67, 0x84, 0xb6, 0xef, 0x1f, 0x1e, 0xd7, 0x8d, 0xef, 0xbf, 0xea, 0xcd, 0x90, 0x88, - 0x5e, 0xdf, 0x73, 0x7c, 0x16, 0xbb, 0x5a, 0x9f, 0xfa, 0x5b, 0xe6, 0xc1, 0xa6, 0x2b, 0x76, 0xb7, - 0x30, 0x97, 0x07, 0xf8, 0xb7, 0xb3, 0x83, 0x25, 0xd0, 0x99, 0xca, 0x90, 0xb4, 0x1c, 0xf3, 0x0d, - 0x9c, 0x0c, 0x70, 0x84, 0x43, 0x24, 0x70, 0xd0, 0xdd, 0x48, 0x30, 0xae, 0x96, 0x46, 0x04, 0x7d, - 0x23, 0xc7, 0x79, 0x94, 0x60, 0x6c, 0xbe, 0x83, 0x33, 0xe7, 0xc0, 0x99, 0xec, 0xf2, 0x88, 0xb0, - 0xa7, 0x73, 0xa8, 0x4c, 0xf7, 0x3c, 0xbc, 0x86, 0x69, 0xd0, 0x15, 0x24, 0xc6, 0xd5, 0xff, 0x1a, - 0xa0, 0x59, 0xea, 0xfc, 0x8f, 0x69, 0xf0, 0x82, 0xc4, 0xb8, 0xb5, 0xf4, 0x7e, 0xbf, 0x6e, 0x7c, - 0xda, 0xaf, 0x1b, 0x1f, 0xce, 0x0e, 0x96, 0x6a, 0x85, 0xb2, 0xc3, 0x36, 0xb0, 0x0f, 0x01, 0xac, - 0xae, 0x33, 0x2a, 0x08, 0xed, 0xb3, 0x3e, 0x1f, 0xf0, 0xc8, 0x6b, 0x38, 0x2b, 0x3d, 0xa2, 0xd5, - 0x0d, 0x78, 0x65, 0xd1, 0x19, 0xf0, 0xb4, 0x33, 0x5c, 0x5f, 0xdb, 0xc5, 0xf4, 0x86, 0x0d, 0x58, - 0x83, 0x90, 0x0b, 0x94, 0x08, 0x25, 0x61, 0x4c, 0x4a, 0x18, 0x97, 0x2b, 0x52, 0xc4, 0x4a, 0x51, - 0xc4, 0x62, 0x41, 0xc4, 0xdf, 0xd8, 0xda, 0x5f, 0x00, 0xbc, 0xf5, 0x10, 0x47, 0x68, 0x37, 0x6f, - 0xd2, 0x65, 0xe8, 0x68, 0x2d, 0x17, 0x89, 0x36, 0x0a, 0x44, 0x2f, 0xe4, 0x62, 0xef, 0x01, 0x58, - 0x79, 0x8e, 0x13, 0xc2, 0x02, 0x73, 0x0e, 0x56, 0x22, 0x4c, 0x43, 0xd1, 0x93, 0x44, 0x4a, 0x1d, - 0x1d, 0x99, 0x3d, 0x58, 0x41, 0xb1, 0x24, 0x38, 0xaa, 0x29, 0xd2, 0xf5, 0x5b, 0xe5, 0x94, 0xb7, - 0xfd, 0x71, 0x0c, 0xce, 0x29, 0x4a, 0xc4, 0xbf, 0x3a, 0x0e, 0x30, 0x9f, 0xc2, 0xec, 0xa3, 0xd9, - 0xdd, 0x92, 0xec, 0xb8, 0x1e, 0xed, 0xdb, 0x43, 0xb0, 0x8a, 0x7d, 0x7b, 0x3c, 0xed, 0x86, 0x52, - 0x38, 0xa9, 0xb7, 0xa8, 0x0c, 0x6f, 0x39, 0xc5, 0xb7, 0x74, 0xa7, 0xd0, 0x9b, 0x8b, 0x85, 0xdb, - 0x5f, 0x81, 0xec, 0x49, 0x8c, 0x28, 0xa6, 0xe2, 0x19, 0xf3, 0x37, 0x71, 0x70, 0x29, 0x6e, 0xfa, - 0x17, 0xcf, 0x0b, 0xc8, 0xd8, 0x3f, 0x01, 0xbc, 0xb9, 0x1e, 0x91, 0x8d, 0x8d, 0x2b, 0xf4, 0xe2, - 0x6a, 0x10, 0xfa, 0x29, 0x25, 0x95, 0x2e, 0xa9, 0xb4, 0x5c, 0x91, 0x93, 0x7d, 0xb7, 0x28, 0xd1, - 0x2a, 0x4e, 0xf6, 0xb0, 0x8e, 0xf6, 0x93, 0xc3, 0x13, 0x0b, 0x1c, 0x9d, 0x58, 0xe0, 0xf7, 0x89, - 0x05, 0xf6, 0x4e, 0x2d, 0xe3, 0xe8, 0xd4, 0x32, 0x7e, 0x9c, 0x5a, 0xc6, 0xab, 0x95, 0x82, 0xe5, - 0xd1, 0x0e, 0xa3, 0x78, 0x59, 0xde, 0x77, 0x3e, 0x8b, 0x54, 0x18, 0xb8, 0x3b, 0xd9, 0x1d, 0xac, - 0x06, 0xc0, 0xab, 0xc8, 0x0d, 0xf7, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x88, 0x61, 0xf1, 0x6e, - 0xab, 0x07, 0x00, 0x00, + // 648 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0xcf, 0x4f, 0xd4, 0x40, + 0x14, 0xde, 0x61, 0x71, 0x95, 0x01, 0xf9, 0x51, 0x11, 0x17, 0x92, 0xed, 0xae, 0x25, 0xd1, 0x75, + 0x23, 0xad, 0xe0, 0x8d, 0x9b, 0x8b, 0x21, 0xf1, 0xc7, 0xc1, 0x6c, 0x8c, 0x07, 0x3d, 0x34, 0xd3, + 0x76, 0x28, 0x13, 0xda, 0x19, 0xd2, 0x99, 0x25, 0xec, 0x7f, 0x40, 0x8c, 0x1a, 0xcf, 0x7a, 0x50, + 0x6f, 0xc6, 0x13, 0x7f, 0x84, 0x07, 0x2e, 0x26, 0x1c, 0xf5, 0x82, 0x06, 0x0e, 0xfc, 0x1b, 0xa6, + 0x33, 0xd3, 0xd2, 0xec, 0xc2, 0x75, 0xc3, 0x05, 0xfa, 0xe6, 0xbd, 0x79, 0xdf, 0xf7, 0xbd, 0x7e, + 0x6f, 0x0b, 0x6b, 0x3b, 0x98, 0x0b, 0x42, 0x43, 0x67, 0x67, 0xd9, 0xc3, 0x02, 0x2d, 0x3b, 0x3a, + 0xb6, 0xb7, 0x13, 0x26, 0x98, 0x31, 0x95, 0x85, 0x3a, 0xbd, 0x30, 0x83, 0x62, 0x42, 0x99, 0x23, + 0xff, 0xaa, 0x9a, 0x05, 0xd3, 0x67, 0x3c, 0x66, 0xdc, 0x41, 0x5d, 0xb1, 0x99, 0xb7, 0x49, 0x83, + 0xbe, 0xbc, 0x87, 0x38, 0xce, 0xf3, 0x3e, 0x23, 0x54, 0xe7, 0x67, 0x43, 0x16, 0x32, 0xf9, 0xe8, + 0xa4, 0x4f, 0xea, 0xd4, 0xfa, 0x35, 0x0a, 0x8d, 0x36, 0xe2, 0xf8, 0x95, 0x22, 0xf0, 0xc8, 0xf7, + 0x59, 0x97, 0x0a, 0xe3, 0x09, 0x9c, 0x48, 0xfb, 0xb8, 0x48, 0xc5, 0x55, 0xd0, 0x00, 0xcd, 0xf1, + 0x95, 0x86, 0xad, 0x30, 0x6c, 0x09, 0xab, 0x31, 0xec, 0xf4, 0xba, 0xbe, 0xd7, 0x1e, 0x3d, 0x3c, + 0xaa, 0x83, 0xce, 0xb8, 0x77, 0x76, 0x64, 0xbc, 0x03, 0x70, 0x9a, 0x25, 0x24, 0x24, 0x14, 0x45, + 0xae, 0xd6, 0x59, 0x1d, 0x69, 0x94, 0x9b, 0xe3, 0x2b, 0xf3, 0x59, 0xbf, 0xb4, 0x3e, 0xef, 0xb7, + 0xc6, 0x08, 0x6d, 0xaf, 0x1f, 0x1c, 0xd5, 0x4b, 0x3f, 0xfe, 0xd6, 0x9b, 0x21, 0x11, 0x9b, 0x5d, + 0xcf, 0xf6, 0x59, 0xec, 0x68, 0x81, 0xea, 0xdf, 0x12, 0x0f, 0xb6, 0x1c, 0xd1, 0xdb, 0xc6, 0x5c, + 0x5e, 0xe0, 0x9f, 0x4e, 0xf7, 0x5b, 0x13, 0x11, 0x0e, 0x91, 0xdf, 0x73, 0x53, 0xd5, 0xfc, 0xfb, + 0xe9, 0x7e, 0x0b, 0x74, 0xa6, 0x32, 0x68, 0x2d, 0xd0, 0xd8, 0x03, 0x70, 0x32, 0xc0, 0x69, 0xa1, + 0xc0, 0x81, 0xbb, 0x91, 0x60, 0x5c, 0x2d, 0x0f, 0x8b, 0xcc, 0xf5, 0x1c, 0x78, 0x3d, 0xc1, 0xd8, + 0xf8, 0x00, 0xe0, 0xcc, 0x19, 0x95, 0x6c, 0x34, 0xa3, 0xc3, 0x62, 0x33, 0x9d, 0x63, 0x67, 0xb3, + 0x99, 0x87, 0xd7, 0x30, 0x0d, 0x5c, 0x41, 0x62, 0x5c, 0xbd, 0xd2, 0x00, 0xcd, 0x72, 0xe7, 0x2a, + 0xa6, 0xc1, 0x4b, 0x12, 0xe3, 0xd5, 0x3b, 0x7b, 0x5f, 0xeb, 0xa5, 0xb7, 0xa7, 0xfb, 0xad, 0x5a, + 0x01, 0x63, 0xd0, 0x38, 0xd6, 0x4f, 0x00, 0xab, 0x6b, 0x8c, 0x0a, 0x42, 0xbb, 0xac, 0xcb, 0xfb, + 0x5c, 0xf5, 0x06, 0xce, 0x4a, 0x57, 0x69, 0xa9, 0x7d, 0xee, 0x5a, 0xb4, 0xfb, 0xb6, 0xc0, 0x1e, + 0xec, 0xaf, 0x0d, 0x66, 0x78, 0x83, 0x96, 0xad, 0x41, 0xc8, 0x05, 0x4a, 0x84, 0xa2, 0x3f, 0x22, + 0xe9, 0x8f, 0xc9, 0x13, 0x29, 0xe0, 0x7e, 0x26, 0x60, 0xb1, 0x20, 0xe0, 0x22, 0xa6, 0xd6, 0x17, + 0x00, 0x6f, 0x3e, 0xc6, 0x11, 0xea, 0xe5, 0xc3, 0x19, 0x86, 0x86, 0xd5, 0x7b, 0x19, 0xc9, 0x46, + 0x81, 0xe4, 0xb9, 0x3c, 0xac, 0xcf, 0x00, 0x56, 0x5e, 0xe0, 0x84, 0xb0, 0xc0, 0x98, 0x83, 0x95, + 0x08, 0xd3, 0x50, 0x6c, 0x4a, 0x12, 0xe5, 0x8e, 0x8e, 0x8c, 0x1e, 0xac, 0xa0, 0x58, 0x92, 0x1b, + 0xda, 0xba, 0x69, 0x40, 0xeb, 0xfd, 0x08, 0x9c, 0x53, 0xec, 0x88, 0x7f, 0x79, 0x4c, 0x60, 0x3c, + 0x83, 0xd9, 0x2f, 0xad, 0xbb, 0x2d, 0xd9, 0x71, 0xbd, 0xfc, 0xb7, 0x06, 0x60, 0x15, 0xfb, 0xf6, + 0x58, 0x3a, 0x18, 0xa5, 0x6d, 0x52, 0x97, 0xa8, 0x0c, 0x5f, 0x6d, 0x65, 0x2f, 0xeb, 0x76, 0x61, + 0x44, 0xe7, 0x8b, 0xb6, 0xbe, 0x01, 0x39, 0x8f, 0x18, 0x51, 0x4c, 0xc5, 0x73, 0xe6, 0x6f, 0xe1, + 0x60, 0x28, 0x86, 0xba, 0x88, 0xe3, 0x39, 0x44, 0xac, 0x3f, 0x00, 0xde, 0x58, 0x8b, 0xc8, 0xc6, + 0xc6, 0x25, 0x7a, 0x61, 0x35, 0x08, 0xfd, 0x94, 0x92, 0x4a, 0x97, 0x55, 0x5a, 0x9e, 0xc8, 0xa5, + 0xbe, 0x9b, 0xc9, 0x33, 0x8b, 0x4b, 0x3d, 0xa8, 0xa1, 0xfd, 0xf4, 0xe0, 0xd8, 0x04, 0x87, 0xc7, + 0x26, 0xf8, 0x77, 0x6c, 0x82, 0x8f, 0x27, 0x66, 0xe9, 0xf0, 0xc4, 0x2c, 0xfd, 0x3e, 0x31, 0x4b, + 0xaf, 0x1f, 0x14, 0x1c, 0x8f, 0x76, 0x19, 0xc5, 0x4b, 0xf2, 0xc3, 0xe8, 0xb3, 0x48, 0x85, 0x81, + 0xb3, 0x9b, 0x7d, 0xac, 0x95, 0xff, 0xbd, 0x8a, 0x2c, 0x78, 0xf8, 0x3f, 0x00, 0x00, 0xff, 0xff, + 0x55, 0xd5, 0xb5, 0xdb, 0xd4, 0x07, 0x00, 0x00, } func (m *BaseVestingAccount) Marshal() (dAtA []byte, err error) { From 2ba73c57fe20b0c2d846c1963af94eeea8b8335c Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Thu, 16 May 2024 08:37:36 +0200 Subject: [PATCH 02/18] docs(vesting): add documentation on cliff attribute --- proto/vesting/v1beta1/tx.proto | 1 + proto/vesting/v1beta1/vesting.proto | 1 + x/vesting/types/tx.pb.go | 3 ++- x/vesting/types/vesting.pb.go | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/proto/vesting/v1beta1/tx.proto b/proto/vesting/v1beta1/tx.proto index d82d7ea35..183585877 100644 --- a/proto/vesting/v1beta1/tx.proto +++ b/proto/vesting/v1beta1/tx.proto @@ -125,6 +125,7 @@ message MsgCreateCliffVestingAccount { ]; int64 end_time = 4; + // cliff time as unix time (in seconds) is the time at which the first portion of the vesting is unlocked. int64 cliff_time = 5; } diff --git a/proto/vesting/v1beta1/vesting.proto b/proto/vesting/v1beta1/vesting.proto index b4c4ed5b7..be11d6a01 100644 --- a/proto/vesting/v1beta1/vesting.proto +++ b/proto/vesting/v1beta1/vesting.proto @@ -108,5 +108,6 @@ message CliffVestingAccount { BaseVestingAccount base_vesting_account = 1 [(gogoproto.embed) = true]; // start_time defines the time at which the vesting period begins int64 start_time = 2; + // cliff_time defines the time at which the first portion of the vesting is unlocked int64 cliff_time = 3; } diff --git a/x/vesting/types/tx.pb.go b/x/vesting/types/tx.pb.go index 19735cedb..2c5583a42 100644 --- a/x/vesting/types/tx.pb.go +++ b/x/vesting/types/tx.pb.go @@ -376,7 +376,8 @@ type MsgCreateCliffVestingAccount struct { ToAddress string `protobuf:"bytes,2,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty" yaml:"to_address"` Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` EndTime int64 `protobuf:"varint,4,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"` - CliffTime int64 `protobuf:"varint,5,opt,name=cliff_time,json=cliffTime,proto3" json:"cliff_time,omitempty"` + // cliff time as unix time (in seconds) is the time at which the first portion of the vesting is unlocked. + CliffTime int64 `protobuf:"varint,5,opt,name=cliff_time,json=cliffTime,proto3" json:"cliff_time,omitempty"` } func (m *MsgCreateCliffVestingAccount) Reset() { *m = MsgCreateCliffVestingAccount{} } diff --git a/x/vesting/types/vesting.pb.go b/x/vesting/types/vesting.pb.go index 959cb92fe..d93609d1f 100644 --- a/x/vesting/types/vesting.pb.go +++ b/x/vesting/types/vesting.pb.go @@ -297,6 +297,7 @@ type CliffVestingAccount struct { *BaseVestingAccount `protobuf:"bytes,1,opt,name=base_vesting_account,json=baseVestingAccount,proto3,embedded=base_vesting_account" json:"base_vesting_account,omitempty"` // start_time defines the time at which the vesting period begins StartTime int64 `protobuf:"varint,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + // cliff_time defines the time at which the first portion of the vesting is unlocked CliffTime int64 `protobuf:"varint,3,opt,name=cliff_time,json=cliffTime,proto3" json:"cliff_time,omitempty"` } From 7536aee0d8f84e5dfb11d26d3819289c45a2013f Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Thu, 16 May 2024 14:01:34 +0200 Subject: [PATCH 03/18] feat(vesting): update to align with cosmos-sdk v0.50.4 This commit updates the vesting module to match the changes introduced in cosmos-sdk v0.50.4. --- x/vesting/client/cli/tx.go | 62 ++++--- x/vesting/module.go | 67 +++++-- x/vesting/msg_server.go | 182 +++++++++++------- x/vesting/types/codec.go | 5 +- x/vesting/types/constants.go | 3 - x/vesting/types/genesis_test.go | 3 +- x/vesting/types/msgs.go | 24 +-- x/vesting/types/period.go | 8 - x/vesting/types/vesting_account.go | 223 ++++++---------------- x/vesting/types/vesting_account_test.go | 235 +++++++++++++++++------- 10 files changed, 434 insertions(+), 378 deletions(-) diff --git a/x/vesting/client/cli/tx.go b/x/vesting/client/cli/tx.go index 4050c8975..3fcc45e27 100644 --- a/x/vesting/client/cli/tx.go +++ b/x/vesting/client/cli/tx.go @@ -2,12 +2,15 @@ package cli import ( "encoding/json" + "errors" "fmt" "os" "strconv" "github.com/spf13/cobra" + "cosmossdk.io/core/address" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" @@ -16,13 +19,13 @@ import ( "github.com/axone-protocol/axoned/v8/x/vesting/types" ) -// FlagDelayed Transaction command flags. +// Transaction command flags. const ( FlagDelayed = "delayed" ) // GetTxCmd returns vesting module's transaction commands. -func GetTxCmd() *cobra.Command { +func GetTxCmd(ac address.Codec) *cobra.Command { txCmd := &cobra.Command{ Use: types.ModuleName, Short: "Vesting transaction subcommands", @@ -32,10 +35,10 @@ func GetTxCmd() *cobra.Command { } txCmd.AddCommand( - NewMsgCreateVestingAccountCmd(), - NewMsgCreatePermanentLockedAccountCmd(), - NewMsgCreatePeriodicVestingAccountCmd(), - NewMsgCreateCliffVestingAccountCmd(), + NewMsgCreateVestingAccountCmd(ac), + NewMsgCreatePermanentLockedAccountCmd(ac), + NewMsgCreatePeriodicVestingAccountCmd(ac), + NewMsgCreateCliffVestingAccountCmd(ac), ) return txCmd @@ -43,7 +46,7 @@ func GetTxCmd() *cobra.Command { // NewMsgCreateVestingAccountCmd returns a CLI command handler for creating a // MsgCreateVestingAccount transaction. -func NewMsgCreateVestingAccountCmd() *cobra.Command { +func NewMsgCreateVestingAccountCmd(ac address.Codec) *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.", @@ -58,11 +61,15 @@ timestamp.`, if err != nil { return err } - toAddr, err := sdk.AccAddressFromBech32(args[0]) + toAddr, err := ac.StringToBytes(args[0]) if err != nil { return err } + if args[1] == "" { + return errors.New("amount is empty") + } + amount, err := sdk.ParseCoinsNormalized(args[1]) if err != nil { return err @@ -76,7 +83,6 @@ timestamp.`, delayed, _ := cmd.Flags().GetBool(FlagDelayed) msg := types.NewMsgCreateVestingAccount(clientCtx.GetFromAddress(), toAddr, amount, endTime, delayed) - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } @@ -89,7 +95,7 @@ timestamp.`, // NewMsgCreatePermanentLockedAccountCmd returns a CLI command handler for creating a // MsgCreatePermanentLockedAccount transaction. -func NewMsgCreatePermanentLockedAccountCmd() *cobra.Command { +func NewMsgCreatePermanentLockedAccountCmd(ac address.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "create-permanent-locked-account [to_address] [amount]", Short: "Create a new permanently locked account funded with an allocation of tokens.", @@ -102,18 +108,21 @@ tokens.`, if err != nil { return err } - toAddr, err := sdk.AccAddressFromBech32(args[0]) + toAddr, err := ac.StringToBytes(args[0]) if err != nil { return err } + if args[1] == "" { + return errors.New("amount is empty") + } + amount, err := sdk.ParseCoinsNormalized(args[1]) if err != nil { return err } msg := types.NewMsgCreatePermanentLockedAccount(clientCtx.GetFromAddress(), toAddr, amount) - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } @@ -129,15 +138,15 @@ type VestingData struct { } type InputPeriod struct { - Coins string `json:"coins"` - LengthSeconds int64 `json:"length_seconds"` + Coins string `json:"coins"` + Length int64 `json:"length_seconds"` //nolint:tagliatelle } // NewMsgCreatePeriodicVestingAccountCmd returns a CLI command handler for creating a // MsgCreatePeriodicVestingAccountCmd transaction. // //nolint:funlen,lll -func NewMsgCreatePeriodicVestingAccountCmd() *cobra.Command { +func NewMsgCreatePeriodicVestingAccountCmd(ac address.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "create-periodic-vesting-account [to_address] [periods_json_file]", Short: "Create a new vesting account funded with an allocation of tokens.", @@ -146,7 +155,7 @@ func NewMsgCreatePeriodicVestingAccountCmd() *cobra.Command { An array of coin strings and unix epoch times for coins to vest { "start_time": 1625204910, -"period":[ +"periods":[ { "coins": "10test", "length_seconds":2592000 //30 days @@ -165,7 +174,7 @@ func NewMsgCreatePeriodicVestingAccountCmd() *cobra.Command { return err } - toAddr, err := sdk.AccAddressFromBech32(args[0]) + toAddr, err := ac.StringToBytes(args[0]) if err != nil { return err } @@ -190,15 +199,15 @@ func NewMsgCreatePeriodicVestingAccountCmd() *cobra.Command { return err } - if p.LengthSeconds < 0 { - return fmt.Errorf("invalid period length of %d in period %d, length must be greater than 0", p.LengthSeconds, i) + if p.Length < 0 { + return fmt.Errorf("invalid period length of %d in period %d, length must be greater than 0", p.Length, i) } - period := types.Period{Length: p.LengthSeconds, Amount: amount} + + period := types.Period{Length: p.Length, Amount: amount} periods = append(periods, period) } msg := types.NewMsgCreatePeriodicVestingAccount(clientCtx.GetFromAddress(), toAddr, vestingData.StartTime, periods) - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } @@ -210,11 +219,11 @@ func NewMsgCreatePeriodicVestingAccountCmd() *cobra.Command { // NewMsgCreateCliffVestingAccountCmd returns a CLI command handler for creating a // MsgCreateCliffVestingAccount transaction. -func NewMsgCreateCliffVestingAccountCmd() *cobra.Command { +func NewMsgCreateCliffVestingAccountCmd(ac address.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "create-cliff-vesting-account [to_address] [amount] [cliff_time] [end_time]", Short: "Create a new vesting account funded with an allocation of tokens with cliff.", - Long: `Create a new vesting account funded with an allocation of tokens. The + Long: `Create a new vesting account funded with an allocation of tokens with cliff. The tokens allowed will be start vested but the token will be released only after the cliff time. All vesting accounts created will have their start time set by the committed block's time. The end_time and cliff_time must be provided as a UNIX epoch @@ -225,11 +234,15 @@ timestamp.`, if err != nil { return err } - toAddr, err := sdk.AccAddressFromBech32(args[0]) + toAddr, err := ac.StringToBytes(args[0]) if err != nil { return err } + if args[1] == "" { + return errors.New("amount is empty") + } + amount, err := sdk.ParseCoinsNormalized(args[1]) if err != nil { return err @@ -246,7 +259,6 @@ timestamp.`, } msg := types.NewMsgCreateCliffVestingAccount(clientCtx.GetFromAddress(), toAddr, amount, endTime, cliffTime) - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } diff --git a/x/vesting/module.go b/x/vesting/module.go index e84e42847..96f48f0e3 100644 --- a/x/vesting/module.go +++ b/x/vesting/module.go @@ -3,13 +3,16 @@ package vesting import ( "encoding/json" - "github.com/grpc-ecosystem/grpc-gateway/runtime" + gwruntime "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" "google.golang.org/grpc" abci "github.com/cometbft/cometbft/abci/types" + modulev1 "cosmossdk.io/api/cosmos/vesting/module/v1" + "cosmossdk.io/core/address" "cosmossdk.io/core/appmodule" + "cosmossdk.io/depinject" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" @@ -23,22 +26,25 @@ import ( ) var ( + _ module.AppModuleBasic = AppModule{} + _ appmodule.AppModule = AppModule{} _ appmodule.HasServices = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} ) // AppModuleBasic defines the basic application module used by the sub-vesting // module. The module itself contain no special logic or state other than message // handling. -type AppModuleBasic struct{} +type AppModuleBasic struct { + ac address.Codec +} // Name returns the module's name. func (AppModuleBasic) Name() string { return types.ModuleName } -// RegisterLegacyAminoCodec registers the module's types with the given codec. +// RegisterCodec registers the module's types with the given codec. func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { types.RegisterLegacyAminoCodec(cdc) } @@ -61,16 +67,11 @@ func (AppModuleBasic) ValidateGenesis(_ codec.JSONCodec, _ client.TxEncodingConf // RegisterGRPCGatewayRoutes registers the module's gRPC Gateway routes. Currently, this // is a no-op. -func (a AppModuleBasic) RegisterGRPCGatewayRoutes(_ client.Context, _ *runtime.ServeMux) {} +func (AppModuleBasic) RegisterGRPCGatewayRoutes(_ client.Context, _ *gwruntime.ServeMux) {} // GetTxCmd returns the root tx command for the auth module. -func (AppModuleBasic) GetTxCmd() *cobra.Command { - return cli.GetTxCmd() -} - -// GetQueryCmd returns the module's root query command. Currently, this is a no-op. -func (AppModuleBasic) GetQueryCmd() *cobra.Command { - return nil +func (ab AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd(ab.ac) } // AppModule extends the AppModuleBasic implementation by implementing the @@ -82,20 +83,19 @@ type AppModule struct { bankKeeper types.BankKeeper } -func (am AppModule) IsOnePerModuleType() {} - -func (am AppModule) IsAppModule() {} - func NewAppModule(ak keeper.AccountKeeper, bk types.BankKeeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, + AppModuleBasic: AppModuleBasic{ac: ak.AddressCodec()}, accountKeeper: ak, bankKeeper: bk, } } -// RegisterInvariants performs a no-op; there are no invariants to enforce. -func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} +// IsOnePerModuleType implements the depinject.OnePerModuleType interface. +func (am AppModule) IsOnePerModuleType() {} + +// IsAppModule implements the appmodule.AppModule interface. +func (am AppModule) IsAppModule() {} // RegisterServices registers module services. func (am AppModule) RegisterServices(registrar grpc.ServiceRegistrar) error { @@ -115,3 +115,32 @@ func (am AppModule) ExportGenesis(_ sdk.Context, cdc codec.JSONCodec) json.RawMe // ConsensusVersion implements AppModule/ConsensusVersion. func (AppModule) ConsensusVersion() uint64 { return 1 } + +// +// App Wiring Setup +// + +func init() { + appmodule.Register(&modulev1.Module{}, + appmodule.Provide(ProvideModule), + ) +} + +type ModuleInputs struct { + depinject.In + + AccountKeeper keeper.AccountKeeper + BankKeeper types.BankKeeper +} + +type ModuleOutputs struct { + depinject.Out + + Module appmodule.AppModule +} + +func ProvideModule(in ModuleInputs) ModuleOutputs { + m := NewAppModule(in.AccountKeeper, in.BankKeeper) + + return ModuleOutputs{Module: m} +} diff --git a/x/vesting/msg_server.go b/x/vesting/msg_server.go index f96f0a7a1..20c0d83c4 100644 --- a/x/vesting/msg_server.go +++ b/x/vesting/msg_server.go @@ -29,37 +29,47 @@ func NewMsgServerImpl(k keeper.AccountKeeper, bk types.BankKeeper) types.MsgServ var _ types.MsgServer = msgServer{} +//nolint:funlen func (s msgServer) CreateVestingAccount(goCtx context.Context, msg *types.MsgCreateVestingAccount, ) (*types.MsgCreateVestingAccountResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - ak := s.AccountKeeper - bk := s.BankKeeper - - if err := bk.IsSendEnabledCoins(ctx, msg.Amount...); err != nil { - return nil, err + from, err := s.AccountKeeper.AddressCodec().StringToBytes(msg.FromAddress) + if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid 'from' address: %s", err) } - from, err := sdk.AccAddressFromBech32(msg.FromAddress) + to, err := s.AccountKeeper.AddressCodec().StringToBytes(msg.ToAddress) if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid 'to' address: %s", err) + } + + if err := validateAmount(msg.Amount); err != nil { return nil, err } - to, err := sdk.AccAddressFromBech32(msg.ToAddress) - if err != nil { + + if msg.EndTime <= 0 { + return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid end time") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + if err := s.BankKeeper.IsSendEnabledCoins(ctx, msg.Amount...); err != nil { return nil, err } - if bk.BlockedAddr(to) { + if s.BankKeeper.BlockedAddr(to) { return nil, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", msg.ToAddress) } - if acc := ak.GetAccount(ctx, to); acc != nil { + if acc := s.AccountKeeper.GetAccount(ctx, to); acc != nil { return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "account %s already exists", msg.ToAddress) } baseAccount := authtypes.NewBaseAccountWithAddress(to) - baseAccount = ak.NewAccount(ctx, baseAccount).(*authtypes.BaseAccount) - baseVestingAccount := types.NewBaseVestingAccount(baseAccount, msg.Amount.Sort(), msg.EndTime) + baseAccount = s.AccountKeeper.NewAccount(ctx, baseAccount).(*authtypes.BaseAccount) + baseVestingAccount, err := types.NewBaseVestingAccount(baseAccount, msg.Amount.Sort(), msg.EndTime) + if err != nil { + return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, err.Error()) + } var vestingAccount sdk.AccountI if msg.Delayed { @@ -68,7 +78,7 @@ func (s msgServer) CreateVestingAccount(goCtx context.Context, vestingAccount = types.NewContinuousVestingAccountRaw(baseVestingAccount, ctx.BlockTime().Unix()) } - ak.SetAccount(ctx, vestingAccount) + s.AccountKeeper.SetAccount(ctx, vestingAccount) defer func() { telemetry.IncrCounter(1, "new", "account") @@ -84,8 +94,7 @@ func (s msgServer) CreateVestingAccount(goCtx context.Context, } }() - err = bk.SendCoins(ctx, from, to, msg.Amount) - if err != nil { + if err = s.BankKeeper.SendCoins(ctx, from, to, msg.Amount); err != nil { return nil, err } @@ -95,36 +104,41 @@ func (s msgServer) CreateVestingAccount(goCtx context.Context, func (s msgServer) CreatePermanentLockedAccount(goCtx context.Context, msg *types.MsgCreatePermanentLockedAccount, ) (*types.MsgCreatePermanentLockedAccountResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - ak := s.AccountKeeper - bk := s.BankKeeper - - if err := bk.IsSendEnabledCoins(ctx, msg.Amount...); err != nil { - return nil, err + from, err := s.AccountKeeper.AddressCodec().StringToBytes(msg.FromAddress) + if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid 'from' address: %s", err) } - from, err := sdk.AccAddressFromBech32(msg.FromAddress) + to, err := s.AccountKeeper.AddressCodec().StringToBytes(msg.ToAddress) if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid 'to' address: %s", err) + } + + if err := validateAmount(msg.Amount); err != nil { return nil, err } - to, err := sdk.AccAddressFromBech32(msg.ToAddress) - if err != nil { + + ctx := sdk.UnwrapSDKContext(goCtx) + if err := s.BankKeeper.IsSendEnabledCoins(ctx, msg.Amount...); err != nil { return nil, err } - if bk.BlockedAddr(to) { + if s.BankKeeper.BlockedAddr(to) { return nil, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", msg.ToAddress) } - if acc := ak.GetAccount(ctx, to); acc != nil { + if acc := s.AccountKeeper.GetAccount(ctx, to); acc != nil { return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "account %s already exists", msg.ToAddress) } baseAccount := authtypes.NewBaseAccountWithAddress(to) - baseAccount = ak.NewAccount(ctx, baseAccount).(*authtypes.BaseAccount) - vestingAccount := types.NewPermanentLockedAccount(baseAccount, msg.Amount) + baseAccount = s.AccountKeeper.NewAccount(ctx, baseAccount).(*authtypes.BaseAccount) + vestingAccount, err := types.NewPermanentLockedAccount(baseAccount, msg.Amount) + if err != nil { + return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, err.Error()) + } - ak.SetAccount(ctx, vestingAccount) + s.AccountKeeper.SetAccount(ctx, vestingAccount) defer func() { telemetry.IncrCounter(1, "new", "account") @@ -140,50 +154,66 @@ func (s msgServer) CreatePermanentLockedAccount(goCtx context.Context, } }() - err = bk.SendCoins(ctx, from, to, msg.Amount) - if err != nil { + if err = s.BankKeeper.SendCoins(ctx, from, to, msg.Amount); err != nil { return nil, err } return &types.MsgCreatePermanentLockedAccountResponse{}, nil } +//nolint:funlen func (s msgServer) CreatePeriodicVestingAccount(goCtx context.Context, msg *types.MsgCreatePeriodicVestingAccount, ) (*types.MsgCreatePeriodicVestingAccountResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - ak := s.AccountKeeper - bk := s.BankKeeper - - from, err := sdk.AccAddressFromBech32(msg.FromAddress) + from, err := s.AccountKeeper.AddressCodec().StringToBytes(msg.FromAddress) if err != nil { - return nil, err + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid 'from' address: %s", err) } - to, err := sdk.AccAddressFromBech32(msg.ToAddress) + + to, err := s.AccountKeeper.AddressCodec().StringToBytes(msg.ToAddress) if err != nil { - return nil, err + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid 'to' address: %s", err) } - if acc := ak.GetAccount(ctx, to); acc != nil { - return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "account %s already exists", msg.ToAddress) + if msg.StartTime < 1 { + return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "invalid start time of %d, length must be greater than 0", msg.StartTime) } var totalCoins sdk.Coins + for i, period := range msg.VestingPeriods { + if period.Length < 1 { + return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, + "invalid period length of %d in period %d, length must be greater than 0", period.Length, i) + } + + if err := validateAmount(period.Amount); err != nil { + return nil, err + } - for _, period := range msg.VestingPeriods { totalCoins = totalCoins.Add(period.Amount...) } - if err := bk.IsSendEnabledCoins(ctx, totalCoins...); err != nil { + if s.BankKeeper.BlockedAddr(to) { + return nil, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", msg.ToAddress) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + if acc := s.AccountKeeper.GetAccount(ctx, to); acc != nil { + return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "account %s already exists", msg.ToAddress) + } + + if err := s.BankKeeper.IsSendEnabledCoins(ctx, totalCoins...); err != nil { return nil, err } baseAccount := authtypes.NewBaseAccountWithAddress(to) - baseAccount = ak.NewAccount(ctx, baseAccount).(*authtypes.BaseAccount) - vestingAccount := types.NewPeriodicVestingAccount(baseAccount, totalCoins.Sort(), msg.StartTime, msg.VestingPeriods) + baseAccount = s.AccountKeeper.NewAccount(ctx, baseAccount).(*authtypes.BaseAccount) + vestingAccount, err := types.NewPeriodicVestingAccount(baseAccount, totalCoins.Sort(), msg.StartTime, msg.VestingPeriods) + if err != nil { + return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, err.Error()) + } - ak.SetAccount(ctx, vestingAccount) + s.AccountKeeper.SetAccount(ctx, vestingAccount) defer func() { telemetry.IncrCounter(1, "new", "account") @@ -199,49 +229,58 @@ func (s msgServer) CreatePeriodicVestingAccount(goCtx context.Context, } }() - err = bk.SendCoins(ctx, from, to, totalCoins) - if err != nil { + if err = s.BankKeeper.SendCoins(ctx, from, to, totalCoins); err != nil { return nil, err } return &types.MsgCreatePeriodicVestingAccountResponse{}, nil } +//nolint:funlen func (s msgServer) CreateCliffVestingAccount(goCtx context.Context, msg *types.MsgCreateCliffVestingAccount, ) (*types.MsgCreateCliffVestingAccountResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - ak := s.AccountKeeper - bk := s.BankKeeper - - if err := bk.IsSendEnabledCoins(ctx, msg.Amount...); err != nil { - return nil, err + from, err := s.AccountKeeper.AddressCodec().StringToBytes(msg.FromAddress) + if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid 'from' address: %s", err) } - from, err := sdk.AccAddressFromBech32(msg.FromAddress) + to, err := s.AccountKeeper.AddressCodec().StringToBytes(msg.ToAddress) if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid 'to' address: %s", err) + } + + if err := validateAmount(msg.Amount); err != nil { return nil, err } - to, err := sdk.AccAddressFromBech32(msg.ToAddress) - if err != nil { + + if msg.EndTime <= 0 { + return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid end time") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + if err := s.BankKeeper.IsSendEnabledCoins(ctx, msg.Amount...); err != nil { return nil, err } - if bk.BlockedAddr(to) { + if s.BankKeeper.BlockedAddr(to) { return nil, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", msg.ToAddress) } - if acc := ak.GetAccount(ctx, to); acc != nil { + if acc := s.AccountKeeper.GetAccount(ctx, to); acc != nil { return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "account %s already exists", msg.ToAddress) } baseAccount := authtypes.NewBaseAccountWithAddress(to) - baseAccount = ak.NewAccount(ctx, baseAccount).(*authtypes.BaseAccount) - baseVestingAccount := types.NewBaseVestingAccount(baseAccount, msg.Amount.Sort(), msg.EndTime) + baseAccount = s.AccountKeeper.NewAccount(ctx, baseAccount).(*authtypes.BaseAccount) + baseVestingAccount, err := types.NewBaseVestingAccount(baseAccount, msg.Amount.Sort(), msg.EndTime) + if err != nil { + return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, err.Error()) + } vestingAccount := types.NewCliffVestingAccountRaw(baseVestingAccount, ctx.BlockTime().Unix(), msg.CliffTime) - ak.SetAccount(ctx, vestingAccount) + s.AccountKeeper.SetAccount(ctx, vestingAccount) defer func() { telemetry.IncrCounter(1, "new", "account") @@ -257,10 +296,21 @@ func (s msgServer) CreateCliffVestingAccount(goCtx context.Context, } }() - err = bk.SendCoins(ctx, from, to, msg.Amount) - if err != nil { + if err = s.BankKeeper.SendCoins(ctx, from, to, msg.Amount); err != nil { return nil, err } return &types.MsgCreateCliffVestingAccountResponse{}, nil } + +func validateAmount(amount sdk.Coins) error { + if !amount.IsValid() { + return sdkerrors.ErrInvalidCoins.Wrap(amount.String()) + } + + if !amount.IsAllPositive() { + return sdkerrors.ErrInvalidCoins.Wrap(amount.String()) + } + + return nil +} diff --git a/x/vesting/types/codec.go b/x/vesting/types/codec.go index 72802262b..407c894fa 100644 --- a/x/vesting/types/codec.go +++ b/x/vesting/types/codec.go @@ -16,13 +16,15 @@ import ( func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { cdc.RegisterInterface((*exported.VestingAccount)(nil), nil) cdc.RegisterConcrete(&BaseVestingAccount{}, "cosmos-sdk/BaseVestingAccount", nil) - cdc.RegisterConcrete(&CliffVestingAccount{}, "cosmos-sdk/CliffVestingAccount", nil) cdc.RegisterConcrete(&ContinuousVestingAccount{}, "cosmos-sdk/ContinuousVestingAccount", nil) cdc.RegisterConcrete(&DelayedVestingAccount{}, "cosmos-sdk/DelayedVestingAccount", nil) cdc.RegisterConcrete(&PeriodicVestingAccount{}, "cosmos-sdk/PeriodicVestingAccount", nil) cdc.RegisterConcrete(&PermanentLockedAccount{}, "cosmos-sdk/PermanentLockedAccount", nil) + cdc.RegisterConcrete(&CliffVestingAccount{}, "cosmos-sdk/CliffVestingAccount", nil) legacy.RegisterAminoMsg(cdc, &MsgCreateVestingAccount{}, "cosmos-sdk/MsgCreateVestingAccount") legacy.RegisterAminoMsg(cdc, &MsgCreatePermanentLockedAccount{}, "cosmos-sdk/MsgCreatePermLockedAccount") + legacy.RegisterAminoMsg(cdc, &MsgCreatePeriodicVestingAccount{}, "cosmos-sdk/MsgCreatePeriodVestAccount") + legacy.RegisterAminoMsg(cdc, &MsgCreateCliffVestingAccount{}, "cosmos-sdk/MsgCreateCliffVestingAccount") } // RegisterInterface associates protoName with AccountI and VestingAccount @@ -62,6 +64,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { (*sdk.Msg)(nil), &MsgCreateVestingAccount{}, &MsgCreatePermanentLockedAccount{}, + &MsgCreateCliffVestingAccount{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) diff --git a/x/vesting/types/constants.go b/x/vesting/types/constants.go index 5fd3ce154..3562a80ea 100644 --- a/x/vesting/types/constants.go +++ b/x/vesting/types/constants.go @@ -4,9 +4,6 @@ const ( // ModuleName defines the module's name. ModuleName = "vesting" - // AttributeValueCategory is an alias for the message event value. - AttributeValueCategory = ModuleName - // RouterKey defines the module's message routing key. RouterKey = ModuleName ) diff --git a/x/vesting/types/genesis_test.go b/x/vesting/types/genesis_test.go index d8b8d6d9d..74d6c49ab 100644 --- a/x/vesting/types/genesis_test.go +++ b/x/vesting/types/genesis_test.go @@ -21,7 +21,8 @@ var ( func TestValidateGenesisInvalidAccounts(t *testing.T) { acc1 := authtypes.NewBaseAccountWithAddress(sdk.AccAddress(addr1)) acc1Balance := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)) - baseVestingAcc := NewBaseVestingAccount(acc1, acc1Balance, 1548775410) + baseVestingAcc, err := NewBaseVestingAccount(acc1, acc1Balance, 1548775410) + require.NoError(t, err) // invalid delegated vesting baseVestingAcc.DelegatedVesting = acc1Balance.Add(acc1Balance...) diff --git a/x/vesting/types/msgs.go b/x/vesting/types/msgs.go index 15e7e8a76..67d00091f 100644 --- a/x/vesting/types/msgs.go +++ b/x/vesting/types/msgs.go @@ -4,17 +4,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -var _ sdk.Msg = &MsgCreateVestingAccount{} - -var _ sdk.Msg = &MsgCreatePermanentLockedAccount{} - -var _ sdk.Msg = &MsgCreatePeriodicVestingAccount{} - -var _ sdk.Msg = &MsgCreateCliffVestingAccount{} +var ( + _ sdk.Msg = &MsgCreateVestingAccount{} + _ sdk.Msg = &MsgCreatePermanentLockedAccount{} + _ sdk.Msg = &MsgCreatePeriodicVestingAccount{} + _ sdk.Msg = &MsgCreateCliffVestingAccount{} +) // NewMsgCreateVestingAccount returns a reference to a new MsgCreateVestingAccount. -// -//nolint:interfacer func NewMsgCreateVestingAccount(fromAddr, toAddr sdk.AccAddress, amount sdk.Coins, @@ -31,8 +28,6 @@ func NewMsgCreateVestingAccount(fromAddr, } // NewMsgCreatePermanentLockedAccount returns a reference to a new MsgCreatePermanentLockedAccount. -// -//nolint:interfacer func NewMsgCreatePermanentLockedAccount(fromAddr, toAddr sdk.AccAddress, amount sdk.Coins) *MsgCreatePermanentLockedAccount { return &MsgCreatePermanentLockedAccount{ FromAddress: fromAddr.String(), @@ -42,10 +37,7 @@ func NewMsgCreatePermanentLockedAccount(fromAddr, toAddr sdk.AccAddress, amount } // NewMsgCreatePeriodicVestingAccount returns a reference to a new MsgCreatePeriodicVestingAccount. -// -//nolint:interfacer -func NewMsgCreatePeriodicVestingAccount(fromAddr, - toAddr sdk.AccAddress, +func NewMsgCreatePeriodicVestingAccount(fromAddr, toAddr sdk.AccAddress, startTime int64, periods []Period, ) *MsgCreatePeriodicVestingAccount { @@ -58,8 +50,6 @@ func NewMsgCreatePeriodicVestingAccount(fromAddr, } // NewMsgCreateCliffVestingAccount returns a reference to a new MsgCreateCliffVestingAccount. -// -//nolint:interfacer func NewMsgCreateCliffVestingAccount(fromAddr, toAddr sdk.AccAddress, amount sdk.Coins, diff --git a/x/vesting/types/period.go b/x/vesting/types/period.go index d733e639c..a1ac78f5d 100644 --- a/x/vesting/types/period.go +++ b/x/vesting/types/period.go @@ -5,8 +5,6 @@ import ( "strings" "time" - "sigs.k8s.io/yaml" - sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -18,12 +16,6 @@ func (p Period) Duration() time.Duration { return time.Duration(p.Length) * time.Second } -// String implements the fmt.Stringer interface. -func (p Period) String() string { - out, _ := yaml.Marshal(p) - return string(out) -} - // TotalLength return the total length in seconds for a period. func (p Periods) TotalLength() int64 { var total int64 diff --git a/x/vesting/types/vesting_account.go b/x/vesting/types/vesting_account.go index c8c420e40..d08c6189f 100644 --- a/x/vesting/types/vesting_account.go +++ b/x/vesting/types/vesting_account.go @@ -2,13 +2,11 @@ package types import ( "errors" + "fmt" "time" - "sigs.k8s.io/yaml" - "cosmossdk.io/math" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -29,14 +27,16 @@ var ( // NewBaseVestingAccount creates a new BaseVestingAccount object. It is the // callers responsibility to ensure the base account has sufficient funds with // regards to the original vesting amount. -func NewBaseVestingAccount(baseAccount *authtypes.BaseAccount, originalVesting sdk.Coins, endTime int64) *BaseVestingAccount { - return &BaseVestingAccount{ +func NewBaseVestingAccount(baseAccount *authtypes.BaseAccount, originalVesting sdk.Coins, endTime int64) (*BaseVestingAccount, error) { + baseVestingAccount := &BaseVestingAccount{ BaseAccount: baseAccount, OriginalVesting: originalVesting, DelegatedFree: sdk.NewCoins(), DelegatedVesting: sdk.NewCoins(), EndTime: endTime, } + + return baseVestingAccount, baseVestingAccount.Validate() } // LockedCoinsFromVesting returns all the coins that are not spendable (i.e. locked) @@ -149,51 +149,19 @@ func (bva BaseVestingAccount) GetEndTime() int64 { // Validate checks for errors on the account fields. func (bva BaseVestingAccount) Validate() error { - if !(bva.DelegatedVesting.IsAllLTE(bva.OriginalVesting)) { - return errors.New("delegated vesting amount cannot be greater than original vesting amount") + if bva.EndTime < 0 { + return errors.New("end time cannot be negative") } - return bva.BaseAccount.Validate() -} - -type vestingAccountYAML struct { - Address sdk.AccAddress `json:"address"` - PublicKey string `json:"public_key"` - AccountNumber uint64 `json:"account_number"` - Sequence uint64 `json:"sequence"` - OriginalVesting sdk.Coins `json:"original_vesting"` - DelegatedFree sdk.Coins `json:"delegated_free"` - DelegatedVesting sdk.Coins `json:"delegated_vesting"` - EndTime int64 `json:"end_time"` - - // custom fields based on concrete vesting type which can be omitted - StartTime int64 `json:"start_time,omitempty"` - CliffTime int64 `json:"cliff_time,omitempty"` - VestingPeriods Periods `json:"vesting_periods,omitempty"` -} -func (bva BaseVestingAccount) String() string { - out, _ := bva.MarshalYAML() - return out.(string) -} - -// MarshalYAML returns the YAML representation of a BaseVestingAccount. -func (bva BaseVestingAccount) MarshalYAML() (interface{}, error) { - accAddr, err := sdk.AccAddressFromBech32(bva.Address) - if err != nil { - return nil, err + if !bva.OriginalVesting.IsValid() || !bva.OriginalVesting.IsAllPositive() { + return fmt.Errorf("invalid coins: %s", bva.OriginalVesting.String()) } - out := vestingAccountYAML{ - Address: accAddr, - AccountNumber: bva.AccountNumber, - PublicKey: getPKString(bva), - Sequence: bva.Sequence, - OriginalVesting: bva.OriginalVesting, - DelegatedFree: bva.DelegatedFree, - DelegatedVesting: bva.DelegatedVesting, - EndTime: bva.EndTime, + if !(bva.DelegatedVesting.IsAllLTE(bva.OriginalVesting)) { + return errors.New("delegated vesting amount cannot be greater than original vesting amount") } - return marshalYaml(out) + + return bva.BaseAccount.Validate() } // Continuous Vesting Account @@ -215,17 +183,19 @@ func NewContinuousVestingAccountRaw(bva *BaseVestingAccount, startTime int64) *C func NewContinuousVestingAccount(baseAcc *authtypes.BaseAccount, originalVesting sdk.Coins, startTime, endTime int64, -) *ContinuousVestingAccount { +) (*ContinuousVestingAccount, error) { baseVestingAcc := &BaseVestingAccount{ BaseAccount: baseAcc, OriginalVesting: originalVesting, EndTime: endTime, } - return &ContinuousVestingAccount{ + continuousVestingAccount := &ContinuousVestingAccount{ StartTime: startTime, BaseVestingAccount: baseVestingAcc, } + + return continuousVestingAccount, continuousVestingAccount.Validate() } // GetVestedCoins returns the total number of vested coins. If no coins are vested, @@ -289,32 +259,6 @@ func (cva ContinuousVestingAccount) Validate() error { return cva.BaseVestingAccount.Validate() } -func (cva ContinuousVestingAccount) String() string { - out, _ := cva.MarshalYAML() - return out.(string) -} - -// MarshalYAML returns the YAML representation of a ContinuousVestingAccount. -func (cva ContinuousVestingAccount) MarshalYAML() (interface{}, error) { - accAddr, err := sdk.AccAddressFromBech32(cva.Address) - if err != nil { - return nil, err - } - - out := vestingAccountYAML{ - Address: accAddr, - AccountNumber: cva.AccountNumber, - PublicKey: getPKString(cva), - Sequence: cva.Sequence, - OriginalVesting: cva.OriginalVesting, - DelegatedFree: cva.DelegatedFree, - DelegatedVesting: cva.DelegatedVesting, - EndTime: cva.EndTime, - StartTime: cva.StartTime, - } - return marshalYaml(out) -} - // Periodic Vesting Account var ( @@ -336,22 +280,25 @@ func NewPeriodicVestingAccount(baseAcc *authtypes.BaseAccount, originalVesting sdk.Coins, startTime int64, periods Periods, -) *PeriodicVestingAccount { +) (*PeriodicVestingAccount, error) { endTime := startTime for _, p := range periods { endTime += p.Length } + baseVestingAcc := &BaseVestingAccount{ BaseAccount: baseAcc, OriginalVesting: originalVesting, EndTime: endTime, } - return &PeriodicVestingAccount{ + periodicVestingAccount := &PeriodicVestingAccount{ BaseVestingAccount: baseVestingAcc, StartTime: startTime, VestingPeriods: periods, } + + return periodicVestingAccount, periodicVestingAccount.Validate() } // GetVestedCoins returns the total number of vested coins. If no coins are vested, @@ -424,47 +371,32 @@ func (pva PeriodicVestingAccount) Validate() error { } endTime := pva.StartTime originalVesting := sdk.NewCoins() - for _, p := range pva.VestingPeriods { + for i, p := range pva.VestingPeriods { + if p.Length < 0 { + return fmt.Errorf("period #%d has a negative length: %d", i, p.Length) + } endTime += p.Length + + if !p.Amount.IsValid() || !p.Amount.IsAllPositive() { + return fmt.Errorf("period #%d has invalid coins: %s", i, p.Amount.String()) + } + originalVesting = originalVesting.Add(p.Amount...) } if endTime != pva.EndTime { return errors.New("vesting end time does not match length of all vesting periods") } + if endTime < pva.GetStartTime() { + return errors.New("cumulative endTime overflowed, and/or is less than startTime") + } if !originalVesting.Equal(pva.OriginalVesting) { - return errors.New("original vesting coins does not match the sum of all coins in vesting periods") + return fmt.Errorf("original vesting coins (%v) does not match the sum of all coins in vesting periods (%v)", + pva.OriginalVesting, originalVesting) } return pva.BaseVestingAccount.Validate() } -func (pva PeriodicVestingAccount) String() string { - out, _ := pva.MarshalYAML() - return out.(string) -} - -// MarshalYAML returns the YAML representation of a PeriodicVestingAccount. -func (pva PeriodicVestingAccount) MarshalYAML() (interface{}, error) { - accAddr, err := sdk.AccAddressFromBech32(pva.Address) - if err != nil { - return nil, err - } - - out := vestingAccountYAML{ - Address: accAddr, - AccountNumber: pva.AccountNumber, - PublicKey: getPKString(pva), - Sequence: pva.Sequence, - OriginalVesting: pva.OriginalVesting, - DelegatedFree: pva.DelegatedFree, - DelegatedVesting: pva.DelegatedVesting, - EndTime: pva.EndTime, - StartTime: pva.StartTime, - VestingPeriods: pva.VestingPeriods, - } - return marshalYaml(out) -} - // Delayed Vesting Account var ( @@ -480,14 +412,19 @@ func NewDelayedVestingAccountRaw(bva *BaseVestingAccount) *DelayedVestingAccount } // NewDelayedVestingAccount returns a DelayedVestingAccount. -func NewDelayedVestingAccount(baseAcc *authtypes.BaseAccount, originalVesting sdk.Coins, endTime int64) *DelayedVestingAccount { +func NewDelayedVestingAccount(baseAcc *authtypes.BaseAccount, + originalVesting sdk.Coins, + endTime int64, +) (*DelayedVestingAccount, error) { baseVestingAcc := &BaseVestingAccount{ BaseAccount: baseAcc, OriginalVesting: originalVesting, EndTime: endTime, } - return &DelayedVestingAccount{baseVestingAcc} + delayedVestingAccount := &DelayedVestingAccount{baseVestingAcc} + + return delayedVestingAccount, delayedVestingAccount.Validate() } // GetVestedCoins returns the total amount of vested coins for a delayed vesting @@ -529,11 +466,6 @@ func (dva DelayedVestingAccount) Validate() error { return dva.BaseVestingAccount.Validate() } -func (dva DelayedVestingAccount) String() string { - out, _ := dva.MarshalYAML() - return out.(string) -} - //----------------------------------------------------------------------------- // Permanent Locked Vesting Account @@ -543,14 +475,16 @@ var ( ) // NewPermanentLockedAccount returns a PermanentLockedAccount. -func NewPermanentLockedAccount(baseAcc *authtypes.BaseAccount, coins sdk.Coins) *PermanentLockedAccount { +func NewPermanentLockedAccount(baseAcc *authtypes.BaseAccount, coins sdk.Coins) (*PermanentLockedAccount, error) { baseVestingAcc := &BaseVestingAccount{ BaseAccount: baseAcc, OriginalVesting: coins, EndTime: 0, // ensure EndTime is set to 0, as PermanentLockedAccount's do not have an EndTime } - return &PermanentLockedAccount{baseVestingAcc} + permanentLockedAccount := &PermanentLockedAccount{baseVestingAcc} + + return permanentLockedAccount, permanentLockedAccount.Validate() } // GetVestedCoins returns the total amount of vested coins for a permanent locked vesting @@ -598,11 +532,6 @@ func (plva PermanentLockedAccount) Validate() error { return plva.BaseVestingAccount.Validate() } -func (plva PermanentLockedAccount) String() string { - out, _ := plva.MarshalYAML() - return out.(string) -} - // Cliff Vesting Account var ( @@ -611,7 +540,7 @@ var ( ) // NewCliffVestingAccountRaw creates a new CliffVestingAccount object from BaseVestingAccount. -func NewCliffVestingAccountRaw(bva *BaseVestingAccount, startTime int64, cliffTime int64) *CliffVestingAccount { +func NewCliffVestingAccountRaw(bva *BaseVestingAccount, startTime, cliffTime int64) *CliffVestingAccount { return &CliffVestingAccount{ BaseVestingAccount: bva, StartTime: startTime, @@ -623,18 +552,20 @@ func NewCliffVestingAccountRaw(bva *BaseVestingAccount, startTime int64, cliffTi func NewCliffVestingAccount(baseAcc *authtypes.BaseAccount, originalVesting sdk.Coins, startTime, cliffTime, endTime int64, -) *CliffVestingAccount { +) (*CliffVestingAccount, error) { baseVestingAcc := &BaseVestingAccount{ BaseAccount: baseAcc, OriginalVesting: originalVesting, EndTime: endTime, } - return &CliffVestingAccount{ + cliffVestingAccount := &CliffVestingAccount{ StartTime: startTime, CliffTime: cliffTime, BaseVestingAccount: baseVestingAcc, } + + return cliffVestingAccount, cliffVestingAccount.Validate() } // GetVestedCoins returns the total number of vested coins. If no coins are vested, @@ -683,7 +614,7 @@ func (cva *CliffVestingAccount) TrackDelegation(blockTime time.Time, balance, am cva.BaseVestingAccount.TrackDelegation(balance, cva.GetVestingCoins(blockTime), amount) } -// GetStartTime returns the time when vesting starts for a cliff vesting +// GetStartTime returns the time when vesting starts for a continuous vesting // account. func (cva CliffVestingAccount) GetStartTime() int64 { return cva.StartTime @@ -698,7 +629,7 @@ func (cva CliffVestingAccount) GetCliffTime() int64 { // Validate checks for errors on the account fields. func (cva CliffVestingAccount) Validate() error { if cva.GetStartTime() >= cva.GetEndTime() { - return errors.New("vesting start-time cannot be after end-time") + return errors.New("vesting start-time cannot be before end-time") } if cva.GetStartTime() >= cva.GetCliffTime() { return errors.New("vesting start-time cannot be after cliff-time") @@ -709,49 +640,3 @@ func (cva CliffVestingAccount) Validate() error { return cva.BaseVestingAccount.Validate() } - -func (cva CliffVestingAccount) String() string { - out, _ := cva.MarshalYAML() - return out.(string) -} - -// MarshalYAML returns the YAML representation of a ContinuousVestingAccount. -func (cva CliffVestingAccount) MarshalYAML() (interface{}, error) { - accAddr, err := sdk.AccAddressFromBech32(cva.Address) - if err != nil { - return nil, err - } - - out := vestingAccountYAML{ - Address: accAddr, - AccountNumber: cva.AccountNumber, - PublicKey: getPKString(cva), - Sequence: cva.Sequence, - OriginalVesting: cva.OriginalVesting, - DelegatedFree: cva.DelegatedFree, - DelegatedVesting: cva.DelegatedVesting, - EndTime: cva.EndTime, - StartTime: cva.StartTime, - CliffTime: cva.CliffTime, - } - return marshalYaml(out) -} - -type getPK interface { - GetPubKey() cryptotypes.PubKey -} - -func getPKString(g getPK) string { - if pk := g.GetPubKey(); pk != nil { - return pk.String() - } - return "" -} - -func marshalYaml(i interface{}) (interface{}, error) { - bz, err := yaml.Marshal(i) - if err != nil { - return nil, err - } - return string(bz), nil -} diff --git a/x/vesting/types/vesting_account_test.go b/x/vesting/types/vesting_account_test.go index 1581b343d..6a5e40d24 100644 --- a/x/vesting/types/vesting_account_test.go +++ b/x/vesting/types/vesting_account_test.go @@ -1,3 +1,4 @@ +//nolint:lll package types_test import ( @@ -7,9 +8,9 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" tmtime "github.com/cometbft/cometbft/types/time" + "cosmossdk.io/core/header" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" @@ -43,8 +44,9 @@ func (s *VestingAccountTestSuite) SetupTest() { encCfg := moduletestutil.MakeTestEncodingConfig(vesting.AppModuleBasic{}) key := storetypes.NewKVStoreKey(authtypes.StoreKey) + storeService := runtime.NewKVStoreService(key) testCtx := testutil.DefaultContextWithDB(s.T(), key, storetypes.NewTransientStoreKey("transient_test")) - s.ctx = testCtx.Ctx.WithBlockHeader(cmtproto.Header{}) + s.ctx = testCtx.Ctx.WithHeaderInfo(header.Info{}) maccPerms := map[string][]string{ "fee_collector": nil, @@ -57,7 +59,7 @@ func (s *VestingAccountTestSuite) SetupTest() { s.accountKeeper = keeper.NewAccountKeeper( encCfg.Codec, - runtime.NewKVStoreService(key), + storeService, authtypes.ProtoBaseAccount, maccPerms, authcodec.NewBech32Codec("cosmos"), @@ -71,7 +73,8 @@ func TestGetVestedCoinsContVestingAcc(t *testing.T) { endTime := now.Add(24 * time.Hour) bacc, origCoins := initBaseAccount() - cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + cva, err := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + require.NoError(t, err) // require no coins vested in the very beginning of the vesting schedule vestedCoins := cva.GetVestedCoins(now) @@ -95,7 +98,8 @@ func TestGetVestingCoinsContVestingAcc(t *testing.T) { endTime := now.Add(24 * time.Hour) bacc, origCoins := initBaseAccount() - cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + cva, err := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + require.NoError(t, err) // require all coins vesting in the beginning of the vesting schedule vestingCoins := cva.GetVestingCoins(now) @@ -115,7 +119,8 @@ func TestSpendableCoinsContVestingAcc(t *testing.T) { endTime := now.Add(24 * time.Hour) bacc, origCoins := initBaseAccount() - cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + cva, err := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + require.NoError(t, err) // require that all original coins are locked at the end of the vesting // schedule @@ -138,19 +143,22 @@ func TestTrackDelegationContVestingAcc(t *testing.T) { bacc, origCoins := initBaseAccount() // require the ability to delegate all vesting coins - cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + cva, err := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + require.NoError(t, err) cva.TrackDelegation(now, origCoins, origCoins) require.Equal(t, origCoins, cva.DelegatedVesting) require.Nil(t, cva.DelegatedFree) // require the ability to delegate all vested coins - cva = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + cva, err = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + require.NoError(t, err) cva.TrackDelegation(endTime, origCoins, origCoins) require.Nil(t, cva.DelegatedVesting) require.Equal(t, origCoins, cva.DelegatedFree) // require the ability to delegate all vesting coins (50%) and all vested coins (50%) - cva = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + cva, err = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + require.NoError(t, err) cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, cva.DelegatedVesting) require.Nil(t, cva.DelegatedFree) @@ -160,7 +168,8 @@ func TestTrackDelegationContVestingAcc(t *testing.T) { require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, cva.DelegatedFree) // require no modifications when delegation amount is zero or not enough funds - cva = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + cva, err = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + require.NoError(t, err) require.Panics(t, func() { cva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) }) @@ -175,23 +184,24 @@ func TestTrackUndelegationContVestingAcc(t *testing.T) { bacc, origCoins := initBaseAccount() // require the ability to undelegate all vesting coins - cva := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + cva, err := types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + require.NoError(t, err) cva.TrackDelegation(now, origCoins, origCoins) cva.TrackUndelegation(origCoins) require.Nil(t, cva.DelegatedFree) require.Equal(t, emptyCoins, cva.DelegatedVesting) // require the ability to undelegate all vested coins - cva = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) - + cva, err = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + require.NoError(t, err) cva.TrackDelegation(endTime, origCoins, origCoins) cva.TrackUndelegation(origCoins) require.Equal(t, emptyCoins, cva.DelegatedFree) require.Nil(t, cva.DelegatedVesting) // require no modifications when the undelegation amount is zero - cva = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) - + cva, err = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + require.NoError(t, err) require.Panics(t, func() { cva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) }) @@ -199,7 +209,8 @@ func TestTrackUndelegationContVestingAcc(t *testing.T) { require.Nil(t, cva.DelegatedVesting) // vest 50% and delegate to two validators - cva = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + cva, err = types.NewContinuousVestingAccount(bacc, origCoins, now.Unix(), endTime.Unix()) + require.NoError(t, err) cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) @@ -221,7 +232,8 @@ func TestGetVestedCoinsDelVestingAcc(t *testing.T) { bacc, origCoins := initBaseAccount() // require no coins are vested until schedule maturation - dva := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + dva, err := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + require.NoError(t, err) vestedCoins := dva.GetVestedCoins(now) require.Nil(t, vestedCoins) @@ -237,7 +249,8 @@ func TestGetVestingCoinsDelVestingAcc(t *testing.T) { bacc, origCoins := initBaseAccount() // require all coins vesting at the beginning of the schedule - dva := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + dva, err := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + require.NoError(t, err) vestingCoins := dva.GetVestingCoins(now) require.Equal(t, origCoins, vestingCoins) @@ -254,7 +267,8 @@ func TestSpendableCoinsDelVestingAcc(t *testing.T) { // require that all coins are locked in the beginning of the vesting // schedule - dva := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + dva, err := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + require.NoError(t, err) lockedCoins := dva.LockedCoins(now) require.True(t, lockedCoins.Equal(origCoins)) @@ -282,27 +296,30 @@ func TestTrackDelegationDelVestingAcc(t *testing.T) { bacc, origCoins := initBaseAccount() // require the ability to delegate all vesting coins - dva := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + dva, err := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + require.NoError(t, err) dva.TrackDelegation(now, origCoins, origCoins) require.Equal(t, origCoins, dva.DelegatedVesting) require.Nil(t, dva.DelegatedFree) // require the ability to delegate all vested coins - dva = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + dva, err = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + require.NoError(t, err) dva.TrackDelegation(endTime, origCoins, origCoins) require.Nil(t, dva.DelegatedVesting) require.Equal(t, origCoins, dva.DelegatedFree) // require the ability to delegate all coins half way through the vesting // schedule - dva = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + dva, err = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + require.NoError(t, err) dva.TrackDelegation(now.Add(12*time.Hour), origCoins, origCoins) require.Equal(t, origCoins, dva.DelegatedVesting) require.Nil(t, dva.DelegatedFree) // require no modifications when delegation amount is zero or not enough funds - dva = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) - + dva, err = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + require.NoError(t, err) require.Panics(t, func() { dva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) }) @@ -317,22 +334,24 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) { bacc, origCoins := initBaseAccount() // require the ability to undelegate all vesting coins - dva := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + dva, err := types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + require.NoError(t, err) dva.TrackDelegation(now, origCoins, origCoins) dva.TrackUndelegation(origCoins) require.Nil(t, dva.DelegatedFree) require.Equal(t, emptyCoins, dva.DelegatedVesting) // require the ability to undelegate all vested coins - dva = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + dva, err = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + require.NoError(t, err) dva.TrackDelegation(endTime, origCoins, origCoins) dva.TrackUndelegation(origCoins) require.Equal(t, emptyCoins, dva.DelegatedFree) require.Nil(t, dva.DelegatedVesting) // require no modifications when the undelegation amount is zero - dva = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) - + dva, err = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + require.NoError(t, err) require.Panics(t, func() { dva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) }) @@ -340,7 +359,8 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) { require.Nil(t, dva.DelegatedVesting) // vest 50% and delegate to two validators - dva = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + dva, err = types.NewDelayedVestingAccount(bacc, origCoins, endTime.Unix()) + require.NoError(t, err) dva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) dva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) @@ -366,7 +386,8 @@ func TestGetVestedCoinsPeriodicVestingAcc(t *testing.T) { } bacc, origCoins := initBaseAccount() - pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + pva, err := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + require.NoError(t, err) // require no coins vested at the beginning of the vesting schedule vestedCoins := pva.GetVestedCoins(now) @@ -400,6 +421,57 @@ func TestGetVestedCoinsPeriodicVestingAcc(t *testing.T) { require.Equal(t, origCoins, vestedCoins) } +func TestOverflowAndNegativeVestedCoinsPeriods(t *testing.T) { + now := tmtime.Now() + tests := []struct { + name string + periods []types.Period + wantErr string + }{ + { + "negative .Length", + types.Periods{ + types.Period{Length: -1, Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, + types.Period{Length: 6 * 60 * 60, Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + }, + "period #0 has a negative length: -1", + }, + { + "overflow after .Length additions", + types.Periods{ + types.Period{Length: 9223372036854775108, Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, + types.Period{Length: 6 * 60 * 60, Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + }, + "vesting start-time cannot be before end-time", // it overflow to a negative number, making start-time > end-time + }, + { + "good periods that are not negative nor overflow", + types.Periods{ + types.Period{Length: now.Unix() - 1000, Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}}, + types.Period{Length: 60, Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + types.Period{Length: 30, Amount: sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}}, + }, + "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + bacc, origCoins := initBaseAccount() + pva, err := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), tt.periods) + if tt.wantErr != "" { + require.ErrorContains(t, err, tt.wantErr) + return + } + + require.NoError(t, err) + if pbva := pva.BaseVestingAccount; pbva.EndTime < 0 { + t.Fatalf("Unfortunately we still have negative .EndTime :-(: %d", pbva.EndTime) + } + }) + } +} + func TestGetVestingCoinsPeriodicVestingAcc(t *testing.T) { now := tmtime.Now() endTime := now.Add(24 * time.Hour) @@ -410,7 +482,8 @@ func TestGetVestingCoinsPeriodicVestingAcc(t *testing.T) { } bacc, origCoins := initBaseAccount() - pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + pva, err := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + require.NoError(t, err) // require all coins vesting at the beginning of the vesting schedule vestingCoins := pva.GetVestingCoins(now) @@ -447,7 +520,8 @@ func TestSpendableCoinsPeriodicVestingAcc(t *testing.T) { } bacc, origCoins := initBaseAccount() - pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + pva, err := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + require.NoError(t, err) // require that there exist no spendable coins at the beginning of the // vesting schedule @@ -476,33 +550,38 @@ func TestTrackDelegationPeriodicVestingAcc(t *testing.T) { bacc, origCoins := initBaseAccount() // require the ability to delegate all vesting coins - pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + pva, err := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + require.NoError(t, err) pva.TrackDelegation(now, origCoins, origCoins) require.Equal(t, origCoins, pva.DelegatedVesting) require.Nil(t, pva.DelegatedFree) // require the ability to delegate all vested coins - pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + pva, err = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + require.NoError(t, err) pva.TrackDelegation(endTime, origCoins, origCoins) require.Nil(t, pva.DelegatedVesting) require.Equal(t, origCoins, pva.DelegatedFree) // delegate half of vesting coins - pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + pva, err = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + require.NoError(t, err) pva.TrackDelegation(now, origCoins, periods[0].Amount) // require that all delegated coins are delegated vesting require.Equal(t, pva.DelegatedVesting, periods[0].Amount) require.Nil(t, pva.DelegatedFree) // delegate 75% of coins, split between vested and vesting - pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + pva, err = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + require.NoError(t, err) pva.TrackDelegation(now.Add(12*time.Hour), origCoins, periods[0].Amount.Add(periods[1].Amount...)) // require that the maximum possible amount of vesting coins are chosen for delegation. require.Equal(t, pva.DelegatedFree, periods[1].Amount) require.Equal(t, pva.DelegatedVesting, periods[0].Amount) // require the ability to delegate all vesting coins (50%) and all vested coins (50%) - pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + pva, err = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + require.NoError(t, err) pva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, pva.DelegatedVesting) require.Nil(t, pva.DelegatedFree) @@ -512,7 +591,8 @@ func TestTrackDelegationPeriodicVestingAcc(t *testing.T) { require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}, pva.DelegatedFree) // require no modifications when delegation amount is zero or not enough funds - pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + pva, err = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + require.NoError(t, err) require.Panics(t, func() { pva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) }) @@ -532,30 +612,32 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { bacc, origCoins := initBaseAccount() // require the ability to undelegate all vesting coins at the beginning of vesting - pva := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + pva, err := types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + require.NoError(t, err) pva.TrackDelegation(now, origCoins, origCoins) pva.TrackUndelegation(origCoins) require.Nil(t, pva.DelegatedFree) require.Equal(t, emptyCoins, pva.DelegatedVesting) // require the ability to undelegate all vested coins at the end of vesting - pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) - + pva, err = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + require.NoError(t, err) pva.TrackDelegation(endTime, origCoins, origCoins) pva.TrackUndelegation(origCoins) require.Equal(t, emptyCoins, pva.DelegatedFree) require.Nil(t, pva.DelegatedVesting) // require the ability to undelegate half of coins - pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + pva, err = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + require.NoError(t, err) pva.TrackDelegation(endTime, origCoins, periods[0].Amount) pva.TrackUndelegation(periods[0].Amount) require.Equal(t, emptyCoins, pva.DelegatedFree) require.Nil(t, pva.DelegatedVesting) // require no modifications when the undelegation amount is zero - pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) - + pva, err = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + require.NoError(t, err) require.Panics(t, func() { pva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) }) @@ -563,7 +645,8 @@ func TestTrackUndelegationPeriodicVestingAcc(t *testing.T) { require.Nil(t, pva.DelegatedVesting) // vest 50% and delegate to two validators - pva = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + pva, err = types.NewPeriodicVestingAccount(bacc, origCoins, now.Unix(), periods) + require.NoError(t, err) pva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) pva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) @@ -585,7 +668,8 @@ func TestGetVestedCoinsPermLockedVestingAcc(t *testing.T) { bacc, origCoins := initBaseAccount() // require no coins are vested - plva := types.NewPermanentLockedAccount(bacc, origCoins) + plva, err := types.NewPermanentLockedAccount(bacc, origCoins) + require.NoError(t, err) vestedCoins := plva.GetVestedCoins(now) require.Nil(t, vestedCoins) @@ -601,7 +685,8 @@ func TestGetVestingCoinsPermLockedVestingAcc(t *testing.T) { bacc, origCoins := initBaseAccount() // require all coins vesting at the beginning of the schedule - plva := types.NewPermanentLockedAccount(bacc, origCoins) + plva, err := types.NewPermanentLockedAccount(bacc, origCoins) + require.NoError(t, err) vestingCoins := plva.GetVestingCoins(now) require.Equal(t, origCoins, vestingCoins) @@ -618,7 +703,8 @@ func TestSpendableCoinsPermLockedVestingAcc(t *testing.T) { // require that all coins are locked in the beginning of the vesting // schedule - plva := types.NewPermanentLockedAccount(bacc, origCoins) + plva, err := types.NewPermanentLockedAccount(bacc, origCoins) + require.NoError(t, err) lockedCoins := plva.LockedCoins(now) require.True(t, lockedCoins.Equal(origCoins)) @@ -641,20 +727,22 @@ func TestTrackDelegationPermLockedVestingAcc(t *testing.T) { bacc, origCoins := initBaseAccount() // require the ability to delegate all vesting coins - plva := types.NewPermanentLockedAccount(bacc, origCoins) + plva, err := types.NewPermanentLockedAccount(bacc, origCoins) + require.NoError(t, err) plva.TrackDelegation(now, origCoins, origCoins) require.Equal(t, origCoins, plva.DelegatedVesting) require.Nil(t, plva.DelegatedFree) // require the ability to delegate all vested coins at endTime - plva = types.NewPermanentLockedAccount(bacc, origCoins) + plva, err = types.NewPermanentLockedAccount(bacc, origCoins) + require.NoError(t, err) plva.TrackDelegation(endTime, origCoins, origCoins) require.Equal(t, origCoins, plva.DelegatedVesting) require.Nil(t, plva.DelegatedFree) // require no modifications when delegation amount is zero or not enough funds - plva = types.NewPermanentLockedAccount(bacc, origCoins) - + plva, err = types.NewPermanentLockedAccount(bacc, origCoins) + require.NoError(t, err) require.Panics(t, func() { plva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) }) @@ -669,21 +757,24 @@ func TestTrackUndelegationPermLockedVestingAcc(t *testing.T) { bacc, origCoins := initBaseAccount() // require the ability to undelegate all vesting coins - plva := types.NewPermanentLockedAccount(bacc, origCoins) + plva, err := types.NewPermanentLockedAccount(bacc, origCoins) + require.NoError(t, err) plva.TrackDelegation(now, origCoins, origCoins) plva.TrackUndelegation(origCoins) require.Nil(t, plva.DelegatedFree) require.Equal(t, emptyCoins, plva.DelegatedVesting) // require the ability to undelegate all vesting coins at endTime - plva = types.NewPermanentLockedAccount(bacc, origCoins) + plva, err = types.NewPermanentLockedAccount(bacc, origCoins) + require.NoError(t, err) plva.TrackDelegation(endTime, origCoins, origCoins) plva.TrackUndelegation(origCoins) require.Nil(t, plva.DelegatedFree) require.Equal(t, emptyCoins, plva.DelegatedVesting) // require no modifications when the undelegation amount is zero - plva = types.NewPermanentLockedAccount(bacc, origCoins) + plva, err = types.NewPermanentLockedAccount(bacc, origCoins) + require.NoError(t, err) require.Panics(t, func() { plva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) }) @@ -691,7 +782,8 @@ func TestTrackUndelegationPermLockedVestingAcc(t *testing.T) { require.Nil(t, plva.DelegatedVesting) // delegate to two validators - plva = types.NewPermanentLockedAccount(bacc, origCoins) + plva, err = types.NewPermanentLockedAccount(bacc, origCoins) + require.NoError(t, err) plva.TrackDelegation(now, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) plva.TrackDelegation(now, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) @@ -712,7 +804,8 @@ func TestGenesisAccountValidate(t *testing.T) { addr := sdk.AccAddress(pubkey.Address()) baseAcc := authtypes.NewBaseAccount(addr, pubkey, 0, 0) initialVesting := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)) - baseVestingWithCoins := types.NewBaseVestingAccount(baseAcc, initialVesting, 100) + baseVestingWithCoins, err := types.NewBaseVestingAccount(baseAcc, initialVesting, 100) + require.NoError(t, err) tests := []struct { name string acc authtypes.GenesisAccount @@ -735,25 +828,26 @@ func TestGenesisAccountValidate(t *testing.T) { }, { "valid continuous vesting account", - types.NewContinuousVestingAccount(baseAcc, initialVesting, 100, 200), + func() authtypes.GenesisAccount { + acc, _ := types.NewContinuousVestingAccount(baseAcc, initialVesting, 100, 200) + return acc + }(), false, }, { "invalid vesting times", - types.NewContinuousVestingAccount(baseAcc, initialVesting, 1654668078, 1554668078), + func() authtypes.GenesisAccount { + acc, _ := types.NewContinuousVestingAccount(baseAcc, initialVesting, 1654668078, 1554668078) + return acc + }(), true, }, { "valid periodic vesting account", - types.NewPeriodicVestingAccount(baseAcc, - initialVesting, - 0, - types.Periods{ - types.Period{ - Length: int64(100), - Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}, - }, - }), + func() authtypes.GenesisAccount { + acc, _ := types.NewPeriodicVestingAccount(baseAcc, initialVesting, 0, types.Periods{types.Period{Length: int64(100), Amount: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}}}) + return acc + }(), false, }, { @@ -772,7 +866,10 @@ func TestGenesisAccountValidate(t *testing.T) { }, { "valid permanent locked vesting account", - types.NewPermanentLockedAccount(baseAcc, initialVesting), + func() authtypes.GenesisAccount { + acc, _ := types.NewPermanentLockedAccount(baseAcc, initialVesting) + return acc + }(), false, }, { From 5581dc76f70012877de632bc57d3a270484656db Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Thu, 16 May 2024 14:07:38 +0200 Subject: [PATCH 04/18] test(vesting): add cli tests --- x/vesting/client/cli/test.json | 13 ++ x/vesting/client/cli/tx_test.go | 279 ++++++++++++++++++++++++++++++++ 2 files changed, 292 insertions(+) create mode 100644 x/vesting/client/cli/test.json create mode 100644 x/vesting/client/cli/tx_test.go diff --git a/x/vesting/client/cli/test.json b/x/vesting/client/cli/test.json new file mode 100644 index 000000000..1ed078e28 --- /dev/null +++ b/x/vesting/client/cli/test.json @@ -0,0 +1,13 @@ +{ + "start_time": 1625204910, + "period": [ + { + "coins": "10test", + "length_seconds": 2592000 + }, + { + "coins": "10test", + "length_seconds": 2592000 + } + ] +} diff --git a/x/vesting/client/cli/tx_test.go b/x/vesting/client/cli/tx_test.go new file mode 100644 index 000000000..9dc159191 --- /dev/null +++ b/x/vesting/client/cli/tx_test.go @@ -0,0 +1,279 @@ +package cli_test + +import ( + "context" + "fmt" + "io" + "testing" + "time" + + rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock" + "github.com/stretchr/testify/suite" + + sdkmath "cosmossdk.io/math" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec/address" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + "github.com/cosmos/cosmos-sdk/testutil" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" + + "github.com/axone-protocol/axoned/v7/x/vesting" + "github.com/axone-protocol/axoned/v7/x/vesting/client/cli" +) + +type CLITestSuite struct { + suite.Suite + + kr keyring.Keyring + encCfg testutilmod.TestEncodingConfig + baseCtx client.Context +} + +func TestMigrateTestSuite(t *testing.T) { + suite.Run(t, new(CLITestSuite)) +} + +func (s *CLITestSuite) SetupSuite() { + s.encCfg = testutilmod.MakeTestEncodingConfig(vesting.AppModuleBasic{}) + s.kr = keyring.NewInMemory(s.encCfg.Codec) + s.baseCtx = client.Context{}. + WithKeyring(s.kr). + WithTxConfig(s.encCfg.TxConfig). + WithCodec(s.encCfg.Codec). + WithClient(clitestutil.MockCometRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard) +} + +func (s *CLITestSuite) TestNewMsgCreateVestingAccountCmd() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + cmd := cli.NewMsgCreateVestingAccountCmd(address.NewBech32Codec("cosmos")) + cmd.SetOutput(io.Discard) + + extraArgs := []string{ + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("photon", sdkmath.NewInt(10))).String()), + fmt.Sprintf("--%s=test-chain", flags.FlagChainID), + fmt.Sprintf("--%s=%s", flags.FlagFrom, accounts[0].Address), + } + + t := time.Date(2033, time.April, 1, 12, 34, 56, 789, time.UTC).Unix() + + testCases := []struct { + name string + ctxGen func() client.Context + from, to sdk.AccAddress + amount sdk.Coins + endTime int64 + extraArgs []string + expectErr bool + }{ + { + "valid transaction", + func() client.Context { + return s.baseCtx + }, + accounts[0].Address, + accounts[0].Address, + sdk.NewCoins( + sdk.NewCoin("stake", sdkmath.NewInt(10)), + sdk.NewCoin("photon", sdkmath.NewInt(40)), + ), + t, + extraArgs, + false, + }, + { + "invalid to Address", + func() client.Context { + return s.baseCtx + }, + accounts[0].Address, + sdk.AccAddress{}, + sdk.NewCoins( + sdk.NewCoin("stake", sdkmath.NewInt(10)), + sdk.NewCoin("photon", sdkmath.NewInt(40)), + ), + t, + extraArgs, + true, + }, + { + "invalid coins", + func() client.Context { + return s.baseCtx + }, + accounts[0].Address, + accounts[0].Address, + nil, + t, + extraArgs, + true, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + fmt.Println(tc.amount.String()) + cmd.SetArgs(append([]string{tc.to.String(), tc.amount.String(), fmt.Sprint(tc.endTime)}, tc.extraArgs...)) + + s.Require().NoError(client.SetCmdClientContextHandler(tc.ctxGen(), cmd)) + + err := cmd.Execute() + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + }) + } +} + +func (s *CLITestSuite) TestNewMsgCreatePermanentLockedAccountCmd() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + cmd := cli.NewMsgCreatePermanentLockedAccountCmd(address.NewBech32Codec("cosmos")) + cmd.SetOutput(io.Discard) + + extraArgs := []string{ + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("photon", sdkmath.NewInt(10))).String()), + fmt.Sprintf("--%s=test-chain", flags.FlagChainID), + fmt.Sprintf("--%s=%s", flags.FlagFrom, accounts[0].Address), + } + + testCases := []struct { + name string + ctxGen func() client.Context + to sdk.AccAddress + amount sdk.Coins + extraArgs []string + expectErr bool + }{ + { + "valid transaction", + func() client.Context { + return s.baseCtx + }, + accounts[0].Address, + sdk.NewCoins( + sdk.NewCoin("stake", sdkmath.NewInt(10)), + sdk.NewCoin("photon", sdkmath.NewInt(40)), + ), + extraArgs, + false, + }, + { + "invalid to Address", + func() client.Context { + return s.baseCtx + }, + sdk.AccAddress{}, + sdk.NewCoins( + sdk.NewCoin("stake", sdkmath.NewInt(10)), + sdk.NewCoin("photon", sdkmath.NewInt(40)), + ), + extraArgs, + true, + }, + { + "invalid coins", + func() client.Context { + return s.baseCtx + }, + accounts[0].Address, + nil, + extraArgs, + true, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(append([]string{tc.to.String(), tc.amount.String()}, tc.extraArgs...)) + + s.Require().NoError(client.SetCmdClientContextHandler(tc.ctxGen(), cmd)) + + err := cmd.Execute() + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + }) + } +} + +func (s *CLITestSuite) TestNewMsgCreatePeriodicVestingAccountCmd() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + cmd := cli.NewMsgCreatePeriodicVestingAccountCmd(address.NewBech32Codec("cosmos")) + cmd.SetOutput(io.Discard) + + extraArgs := []string{ + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("photon", sdkmath.NewInt(10))).String()), + fmt.Sprintf("--%s=test-chain", flags.FlagChainID), + fmt.Sprintf("--%s=%s", flags.FlagFrom, accounts[0].Address), + } + + testCases := []struct { + name string + ctxGen func() client.Context + to sdk.AccAddress + extraArgs []string + expectErr bool + }{ + { + "valid transaction", + func() client.Context { + return s.baseCtx + }, + accounts[0].Address, + extraArgs, + false, + }, + { + "invalid to Address", + func() client.Context { + return s.baseCtx + }, + sdk.AccAddress{}, + extraArgs, + true, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(append([]string{tc.to.String(), "./test.json"}, tc.extraArgs...)) + + s.Require().NoError(client.SetCmdClientContextHandler(tc.ctxGen(), cmd)) + + err := cmd.Execute() + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + }) + } +} From 8f6066f9c70fea8d8bd48f2bba3ff41fe42956a0 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Thu, 16 May 2024 14:16:31 +0200 Subject: [PATCH 05/18] test(vesting): add cli test for cliff vesting account --- x/vesting/client/cli/tx_test.go | 92 +++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/x/vesting/client/cli/tx_test.go b/x/vesting/client/cli/tx_test.go index 9dc159191..2b53819d5 100644 --- a/x/vesting/client/cli/tx_test.go +++ b/x/vesting/client/cli/tx_test.go @@ -139,6 +139,98 @@ func (s *CLITestSuite) TestNewMsgCreateVestingAccountCmd() { } } +func (s *CLITestSuite) TestNewMsgCreateCliffVestingAccountCmd() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + cmd := cli.NewMsgCreateCliffVestingAccountCmd(address.NewBech32Codec("cosmos")) + cmd.SetOutput(io.Discard) + + extraArgs := []string{ + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("photon", sdkmath.NewInt(10))).String()), + fmt.Sprintf("--%s=test-chain", flags.FlagChainID), + fmt.Sprintf("--%s=%s", flags.FlagFrom, accounts[0].Address), + } + + t := time.Date(2033, time.April, 1, 12, 34, 56, 789, time.UTC).Unix() + + testCases := []struct { + name string + ctxGen func() client.Context + from, to sdk.AccAddress + amount sdk.Coins + cliffTime int64 + endTime int64 + extraArgs []string + expectErr bool + }{ + { + "valid transaction", + func() client.Context { + return s.baseCtx + }, + accounts[0].Address, + accounts[0].Address, + sdk.NewCoins( + sdk.NewCoin("stake", sdkmath.NewInt(10)), + sdk.NewCoin("photon", sdkmath.NewInt(40)), + ), + t, + t, + extraArgs, + false, + }, + { + "invalid to Address", + func() client.Context { + return s.baseCtx + }, + accounts[0].Address, + sdk.AccAddress{}, + sdk.NewCoins( + sdk.NewCoin("stake", sdkmath.NewInt(10)), + sdk.NewCoin("photon", sdkmath.NewInt(40)), + ), + t, + t, + extraArgs, + true, + }, + { + "invalid coins", + func() client.Context { + return s.baseCtx + }, + accounts[0].Address, + accounts[0].Address, + nil, + t, + t, + extraArgs, + true, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(append([]string{tc.to.String(), tc.amount.String(), fmt.Sprint(tc.cliffTime), fmt.Sprint(tc.endTime)}, tc.extraArgs...)) + + s.Require().NoError(client.SetCmdClientContextHandler(tc.ctxGen(), cmd)) + + err := cmd.Execute() + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + }) + } +} + func (s *CLITestSuite) TestNewMsgCreatePermanentLockedAccountCmd() { accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) cmd := cli.NewMsgCreatePermanentLockedAccountCmd(address.NewBech32Codec("cosmos")) From fb415ab4980996274b85c92e1e443cc2af3b76d3 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Thu, 16 May 2024 14:42:53 +0200 Subject: [PATCH 06/18] test(vesting): add msg_server tests for cliff --- x/vesting/msg_server.go | 3 + x/vesting/msg_server_test.go | 308 +++++++++++++++++++++++++++++++++-- 2 files changed, 300 insertions(+), 11 deletions(-) diff --git a/x/vesting/msg_server.go b/x/vesting/msg_server.go index 20c0d83c4..b3da2408f 100644 --- a/x/vesting/msg_server.go +++ b/x/vesting/msg_server.go @@ -257,6 +257,9 @@ func (s msgServer) CreateCliffVestingAccount(goCtx context.Context, if msg.EndTime <= 0 { return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid end time") } + if msg.CliffTime <= 0 { + return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid cliff time") + } ctx := sdk.UnwrapSDKContext(goCtx) if err := s.BankKeeper.IsSendEnabledCoins(ctx, msg.Amount...); err != nil { diff --git a/x/vesting/msg_server_test.go b/x/vesting/msg_server_test.go index 38e077d80..26c29426b 100644 --- a/x/vesting/msg_server_test.go +++ b/x/vesting/msg_server_test.go @@ -1,15 +1,15 @@ package vesting_test import ( + "cosmossdk.io/math" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + cmttime "github.com/cometbft/cometbft/types/time" "testing" "time" "github.com/golang/mock/gomock" "github.com/stretchr/testify/suite" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmtime "github.com/cometbft/cometbft/types/time" - storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/runtime" @@ -47,7 +47,7 @@ func (s *VestingTestSuite) SetupTest() { key := storetypes.NewKVStoreKey(authtypes.StoreKey) storeService := runtime.NewKVStoreService(key) testCtx := testutil.DefaultContextWithDB(s.T(), key, storetypes.NewTransientStoreKey("transient_test")) - s.ctx = testCtx.Ctx.WithBlockHeader(tmproto.Header{Time: tmtime.Now()}) + s.ctx = testCtx.Ctx.WithBlockHeader(cmtproto.Header{Time: cmttime.Now()}) encCfg := moduletestutil.MakeTestEncodingConfig() maccPerms := map[string][]string{} @@ -76,6 +76,50 @@ func (s *VestingTestSuite) TestCreateVestingAccount() { expErr bool expErrMsg string }{ + "empty from address": { + input: vestingtypes.NewMsgCreateVestingAccount( + []byte{}, + to1Addr, + sdk.Coins{fooCoin}, + time.Now().Unix(), + true, + ), + expErr: true, + expErrMsg: "invalid 'from' address", + }, + "empty to address": { + input: vestingtypes.NewMsgCreateVestingAccount( + fromAddr, + []byte{}, + sdk.Coins{fooCoin}, + time.Now().Unix(), + true, + ), + expErr: true, + expErrMsg: "invalid 'to' address", + }, + "invalid coins": { + input: vestingtypes.NewMsgCreateVestingAccount( + fromAddr, + to1Addr, + sdk.Coins{sdk.Coin{Denom: "stake", Amount: math.NewInt(-1)}}, + time.Now().Unix(), + true, + ), + expErr: true, + expErrMsg: "-1stake: invalid coins", + }, + "invalid end time": { + input: vestingtypes.NewMsgCreateVestingAccount( + fromAddr, + to1Addr, + sdk.Coins{fooCoin}, + -10, + true, + ), + expErr: true, + expErrMsg: "invalid end time", + }, "create for existing account": { preRun: func() { toAcc := s.accountKeeper.NewAccountWithAddress(s.ctx, to1Addr) @@ -93,6 +137,21 @@ func (s *VestingTestSuite) TestCreateVestingAccount() { expErr: true, expErrMsg: "already exists", }, + "create for blocked account": { + preRun: func() { + s.bankKeeper.EXPECT().IsSendEnabledCoins(gomock.Any(), fooCoin).Return(nil) + s.bankKeeper.EXPECT().BlockedAddr(to1Addr).Return(true) + }, + input: vestingtypes.NewMsgCreateVestingAccount( + fromAddr, + to1Addr, + sdk.Coins{fooCoin}, + time.Now().Unix(), + true, + ), + expErr: true, + expErrMsg: "not allowed to receive funds", + }, "create a valid delayed vesting account": { preRun: func() { s.bankKeeper.EXPECT().IsSendEnabledCoins(gomock.Any(), fooCoin).Return(nil) @@ -129,7 +188,9 @@ func (s *VestingTestSuite) TestCreateVestingAccount() { for name, tc := range testCases { s.Run(name, func() { - tc.preRun() + if tc.preRun != nil { + tc.preRun() + } _, err := s.msgServer.CreateVestingAccount(s.ctx, tc.input) if tc.expErr { s.Require().Error(err) @@ -148,6 +209,33 @@ func (s *VestingTestSuite) TestCreatePermanentLockedAccount() { expErr bool expErrMsg string }{ + "empty from address": { + input: vestingtypes.NewMsgCreatePermanentLockedAccount( + []byte{}, + to1Addr, + sdk.Coins{fooCoin}, + ), + expErr: true, + expErrMsg: "invalid 'from' address", + }, + "empty to address": { + input: vestingtypes.NewMsgCreatePermanentLockedAccount( + fromAddr, + []byte{}, + sdk.Coins{fooCoin}, + ), + expErr: true, + expErrMsg: "invalid 'to' address", + }, + "invalid coins": { + input: vestingtypes.NewMsgCreatePermanentLockedAccount( + fromAddr, + to1Addr, + sdk.Coins{sdk.Coin{Denom: "stake", Amount: math.NewInt(-1)}}, + ), + expErr: true, + expErrMsg: "-1stake: invalid coins", + }, "create for existing account": { preRun: func() { toAcc := s.accountKeeper.NewAccountWithAddress(s.ctx, to1Addr) @@ -163,6 +251,22 @@ func (s *VestingTestSuite) TestCreatePermanentLockedAccount() { expErr: true, expErrMsg: "already exists", }, + "create for blocked account": { + preRun: func() { + toAcc := s.accountKeeper.NewAccountWithAddress(s.ctx, to1Addr) + s.bankKeeper.EXPECT().IsSendEnabledCoins(gomock.Any(), fooCoin).Return(nil) + s.bankKeeper.EXPECT().BlockedAddr(to1Addr).Return(true) + s.accountKeeper.SetAccount(s.ctx, toAcc) + }, + input: vestingtypes.NewMsgCreatePermanentLockedAccount( + fromAddr, + to1Addr, + sdk.Coins{fooCoin}, + ), + expErr: true, + expErrMsg: "not allowed to receive funds", + }, + "create a valid permanent locked account": { preRun: func() { s.bankKeeper.EXPECT().IsSendEnabledCoins(gomock.Any(), fooCoin).Return(nil) @@ -181,7 +285,10 @@ func (s *VestingTestSuite) TestCreatePermanentLockedAccount() { for name, tc := range testCases { s.Run(name, func() { - tc.preRun() + if tc.preRun != nil { + tc.preRun() + } + _, err := s.msgServer.CreatePermanentLockedAccount(s.ctx, tc.input) if tc.expErr { s.Require().Error(err) @@ -201,9 +308,90 @@ func (s *VestingTestSuite) TestCreatePeriodicVestingAccount() { expErr bool expErrMsg string }{ + { + name: "empty from address", + input: vestingtypes.NewMsgCreatePeriodicVestingAccount( + []byte{}, + to1Addr, + time.Now().Unix(), + []vestingtypes.Period{ + { + Length: 10, + Amount: sdk.NewCoins(periodCoin), + }, + }, + ), + expErr: true, + expErrMsg: "invalid 'from' address", + }, + { + name: "empty to address", + input: vestingtypes.NewMsgCreatePeriodicVestingAccount( + fromAddr, + []byte{}, + time.Now().Unix(), + []vestingtypes.Period{ + { + Length: 10, + Amount: sdk.NewCoins(periodCoin), + }, + }, + ), + expErr: true, + expErrMsg: "invalid 'to' address", + }, + { + name: "invalid start time", + input: vestingtypes.NewMsgCreatePeriodicVestingAccount( + fromAddr, + to1Addr, + 0, + []vestingtypes.Period{ + { + Length: 10, + Amount: sdk.NewCoins(periodCoin), + }, + }, + ), + expErr: true, + expErrMsg: "invalid start time", + }, + { + name: "invalid period", + input: vestingtypes.NewMsgCreatePeriodicVestingAccount( + fromAddr, + to1Addr, + time.Now().Unix(), + []vestingtypes.Period{ + { + Length: 0, + Amount: sdk.NewCoins(periodCoin), + }, + }, + ), + expErr: true, + expErrMsg: "invalid period", + }, + { + name: "invalid coins", + input: vestingtypes.NewMsgCreatePeriodicVestingAccount( + fromAddr, + to1Addr, + time.Now().Unix(), + []vestingtypes.Period{ + { + Length: 1, + Amount: sdk.Coins{sdk.Coin{Denom: "stake", Amount: math.NewInt(-1)}}, + }, + }, + ), + expErr: true, + expErrMsg: "-1stake: invalid coins", + }, { name: "create for existing account", preRun: func() { + s.bankKeeper.EXPECT().BlockedAddr(to1Addr).Return(false) toAcc := s.accountKeeper.NewAccountWithAddress(s.ctx, to1Addr) s.accountKeeper.SetAccount(s.ctx, toAcc) }, @@ -221,10 +409,34 @@ func (s *VestingTestSuite) TestCreatePeriodicVestingAccount() { expErr: true, expErrMsg: "already exists", }, + { + name: "create for blocked address", + preRun: func() { + s.bankKeeper.EXPECT().BlockedAddr(to2Addr).Return(true) + }, + input: vestingtypes.NewMsgCreatePeriodicVestingAccount( + fromAddr, + to2Addr, + time.Now().Unix(), + []vestingtypes.Period{ + { + Length: 10, + Amount: sdk.NewCoins(periodCoin), + }, + { + Length: 20, + Amount: sdk.NewCoins(fooCoin), + }, + }, + ), + expErr: true, + expErrMsg: "not allowed to receive funds", + }, { name: "create a valid periodic vesting account", preRun: func() { s.bankKeeper.EXPECT().IsSendEnabledCoins(gomock.Any(), periodCoin.Add(fooCoin)).Return(nil) + s.bankKeeper.EXPECT().BlockedAddr(to2Addr).Return(false) s.bankKeeper.EXPECT().SendCoins(gomock.Any(), fromAddr, to2Addr, gomock.Any()).Return(nil) }, input: vestingtypes.NewMsgCreatePeriodicVestingAccount( @@ -249,7 +461,9 @@ func (s *VestingTestSuite) TestCreatePeriodicVestingAccount() { for _, tc := range testCases { s.Run(tc.name, func() { - tc.preRun() + if tc.preRun != nil { + tc.preRun() + } _, err := s.msgServer.CreatePeriodicVestingAccount(s.ctx, tc.input) if tc.expErr { s.Require().Error(err) @@ -268,6 +482,61 @@ func (s *VestingTestSuite) TestCreateCliffVestingAccount() { expErr bool expErrMsg string }{ + "empty from address": { + input: vestingtypes.NewMsgCreateCliffVestingAccount( + []byte{}, + to1Addr, + sdk.Coins{fooCoin}, + time.Now().Add(24*time.Hour).Unix(), + time.Now().Add(12*time.Hour).Unix(), + ), + expErr: true, + expErrMsg: "invalid 'from' address", + }, + "empty to address": { + input: vestingtypes.NewMsgCreateCliffVestingAccount( + fromAddr, + []byte{}, + sdk.Coins{fooCoin}, + time.Now().Add(24*time.Hour).Unix(), + time.Now().Add(12*time.Hour).Unix(), + ), + expErr: true, + expErrMsg: "invalid 'to' address", + }, + "invalid coins": { + input: vestingtypes.NewMsgCreateCliffVestingAccount( + fromAddr, + to1Addr, + sdk.Coins{sdk.Coin{Denom: "stake", Amount: math.NewInt(-1)}}, + time.Now().Add(24*time.Hour).Unix(), + time.Now().Add(12*time.Hour).Unix(), + ), + expErr: true, + expErrMsg: "-1stake: invalid coins", + }, + "invalid end time": { + input: vestingtypes.NewMsgCreateCliffVestingAccount( + fromAddr, + to1Addr, + sdk.Coins{fooCoin}, + -10, + time.Now().Add(12*time.Hour).Unix(), + ), + expErr: true, + expErrMsg: "invalid end time", + }, + "invalid cliff time": { + input: vestingtypes.NewMsgCreateCliffVestingAccount( + fromAddr, + to1Addr, + sdk.Coins{fooCoin}, + time.Now().Add(12*time.Hour).Unix(), + -10, + ), + expErr: true, + expErrMsg: "invalid cliff time", + }, "create for existing account": { preRun: func() { toAcc := s.accountKeeper.NewAccountWithAddress(s.ctx, to1Addr) @@ -285,15 +554,30 @@ func (s *VestingTestSuite) TestCreateCliffVestingAccount() { expErr: true, expErrMsg: "already exists", }, + "create for blocked account": { + preRun: func() { + s.bankKeeper.EXPECT().IsSendEnabledCoins(gomock.Any(), fooCoin).Return(nil) + s.bankKeeper.EXPECT().BlockedAddr(to1Addr).Return(true) + }, + input: vestingtypes.NewMsgCreateCliffVestingAccount( + fromAddr, + to1Addr, + sdk.Coins{fooCoin}, + time.Now().Add(24*time.Hour).Unix(), + time.Now().Add(12*time.Hour).Unix(), + ), + expErr: true, + expErrMsg: "not allowed to receive funds", + }, "create a valid cliff vesting account": { preRun: func() { s.bankKeeper.EXPECT().IsSendEnabledCoins(gomock.Any(), fooCoin).Return(nil) - s.bankKeeper.EXPECT().BlockedAddr(to3Addr).Return(false) - s.bankKeeper.EXPECT().SendCoins(gomock.Any(), fromAddr, to3Addr, sdk.Coins{fooCoin}).Return(nil) + s.bankKeeper.EXPECT().BlockedAddr(to2Addr).Return(false) + s.bankKeeper.EXPECT().SendCoins(gomock.Any(), fromAddr, to2Addr, sdk.Coins{fooCoin}).Return(nil) }, input: vestingtypes.NewMsgCreateCliffVestingAccount( fromAddr, - to3Addr, + to2Addr, sdk.Coins{fooCoin}, time.Now().Add(24*time.Hour).Unix(), time.Now().Add(12*time.Hour).Unix(), @@ -305,7 +589,9 @@ func (s *VestingTestSuite) TestCreateCliffVestingAccount() { for name, tc := range testCases { s.Run(name, func() { - tc.preRun() + if tc.preRun != nil { + tc.preRun() + } _, err := s.msgServer.CreateCliffVestingAccount(s.ctx, tc.input) if tc.expErr { s.Require().Error(err) From d12c72d2aa6b6efec908ea4c1f4a222e924a5f73 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Thu, 16 May 2024 15:51:37 +0200 Subject: [PATCH 07/18] test(vesting): add vesting_account cliff tests --- x/vesting/types/vesting_account_test.go | 101 ++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/x/vesting/types/vesting_account_test.go b/x/vesting/types/vesting_account_test.go index 6a5e40d24..281f9795e 100644 --- a/x/vesting/types/vesting_account_test.go +++ b/x/vesting/types/vesting_account_test.go @@ -799,6 +799,107 @@ func TestTrackUndelegationPermLockedVestingAcc(t *testing.T) { require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}, plva.DelegatedVesting) } +func TestGetVestedCoinsCliffVestingAcc(t *testing.T) { + now := tmtime.Now() + cliffTime := now.Add(12 * time.Hour) + endTime := now.Add(24 * time.Hour) + + bacc, origCoins := initBaseAccount() + cva, err := types.NewCliffVestingAccount(bacc, origCoins, now.Unix(), cliffTime.Unix(), endTime.Unix()) + require.NoError(t, err) + + // require no coins vested before the cliff time + vestedCoins := cva.GetVestedCoins(now.Add(6 * time.Hour)) + 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 no coins vested at cliff time + vestedCoins = cva.GetVestedCoins(cliffTime) + require.Nil(t, vestedCoins) + + // require 75% of coins vested + vestedCoins = cva.GetVestedCoins(now.Add(18 * time.Hour)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 750), sdk.NewInt64Coin(stakeDenom, 75)}, vestedCoins) + + // require all coins vested after end time + vestedCoins = cva.GetVestedCoins(endTime.Add(48 * time.Hour)) + require.Equal(t, origCoins, vestedCoins) +} + +func TestGetVestingCoinsCliffVestingAcc(t *testing.T) { + now := tmtime.Now() + cliffTime := now.Add(12 * time.Hour) + endTime := now.Add(24 * time.Hour) + + bacc, origCoins := initBaseAccount() + cva, err := types.NewCliffVestingAccount(bacc, origCoins, now.Unix(), cliffTime.Unix(), endTime.Unix()) + require.NoError(t, err) + + // require all coins vesting before the cliff time + vestingCoins := cva.GetVestingCoins(now.Add(6 * time.Hour)) + require.Equal(t, origCoins, vestingCoins) + + // require all coins vesting at cliff time + vestingCoins = cva.GetVestingCoins(cliffTime) + require.Equal(t, origCoins, vestingCoins) + + // require no coins vesting at the end of the vesting schedule + vestingCoins = cva.GetVestingCoins(endTime) + require.Equal(t, emptyCoins, vestingCoins) + + // require 25% of coins vesting + vestingCoins = cva.GetVestingCoins(now.Add(18 * time.Hour)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}, vestingCoins) +} + +func TestTrackDelegationCliffVestingAcc(t *testing.T) { + now := tmtime.Now() + cliffTime := now.Add(12 * time.Hour) + endTime := now.Add(24 * time.Hour) + + bacc, origCoins := initBaseAccount() + + // require the ability to delegate all vesting coins + cva, err := types.NewCliffVestingAccount(bacc, origCoins, now.Unix(), cliffTime.Unix(), endTime.Unix()) + require.NoError(t, err) + cva.TrackDelegation(now, origCoins, origCoins) + require.Equal(t, origCoins, cva.DelegatedVesting) + require.Nil(t, cva.DelegatedFree) + + // require the ability to delegate all vested coins + cva, err = types.NewCliffVestingAccount(bacc, origCoins, now.Unix(), cliffTime.Unix(), endTime.Unix()) + require.NoError(t, err) + cva.TrackDelegation(endTime, origCoins, origCoins) + require.Nil(t, cva.DelegatedVesting) + require.Equal(t, origCoins, cva.DelegatedFree) + + // require the ability to delegate all coins before the cliff time + cva, err = types.NewCliffVestingAccount(bacc, origCoins, now.Unix(), cliffTime.Unix(), endTime.Unix()) + require.NoError(t, err) + cva.TrackDelegation(now.Add(6*time.Hour), origCoins, origCoins) + require.Equal(t, origCoins, cva.DelegatedVesting) + require.Nil(t, cva.DelegatedFree) + + // require the ability to delegate 25 % coins after 75% of vesting coins + cva, err = types.NewCliffVestingAccount(bacc, origCoins, now.Unix(), cliffTime.Unix(), endTime.Unix()) + require.NoError(t, err) + cva.TrackDelegation(now.Add(18*time.Hour), origCoins, origCoins) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}, cva.DelegatedVesting) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 750), sdk.NewInt64Coin(stakeDenom, 75)}, cva.DelegatedFree) + + // require no modifications when delegation amount is zero or not enough funds + cva, err = types.NewCliffVestingAccount(bacc, origCoins, now.Unix(), cliffTime.Unix(), endTime.Unix()) + require.NoError(t, err) + require.Panics(t, func() { + cva.TrackDelegation(endTime, origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 1000000)}) + }) + require.Nil(t, cva.DelegatedVesting) + require.Nil(t, cva.DelegatedFree) +} + func TestGenesisAccountValidate(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) From 0aa79f61d2e65324be2866c7ab42842dc2976197 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Thu, 16 May 2024 16:20:12 +0200 Subject: [PATCH 08/18] test(vesting): add vesting_account test for cliff undelegation --- x/vesting/types/vesting_account_test.go | 50 +++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/x/vesting/types/vesting_account_test.go b/x/vesting/types/vesting_account_test.go index 281f9795e..e51852dc1 100644 --- a/x/vesting/types/vesting_account_test.go +++ b/x/vesting/types/vesting_account_test.go @@ -900,6 +900,56 @@ func TestTrackDelegationCliffVestingAcc(t *testing.T) { require.Nil(t, cva.DelegatedFree) } +func TestTrackUndelegationCliffVestingAcc(t *testing.T) { + now := tmtime.Now() + cliffTime := now.Add(12 * time.Hour) + endTime := now.Add(24 * time.Hour) + + bacc, origCoins := initBaseAccount() + + // require the ability to undelegate all vesting coins + cva, err := types.NewCliffVestingAccount(bacc, origCoins, now.Unix(), cliffTime.Unix(), endTime.Unix()) + require.NoError(t, err) + cva.TrackDelegation(now, origCoins, origCoins) + cva.TrackUndelegation(origCoins) + require.Nil(t, cva.DelegatedFree) + require.Equal(t, emptyCoins, cva.DelegatedVesting) + + // require the ability to undelegate all vested coins at endTime + cva, err = types.NewCliffVestingAccount(bacc, origCoins, now.Unix(), cliffTime.Unix(), endTime.Unix()) + require.NoError(t, err) + cva.TrackDelegation(endTime, origCoins, origCoins) + cva.TrackUndelegation(origCoins) + require.Equal(t, emptyCoins, cva.DelegatedFree) + require.Nil(t, cva.DelegatedVesting) + + // require no modifications when the undelegation amount is zero + cva, err = types.NewCliffVestingAccount(bacc, origCoins, now.Unix(), cliffTime.Unix(), endTime.Unix()) + require.NoError(t, err) + require.Panics(t, func() { + cva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 0)}) + }) + require.Nil(t, cva.DelegatedFree) + require.Nil(t, cva.DelegatedVesting) + + // vest 50% and delegate to two validators + cva, err = types.NewCliffVestingAccount(bacc, origCoins, now.Unix(), cliffTime.Unix(), endTime.Unix()) + require.NoError(t, err) + cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + cva.TrackDelegation(now.Add(12*time.Hour), origCoins, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + + // undelegate from one validator that got slashed 50% + cva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}) + + require.Nil(t, cva.DelegatedFree) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 75)}, cva.DelegatedVesting) + + // undelegate from the other validator that did not get slashed + cva.TrackUndelegation(sdk.Coins{sdk.NewInt64Coin(stakeDenom, 50)}) + require.Nil(t, cva.DelegatedFree) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}, cva.DelegatedVesting) +} + func TestGenesisAccountValidate(t *testing.T) { pubkey := secp256k1.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) From f00b7bb5405a9c3b3fbfdd617ddc8063155d007e Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Thu, 16 May 2024 16:32:30 +0200 Subject: [PATCH 09/18] test(vesting): add vesting_account test for cliff spendable coins --- x/vesting/types/vesting_account_test.go | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/x/vesting/types/vesting_account_test.go b/x/vesting/types/vesting_account_test.go index e51852dc1..cb85a2130 100644 --- a/x/vesting/types/vesting_account_test.go +++ b/x/vesting/types/vesting_account_test.go @@ -855,6 +855,36 @@ func TestGetVestingCoinsCliffVestingAcc(t *testing.T) { require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}, vestingCoins) } +func TestSpendableCoinsCliffVestingAcc(t *testing.T) { + now := tmtime.Now() + cliffTime := now.Add(12 * time.Hour) + endTime := now.Add(24 * time.Hour) + + bacc, origCoins := initBaseAccount() + cva, err := types.NewCliffVestingAccount(bacc, origCoins, now.Unix(), cliffTime.Unix(), endTime.Unix()) + require.NoError(t, err) + + // require all coins are locked at the beginning of the vesting schedule + lockedCoins := cva.LockedCoins(now) + require.Equal(t, origCoins, lockedCoins) + + // require all coins are locked before the cliff time but after the beginning + lockedCoins = cva.LockedCoins(now.Add(6 * time.Hour)) + require.Equal(t, origCoins, lockedCoins) + + // require no coins are locked at the end of the vesting schedule + lockedCoins = cva.LockedCoins(endTime) + require.Equal(t, sdk.NewCoins(), lockedCoins) + + // require 50% of coins are locked at the cliff time + lockedCoins = cva.LockedCoins(cliffTime.Add(1 * time.Second)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, lockedCoins) + + // require 25% of coins are locked + lockedCoins = cva.LockedCoins(now.Add(18 * time.Hour)) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 250), sdk.NewInt64Coin(stakeDenom, 25)}, lockedCoins) +} + func TestTrackDelegationCliffVestingAcc(t *testing.T) { now := tmtime.Now() cliffTime := now.Add(12 * time.Hour) From c018447c95832720e419282c7695d0655765a775 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Thu, 16 May 2024 16:53:33 +0200 Subject: [PATCH 10/18] fix(vesting): format and lint --- x/vesting/client/cli/tx_test.go | 4 ++-- x/vesting/msg_server_test.go | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/x/vesting/client/cli/tx_test.go b/x/vesting/client/cli/tx_test.go index 2b53819d5..07b60100a 100644 --- a/x/vesting/client/cli/tx_test.go +++ b/x/vesting/client/cli/tx_test.go @@ -7,9 +7,10 @@ import ( "testing" "time" - rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock" "github.com/stretchr/testify/suite" + rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock" + sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/client" @@ -124,7 +125,6 @@ func (s *CLITestSuite) TestNewMsgCreateVestingAccountCmd() { ctx := svrcmd.CreateExecuteContext(context.Background()) cmd.SetContext(ctx) - fmt.Println(tc.amount.String()) cmd.SetArgs(append([]string{tc.to.String(), tc.amount.String(), fmt.Sprint(tc.endTime)}, tc.extraArgs...)) s.Require().NoError(client.SetCmdClientContextHandler(tc.ctxGen(), cmd)) diff --git a/x/vesting/msg_server_test.go b/x/vesting/msg_server_test.go index 26c29426b..644f4d296 100644 --- a/x/vesting/msg_server_test.go +++ b/x/vesting/msg_server_test.go @@ -1,15 +1,16 @@ package vesting_test import ( - "cosmossdk.io/math" - cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" - cmttime "github.com/cometbft/cometbft/types/time" "testing" "time" "github.com/golang/mock/gomock" "github.com/stretchr/testify/suite" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + cmttime "github.com/cometbft/cometbft/types/time" + + "cosmossdk.io/math" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/runtime" From fde166cda8dec105b958a4f2ba4b5f1a15284b34 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Fri, 17 May 2024 10:10:48 +0200 Subject: [PATCH 11/18] fix(docs): generate docs with module subfolder on proto --- Makefile | 2 +- docs/proto/vesting.md | 8 ++++---- proto/buf.gen.doc.yml | 2 +- scripts/protocgen-doc.sh | 5 +++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 2a732d6d5..5ae635bfa 100644 --- a/Makefile +++ b/Makefile @@ -319,7 +319,7 @@ doc: doc-proto doc-command doc-predicate ## Generate all the documentation doc-proto: proto-gen ## Generate the documentation from the Protobuf files @echo "${COLOR_CYAN} 📝 Generating doc from Protobuf files${COLOR_RESET}" @$(DOCKER_PROTO_RUN) sh ./scripts/protocgen-doc.sh - @for MODULE in $(shell find proto -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq | xargs dirname) ; do \ + @for MODULE in $(shell find proto -name '*.proto' -maxdepth 3 -print0 | xargs -0 -n1 dirname | sort | uniq | xargs dirname) ; do \ echo "${COLOR_CYAN} 📖 Generate documentation for $${MODULE} module${COLOR_RESET}" ; \ DEFAULT_DATASOURCE="./docs/proto/templates/default.yaml" ; \ MODULE_DATASOURCE="merge:./$${MODULE}/docs.yaml|$${DEFAULT_DATASOURCE}" ; \ diff --git a/docs/proto/vesting.md b/docs/proto/vesting.md index d428f2b76..ed1c14fd4 100644 --- a/docs/proto/vesting.md +++ b/docs/proto/vesting.md @@ -60,7 +60,7 @@ continuously vests by unlocking coins after a cliff period linearly with respect | ----- | ---- | ----- | ----------- | | `base_vesting_account` | [BaseVestingAccount](#vesting.v1beta1.BaseVestingAccount) | | base_vesting_account implements the VestingAccount interface. It contains all the necessary fields needed for any vesting account implementation | | `start_time` | [int64](#int64) | | start_time defines the time at which the vesting period begins | -| `cliff_time` | [int64](#int64) | | | +| `cliff_time` | [int64](#int64) | | cliff_time defines the time at which the first portion of the vesting is unlocked | @@ -94,7 +94,7 @@ Period defines a length of time and amount of coins that will vest. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `length` | [int64](#int64) | | | +| `length` | [int64](#int64) | | Period duration in seconds. | | `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | | @@ -150,7 +150,7 @@ account. | `to_address` | [string](#string) | | | | `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | | | `end_time` | [int64](#int64) | | | -| `cliff_time` | [int64](#int64) | | | +| `cliff_time` | [int64](#int64) | | cliff time as unix time (in seconds) is the time at which the first portion of the vesting is unlocked. | @@ -218,7 +218,7 @@ account. | `from_address` | [string](#string) | | | | `to_address` | [string](#string) | | | | `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | | -| `end_time` | [int64](#int64) | | | +| `end_time` | [int64](#int64) | | end of vesting as unix time (in seconds). | | `delayed` | [bool](#bool) | | | diff --git a/proto/buf.gen.doc.yml b/proto/buf.gen.doc.yml index ec865c626..9dee9f81c 100644 --- a/proto/buf.gen.doc.yml +++ b/proto/buf.gen.doc.yml @@ -4,4 +4,4 @@ plugins: - name: doc out: ../docs/proto opt: - - ../docs/proto/templates/protodoc-markdown.tmpl,docs.md + - ../docs/proto/templates/protodoc-markdown.tmpl,docs.md:module/* diff --git a/scripts/protocgen-doc.sh b/scripts/protocgen-doc.sh index 0c254e6bd..820b8e676 100755 --- a/scripts/protocgen-doc.sh +++ b/scripts/protocgen-doc.sh @@ -11,7 +11,8 @@ protoc_install_proto_gen_doc echo "Generating proto docs" cd proto -for MODULE in $(find . -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq | xargs -n1 dirname); do +for MODULE in $(find . -name '*.proto' -maxdepth 3 -print0 | xargs -0 -n1 dirname | sort | uniq | xargs -n1 dirname); do + echo "Generating docs for ${MODULE}" buf generate --path "${MODULE}" --template buf.gen.doc.yml -v - mv ../docs/proto/docs.md ../docs/proto/"${MODULE}".md + mv -f ../docs/proto/docs.md ../docs/proto/"${MODULE}".md done From e1b01158a485da1c8ac8b15ce18f6d98e91ac289 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Fri, 17 May 2024 10:11:15 +0200 Subject: [PATCH 12/18] build: align cosmos-sdk buf proto version with chain version --- proto/buf.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto/buf.yaml b/proto/buf.yaml index 32c51a85f..b4b143c0a 100644 --- a/proto/buf.yaml +++ b/proto/buf.yaml @@ -1,7 +1,7 @@ version: v1 name: buf.build/axone-protocol/axoned deps: - - buf.build/cosmos/cosmos-sdk:v0.50.1 + - buf.build/cosmos/cosmos-sdk:v0.50.4 - buf.build/cosmos/cosmos-proto - buf.build/cosmos/gogo-proto - buf.build/googleapis/googleapis From 52a40079bd8ade3f9846626c01e5078cf5831bc8 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Fri, 17 May 2024 15:52:27 +0200 Subject: [PATCH 13/18] docs(vesting): update commands docs --- docs/command/axoned_tx_vesting_create-cliff-vesting-account.md | 2 +- .../axoned_tx_vesting_create-periodic-vesting-account.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/command/axoned_tx_vesting_create-cliff-vesting-account.md b/docs/command/axoned_tx_vesting_create-cliff-vesting-account.md index 98e845fd7..141b5e2aa 100644 --- a/docs/command/axoned_tx_vesting_create-cliff-vesting-account.md +++ b/docs/command/axoned_tx_vesting_create-cliff-vesting-account.md @@ -4,7 +4,7 @@ Create a new vesting account funded with an allocation of tokens with cliff. ### Synopsis -Create a new vesting account funded with an allocation of tokens. The +Create a new vesting account funded with an allocation of tokens with cliff. The tokens allowed will be start vested but the token will be released only after the cliff time. All vesting accounts created will have their start time set by the committed block's time. The end_time and cliff_time must be provided as a UNIX epoch diff --git a/docs/command/axoned_tx_vesting_create-periodic-vesting-account.md b/docs/command/axoned_tx_vesting_create-periodic-vesting-account.md index 864eab3f1..3f36d9b67 100644 --- a/docs/command/axoned_tx_vesting_create-periodic-vesting-account.md +++ b/docs/command/axoned_tx_vesting_create-periodic-vesting-account.md @@ -9,7 +9,7 @@ A sequence of coins and period length in seconds. Periods are sequential, in tha An array of coin strings and unix epoch times for coins to vest \{ "start_time": 1625204910, -"period":[ +"periods":[ \{ "coins": "10test", "length_seconds":2592000 //30 days From 4b4bafbc61a8d2ffb46fa1a4ca28eb35435b0d70 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Fri, 17 May 2024 15:54:38 +0200 Subject: [PATCH 14/18] fix(vesting): reintroduce the add-genesis-account custom command to include cliff vesting account --- cmd/axoned/cmd/genaccount.go | 105 +++++++++++++++++++++ cmd/axoned/cmd/genaccount_test.go | 116 +++++++++++++++++++++++ cmd/axoned/cmd/root.go | 9 ++ x/vesting/types/genaccounts.go | 149 ++++++++++++++++++++++++++++++ 4 files changed, 379 insertions(+) create mode 100644 cmd/axoned/cmd/genaccount.go create mode 100644 cmd/axoned/cmd/genaccount_test.go create mode 100644 x/vesting/types/genaccounts.go diff --git a/cmd/axoned/cmd/genaccount.go b/cmd/axoned/cmd/genaccount.go new file mode 100644 index 000000000..a1c7c6ee2 --- /dev/null +++ b/cmd/axoned/cmd/genaccount.go @@ -0,0 +1,105 @@ +package cmd + +import ( + "bufio" + "fmt" + + "github.com/spf13/cobra" + + address "cosmossdk.io/core/address" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/server" + sdk "github.com/cosmos/cosmos-sdk/types" + + vestingtypes "github.com/axone-protocol/axoned/v7/x/vesting/types" +) + +const ( + flagVestingStart = "vesting-start-time" + flagVestingCliff = "vesting-cliff-time" + flagVestingEnd = "vesting-end-time" + flagVestingAmt = "vesting-amount" + flagAppendMode = "append" + flagModuleName = "module-name" +) + +// AddGenesisAccountCmd returns add-genesis-account cobra Command. +// This command is provided as a default, applications are expected to provide their own command if custom genesis accounts are needed. +// +//nolint:funlen,nestif +func AddGenesisAccountCmd(defaultNodeHome string, addressCodec address.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]", + Short: "Add a genesis account to genesis.json", + Long: `Add a genesis account to genesis.json. The provided account must specify +the account address or key name and a list of initial coins. If a key name is given, +the address will be looked up in the local Keybase. The list of initial tokens must +contain valid denominations. Accounts may optionally be supplied with vesting parameters. +`, + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + serverCtx := server.GetServerContextFromCmd(cmd) + config := serverCtx.Config + + config.SetRoot(clientCtx.HomeDir) + + var kr keyring.Keyring + addr, err := addressCodec.StringToBytes(args[0]) + if err != nil { + inBuf := bufio.NewReader(cmd.InOrStdin()) + keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) + + if keyringBackend != "" && clientCtx.Keyring == nil { + var err error + kr, err = keyring.New(sdk.KeyringServiceName(), keyringBackend, clientCtx.HomeDir, inBuf, clientCtx.Codec) + if err != nil { + return err + } + } else { + kr = clientCtx.Keyring + } + + k, err := kr.Key(args[0]) + if err != nil { + return fmt.Errorf("failed to get address from Keyring: %w", err) + } + + addr, err = k.GetAddress() + if err != nil { + return err + } + } + + appendflag, _ := cmd.Flags().GetBool(flagAppendMode) + vestingStart, _ := cmd.Flags().GetInt64(flagVestingStart) + vestingCliff, _ := cmd.Flags().GetInt64(flagVestingCliff) + vestingEnd, _ := cmd.Flags().GetInt64(flagVestingEnd) + vestingAmtStr, _ := cmd.Flags().GetString(flagVestingAmt) + moduleNameStr, _ := cmd.Flags().GetString(flagModuleName) + + return vestingtypes.AddGenesisAccount(clientCtx.Codec, + addr, + appendflag, + config.GenesisFile(), + args[1], + vestingAmtStr, vestingStart, vestingCliff, vestingEnd, + moduleNameStr) + }, + } + + cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory") + cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)") + cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts") + cmd.Flags().Int64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts") + cmd.Flags().Int64(flagVestingCliff, 0, "schedule cliff time (unix epoch) for vesting accounts") + cmd.Flags().Int64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts") + cmd.Flags().Bool(flagAppendMode, false, "append the coins to an account already in the genesis.json file") + cmd.Flags().String(flagModuleName, "", "module account name") + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/cmd/axoned/cmd/genaccount_test.go b/cmd/axoned/cmd/genaccount_test.go new file mode 100644 index 000000000..45d33ba23 --- /dev/null +++ b/cmd/axoned/cmd/genaccount_test.go @@ -0,0 +1,116 @@ +package cmd_test + +import ( + "context" + "fmt" + "testing" + + "github.com/spf13/viper" + "github.com/stretchr/testify/require" + + "cosmossdk.io/log" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + addresscodec "github.com/cosmos/cosmos-sdk/codec/address" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/server" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + genutiltest "github.com/cosmos/cosmos-sdk/x/genutil/client/testutil" + "github.com/cosmos/cosmos-sdk/x/staking" +) + +var testMbm = module.NewBasicManager( + staking.AppModuleBasic{}, + genutil.AppModuleBasic{}, +) + +func TestAddGenesisAccountCmd(t *testing.T) { + _, _, addr1 := testdata.KeyTestPubAddr() + tests := []struct { + name string + addr string + denom string + withKeyring bool + expectErr bool + }{ + { + name: "invalid address", + addr: "", + denom: "1000atom", + withKeyring: false, + expectErr: true, + }, + { + name: "valid address", + addr: addr1.String(), + denom: "1000atom", + withKeyring: false, + expectErr: false, + }, + { + name: "multiple denoms", + addr: addr1.String(), + denom: "1000atom, 2000stake", + withKeyring: false, + expectErr: false, + }, + { + name: "with keyring", + addr: "ser", + denom: "1000atom", + withKeyring: true, + expectErr: false, + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + home := t.TempDir() + logger := log.NewNopLogger() + cfg, err := genutiltest.CreateDefaultCometConfig(home) + require.NoError(t, err) + + appCodec := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}).Codec + err = genutiltest.ExecInitCmd(testMbm, home, appCodec) + require.NoError(t, err) + + serverCtx := server.NewContext(viper.New(), cfg, logger) + clientCtx := client.Context{}.WithCodec(appCodec).WithHomeDir(home) + + if tc.withKeyring { + path := hd.CreateHDPath(118, 0, 0).String() + kr, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, home, nil, appCodec) + require.NoError(t, err) + _, _, err = kr.NewMnemonic(tc.addr, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) + clientCtx = clientCtx.WithKeyring(kr) + } + + ctx := context.Background() + ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) + ctx = context.WithValue(ctx, server.ServerContextKey, serverCtx) + + cmd := genutilcli.AddGenesisAccountCmd(home, addresscodec.NewBech32Codec("cosmos")) + cmd.SetArgs([]string{ + tc.addr, + tc.denom, + fmt.Sprintf("--%s=home", flags.FlagHome), + }) + + if tc.expectErr { + require.Error(t, cmd.ExecuteContext(ctx)) + } else { + require.NoError(t, cmd.ExecuteContext(ctx)) + } + }) + } +} diff --git a/cmd/axoned/cmd/root.go b/cmd/axoned/cmd/root.go index 56687817c..20f5ffc06 100644 --- a/cmd/axoned/cmd/root.go +++ b/cmd/axoned/cmd/root.go @@ -196,9 +196,18 @@ func initRootCmd( func genesisCommand(txConfig client.TxConfig, basicManager module.BasicManager, cmds ...*cobra.Command) *cobra.Command { cmd := genutilcli.Commands(txConfig, basicManager, app.DefaultNodeHome) + // Remove default `add-genesis-account` command and add our custom (integrating the cliff), + for _, command := range cmd.Commands() { + if command.Name() == "add-genesis-account" { + cmd.RemoveCommand(command) + } + } + cmd.AddCommand(AddGenesisAccountCmd(app.DefaultNodeHome, txConfig.SigningContext().AddressCodec())) + for _, subCmd := range cmds { cmd.AddCommand(subCmd) } + return cmd } diff --git a/x/vesting/types/genaccounts.go b/x/vesting/types/genaccounts.go new file mode 100644 index 000000000..d67a4705e --- /dev/null +++ b/x/vesting/types/genaccounts.go @@ -0,0 +1,149 @@ +package types + +import ( + "encoding/json" + "errors" + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" +) + +// AddGenesisAccount adds a genesis account to the genesis state. +// Where `cdc` is client codec, `genesisFileUrl` is the path/url of current genesis file, +// `accAddr` is the address to be added to the genesis state, `amountStr` is the list of initial coins +// to be added for the account, `appendAcct` updates the account if already exists. +// `vestingStart, vestingEnd and vestingAmtStr` respectively are the schedule start time, end time (unix epoch) +// `moduleName` is the module name for which the account is being created +// and coins to be appended to the account already in the genesis.json file. +// +//nolint:funlen,cyclop,nestif +func AddGenesisAccount( + cdc codec.Codec, + accAddr sdk.AccAddress, + appendAcct bool, + genesisFileURL, amountStr, vestingAmtStr string, + vestingStart, vestingCliff, vestingEnd int64, + moduleName string, +) error { + coins, err := sdk.ParseCoinsNormalized(amountStr) + if err != nil { + return fmt.Errorf("failed to parse coins: %w", err) + } + + vestingAmt, err := sdk.ParseCoinsNormalized(vestingAmtStr) + if err != nil { + return fmt.Errorf("failed to parse vesting amount: %w", err) + } + + // create concrete account type based on input parameters + var genAccount authtypes.GenesisAccount + + balances := banktypes.Balance{Address: accAddr.String(), Coins: coins.Sort()} + baseAccount := authtypes.NewBaseAccount(accAddr, nil, 0, 0) + + switch { + case !vestingAmt.IsZero(): + baseVestingAccount, err := NewBaseVestingAccount(baseAccount, vestingAmt.Sort(), vestingEnd) + if err != nil { + return fmt.Errorf("failed to create base vesting account: %w", err) + } + + if (balances.Coins.IsZero() && !baseVestingAccount.OriginalVesting.IsZero()) || + baseVestingAccount.OriginalVesting.IsAnyGT(balances.Coins) { + return errors.New("vesting amount cannot be greater than total amount") + } + + switch { + case vestingStart != 0 && vestingCliff != 0: + genAccount = NewCliffVestingAccountRaw(baseVestingAccount, vestingStart, vestingCliff) + + case vestingStart != 0 && vestingEnd != 0: + genAccount = NewContinuousVestingAccountRaw(baseVestingAccount, vestingStart) + + case vestingEnd != 0: + genAccount = NewDelayedVestingAccountRaw(baseVestingAccount) + + default: + return errors.New("invalid vesting parameters; must supply start and end time or end time") + } + case moduleName != "": + genAccount = authtypes.NewEmptyModuleAccount(moduleName, authtypes.Burner, authtypes.Minter) + default: + genAccount = baseAccount + } + + if err := genAccount.Validate(); err != nil { + return fmt.Errorf("failed to validate new genesis account: %w", err) + } + + appState, appGenesis, err := genutiltypes.GenesisStateFromGenFile(genesisFileURL) + if err != nil { + return fmt.Errorf("failed to unmarshal genesis state: %w", err) + } + + authGenState := authtypes.GetGenesisStateFromAppState(cdc, appState) + + accs, err := authtypes.UnpackAccounts(authGenState.Accounts) + if err != nil { + return fmt.Errorf("failed to get accounts from any: %w", err) + } + + bankGenState := banktypes.GetGenesisStateFromAppState(cdc, appState) + if accs.Contains(accAddr) { + if !appendAcct { + return fmt.Errorf(" Account %s already exists\nUse `append` flag to append account at existing address", accAddr) + } + + genesisB := banktypes.GetGenesisStateFromAppState(cdc, appState) + for idx, acc := range genesisB.Balances { + if acc.Address != accAddr.String() { + continue + } + + updatedCoins := acc.Coins.Add(coins...) + bankGenState.Balances[idx] = banktypes.Balance{Address: accAddr.String(), Coins: updatedCoins.Sort()} + break + } + } else { + // Add the new account to the set of genesis accounts and sanitize the accounts afterwards. + accs = append(accs, genAccount) + accs = authtypes.SanitizeGenesisAccounts(accs) + + genAccs, err := authtypes.PackAccounts(accs) + if err != nil { + return fmt.Errorf("failed to convert accounts into any's: %w", err) + } + authGenState.Accounts = genAccs + + authGenStateBz, err := cdc.MarshalJSON(&authGenState) + if err != nil { + return fmt.Errorf("failed to marshal auth genesis state: %w", err) + } + appState[authtypes.ModuleName] = authGenStateBz + + bankGenState.Balances = append(bankGenState.Balances, balances) + } + + bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances) + + bankGenState.Supply = bankGenState.Supply.Add(balances.Coins...) + + bankGenStateBz, err := cdc.MarshalJSON(bankGenState) + if err != nil { + return fmt.Errorf("failed to marshal bank genesis state: %w", err) + } + appState[banktypes.ModuleName] = bankGenStateBz + + appStateJSON, err := json.Marshal(appState) + if err != nil { + return fmt.Errorf("failed to marshal application genesis state: %w", err) + } + + appGenesis.AppState = appStateJSON + return genutil.ExportGenesisFile(appGenesis, genesisFileURL) +} From 92479e8f8412b86d5113157041f0e0b405bcd892 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Fri, 17 May 2024 15:56:49 +0200 Subject: [PATCH 15/18] docs(vesting): include the cliff command in docs --- docs/command/axoned_genesis_add-genesis-account.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/command/axoned_genesis_add-genesis-account.md b/docs/command/axoned_genesis_add-genesis-account.md index 5e188bd36..4fd2e0c50 100644 --- a/docs/command/axoned_genesis_add-genesis-account.md +++ b/docs/command/axoned_genesis_add-genesis-account.md @@ -27,6 +27,7 @@ axoned genesis add-genesis-account [address_or_key_name] [coin][,[coin]] [flags] --node string : to CometBFT RPC interface for this chain (default "tcp://localhost:26657") -o, --output string Output format (text|json) (default "text") --vesting-amount string amount of coins for vesting accounts + --vesting-cliff-time int schedule cliff time (unix epoch) for vesting accounts --vesting-end-time int schedule end time (unix epoch) for vesting accounts --vesting-start-time int schedule start time (unix epoch) for vesting accounts ``` From 9c48d27bde87bb2e015561152c05902c0f15cc65 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX <33665639+bdeneux@users.noreply.github.com> Date: Tue, 4 Jun 2024 17:12:56 +0200 Subject: [PATCH 16/18] chore: reset cosmos-sdk buf dependencies to 0.50.0 --- proto/buf.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto/buf.yaml b/proto/buf.yaml index b4b143c0a..64f59b7cc 100644 --- a/proto/buf.yaml +++ b/proto/buf.yaml @@ -1,7 +1,7 @@ version: v1 name: buf.build/axone-protocol/axoned deps: - - buf.build/cosmos/cosmos-sdk:v0.50.4 + - buf.build/cosmos/cosmos-sdk:v0.50.0 - buf.build/cosmos/cosmos-proto - buf.build/cosmos/gogo-proto - buf.build/googleapis/googleapis From f14c0e5055792e7b4e2d6c233c2f721291bd3806 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Tue, 4 Jun 2024 17:36:26 +0200 Subject: [PATCH 17/18] chore: use axoned v8 for vesting module --- cmd/axoned/cmd/genaccount.go | 2 +- x/vesting/client/cli/tx_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/axoned/cmd/genaccount.go b/cmd/axoned/cmd/genaccount.go index a1c7c6ee2..20b44c55c 100644 --- a/cmd/axoned/cmd/genaccount.go +++ b/cmd/axoned/cmd/genaccount.go @@ -14,7 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" - vestingtypes "github.com/axone-protocol/axoned/v7/x/vesting/types" + vestingtypes "github.com/axone-protocol/axoned/v8/x/vesting/types" ) const ( diff --git a/x/vesting/client/cli/tx_test.go b/x/vesting/client/cli/tx_test.go index 07b60100a..d3650ee39 100644 --- a/x/vesting/client/cli/tx_test.go +++ b/x/vesting/client/cli/tx_test.go @@ -23,8 +23,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" - "github.com/axone-protocol/axoned/v7/x/vesting" - "github.com/axone-protocol/axoned/v7/x/vesting/client/cli" + "github.com/axone-protocol/axoned/v8/x/vesting" + "github.com/axone-protocol/axoned/v8/x/vesting/client/cli" ) type CLITestSuite struct { From caca9a793828acf3940e5a4ee96d4ac7e56f3ad8 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Wed, 5 Jun 2024 14:23:11 +0200 Subject: [PATCH 18/18] ci: fix codecov by setting token --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 497a77c52..7f4783b72 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -57,6 +57,7 @@ jobs: env_vars: OS,GOLANG fail_ci_if_error: false verbose: true + token: ${{ secrets.CODECOV_TOKEN }} test-blockchain: runs-on: ubuntu-22.04