Skip to content

Commit

Permalink
Merge pull request #54 from agoric-labs/zaki-periodic-vesting-msg-alpha
Browse files Browse the repository at this point in the history
Add a msg for create PeriodicVestingAccount
  • Loading branch information
zmanian authored Jun 21, 2021
2 parents 8cfa2c2 + 663cc47 commit 780f61c
Show file tree
Hide file tree
Showing 8 changed files with 697 additions and 99 deletions.
144 changes: 82 additions & 62 deletions docs/core/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -568,12 +568,6 @@

- [Query](#cosmos.upgrade.v1beta1.Query)

- [cosmos/vesting/v1beta1/tx.proto](#cosmos/vesting/v1beta1/tx.proto)
- [MsgCreateVestingAccount](#cosmos.vesting.v1beta1.MsgCreateVestingAccount)
- [MsgCreateVestingAccountResponse](#cosmos.vesting.v1beta1.MsgCreateVestingAccountResponse)

- [Msg](#cosmos.vesting.v1beta1.Msg)

- [cosmos/vesting/v1beta1/vesting.proto](#cosmos/vesting/v1beta1/vesting.proto)
- [BaseVestingAccount](#cosmos.vesting.v1beta1.BaseVestingAccount)
- [ContinuousVestingAccount](#cosmos.vesting.v1beta1.ContinuousVestingAccount)
Expand All @@ -582,6 +576,13 @@
- [PeriodicVestingAccount](#cosmos.vesting.v1beta1.PeriodicVestingAccount)
- [PermanentLockedAccount](#cosmos.vesting.v1beta1.PermanentLockedAccount)

- [cosmos/vesting/v1beta1/tx.proto](#cosmos/vesting/v1beta1/tx.proto)
- [MsgCreatePeriodicVestingAccount](#cosmos.vesting.v1beta1.MsgCreatePeriodicVestingAccount)
- [MsgCreateVestingAccount](#cosmos.vesting.v1beta1.MsgCreateVestingAccount)
- [MsgCreateVestingAccountResponse](#cosmos.vesting.v1beta1.MsgCreateVestingAccountResponse)

- [Msg](#cosmos.vesting.v1beta1.Msg)

- [Scalar Value Types](#scalar-value-types)


Expand Down Expand Up @@ -8008,62 +8009,6 @@ Query defines the gRPC upgrade querier service.



<a name="cosmos/vesting/v1beta1/tx.proto"></a>
<p align="right"><a href="#top">Top</a></p>

## cosmos/vesting/v1beta1/tx.proto



<a name="cosmos.vesting.v1beta1.MsgCreateVestingAccount"></a>

### MsgCreateVestingAccount
MsgCreateVestingAccount defines a message that enables creating a vesting
account.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `from_address` | [string](#string) | | |
| `to_address` | [string](#string) | | |
| `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | |
| `end_time` | [int64](#int64) | | |
| `delayed` | [bool](#bool) | | |






<a name="cosmos.vesting.v1beta1.MsgCreateVestingAccountResponse"></a>

### MsgCreateVestingAccountResponse
MsgCreateVestingAccountResponse defines the Msg/CreateVestingAccount response type.





<!-- end messages -->

<!-- end enums -->

<!-- end HasExtensions -->


<a name="cosmos.vesting.v1beta1.Msg"></a>

### Msg
Msg defines the bank Msg service.

| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `CreateVestingAccount` | [MsgCreateVestingAccount](#cosmos.vesting.v1beta1.MsgCreateVestingAccount) | [MsgCreateVestingAccountResponse](#cosmos.vesting.v1beta1.MsgCreateVestingAccountResponse) | CreateVestingAccount defines a method that enables creating a vesting account. | |

<!-- end services -->



<a name="cosmos/vesting/v1beta1/vesting.proto"></a>
<p align="right"><a href="#top">Top</a></p>

Expand Down Expand Up @@ -8185,6 +8130,81 @@ still be used for delegating and for governance votes even while locked.



<a name="cosmos/vesting/v1beta1/tx.proto"></a>
<p align="right"><a href="#top">Top</a></p>

## cosmos/vesting/v1beta1/tx.proto



<a name="cosmos.vesting.v1beta1.MsgCreatePeriodicVestingAccount"></a>

### MsgCreatePeriodicVestingAccount
MsgCreateVestingAccount defines a message that enables creating a vesting
account.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `from_address` | [string](#string) | | |
| `to_address` | [string](#string) | | |
| `vesting_periods` | [Period](#cosmos.vesting.v1beta1.Period) | repeated | |






<a name="cosmos.vesting.v1beta1.MsgCreateVestingAccount"></a>

### MsgCreateVestingAccount
MsgCreateVestingAccount defines a message that enables creating a vesting
account.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `from_address` | [string](#string) | | |
| `to_address` | [string](#string) | | |
| `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | |
| `end_time` | [int64](#int64) | | |
| `delayed` | [bool](#bool) | | |






<a name="cosmos.vesting.v1beta1.MsgCreateVestingAccountResponse"></a>

### MsgCreateVestingAccountResponse
MsgCreateVestingAccountResponse defines the Msg/CreateVestingAccount response type.





<!-- end messages -->

<!-- end enums -->

<!-- end HasExtensions -->


<a name="cosmos.vesting.v1beta1.Msg"></a>

### Msg
Msg defines the bank Msg service.

| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `CreateVestingAccount` | [MsgCreateVestingAccount](#cosmos.vesting.v1beta1.MsgCreateVestingAccount) | [MsgCreateVestingAccountResponse](#cosmos.vesting.v1beta1.MsgCreateVestingAccountResponse) | CreateVestingAccount defines a method that enables creating a vesting account. | |
| `CreatePeriodicVestingAccount` | [MsgCreatePeriodicVestingAccount](#cosmos.vesting.v1beta1.MsgCreatePeriodicVestingAccount) | [MsgCreateVestingAccountResponse](#cosmos.vesting.v1beta1.MsgCreateVestingAccountResponse) | | |

<!-- end services -->



## Scalar Value Types

| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby |
Expand Down
15 changes: 14 additions & 1 deletion proto/cosmos/vesting/v1beta1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cosmos.vesting.v1beta1;

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

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

Expand All @@ -11,6 +12,7 @@ service Msg {
// CreateVestingAccount defines a method that enables creating a vesting
// account.
rpc CreateVestingAccount(MsgCreateVestingAccount) returns (MsgCreateVestingAccountResponse);
rpc CreatePeriodicVestingAccount(MsgCreatePeriodicVestingAccount) returns (MsgCreateVestingAccountResponse);
}

// MsgCreateVestingAccount defines a message that enables creating a vesting
Expand All @@ -28,4 +30,15 @@ message MsgCreateVestingAccount {
}

// MsgCreateVestingAccountResponse defines the Msg/CreateVestingAccount response type.
message MsgCreateVestingAccountResponse {}
message MsgCreateVestingAccountResponse {}


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

string from_address = 1 [(gogoproto.moretags) = "yaml:\"from_address\""];
string to_address = 2 [(gogoproto.moretags) = "yaml:\"to_address\""];
repeated Period vesting_periods = 3 [(gogoproto.nullable) = false];
}
85 changes: 85 additions & 0 deletions x/auth/vesting/client/cli/tx.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package cli

import (
"encoding/json"
"fmt"
"io/ioutil"
"strconv"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -29,6 +32,7 @@ func GetTxCmd() *cobra.Command {

txCmd.AddCommand(
NewMsgCreateVestingAccountCmd(),
NewMsgCreatePeriodicVestingAccountCmd(),
)

return txCmd
Expand Down Expand Up @@ -79,3 +83,84 @@ timestamp.`,

return cmd
}

type InputPeriod struct {
Coins string `json:"coins"`
Length int64 `json:"length_seconds"`
}

// NewMsgCreateVestingAccountCmd returns a CLI command handler for creating a
// MsgCreateVestingAccount transaction.
func NewMsgCreatePeriodicVestingAccountCmd() *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.",
Long: `A sequence of coins and period length in seconds. Periods are sequential, in that the duration of of a period only starts at the end of the previous period. The duration of the first period starts upon account creation. For instance, the following periods.json file shows 20 "test" coins vesting 30 days apart from each other.
Where periods.json contains:
An array of coin strings and unix epoch times for coins to vest
[
{
"coins": "10test",
"length_seconds":2592000 //30 days
},
{
"coins": "10test",
"length_seconds":2592000 //30 days
},
]
`,
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
toAddr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return err
}

contents, err := ioutil.ReadFile(args[1])
if err != nil {
return err
}

var inputPeriods []InputPeriod

err = json.Unmarshal(contents, inputPeriods)
if err != nil {
return err
}

var periods []types.Period

for i, p := range inputPeriods {

amount, err := sdk.ParseCoinsNormalized(p.Coins)
if err != nil {
return err
}

if p.Length < 1 {
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.Length, Amount: amount}
periods = append(periods, period)
}

msg := types.NewMsgCreatePeriodicVestingAccount(clientCtx.GetFromAddress(), toAddr, periods)
if err := msg.ValidateBasic(); err != nil {
return err
}

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

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

return cmd
}
46 changes: 46 additions & 0 deletions x/auth/vesting/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,52 @@ func (suite *HandlerTestSuite) TestMsgCreateVestingAccount() {
}
}

func (suite *HandlerTestSuite) TestMsgCreatePeriodicVestingAccount() {
ctx := suite.app.BaseApp.NewContext(false, tmproto.Header{Height: suite.app.LastBlockHeight() + 1})

balances := sdk.NewCoins(sdk.NewInt64Coin("test", 1000))
addr1 := sdk.AccAddress([]byte("addr1_______________"))
addr3 := sdk.AccAddress([]byte("addr3_______________"))

acc1 := suite.app.AccountKeeper.NewAccountWithAddress(ctx, addr1)

period := []types.Period{{Length: 5000, Amount: balances}}
suite.app.AccountKeeper.SetAccount(ctx, acc1)
suite.Require().NoError(suite.app.BankKeeper.SetBalances(ctx, addr1, balances))

testCases := []struct {
name string
msg *types.MsgCreatePeriodicVestingAccount
expectErr bool
}{
{
name: "continuous vesting account already exists",
msg: types.NewMsgCreatePeriodicVestingAccount(addr1, addr3, period),
expectErr: true,
},
}

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

suite.Run(tc.name, func() {
res, err := suite.handler(ctx, tc.msg)
if tc.expectErr {
suite.Require().Error(err)
} else {
suite.Require().NoError(err)
suite.Require().NotNil(res)

toAddr, err := sdk.AccAddressFromBech32(tc.msg.ToAddress)
suite.Require().NoError(err)
accI := suite.app.AccountKeeper.GetAccount(ctx, toAddr)
suite.Require().NotNil(accI)

}
})
}
}

func TestHandlerTestSuite(t *testing.T) {
suite.Run(t, new(HandlerTestSuite))
}
Loading

0 comments on commit 780f61c

Please sign in to comment.