Skip to content

Commit

Permalink
Draft changes to be able to add a start-time in the future for a cont…
Browse files Browse the repository at this point in the history
…inuous vesting acct
  • Loading branch information
liamsi committed Aug 31, 2023
1 parent 47309fa commit cbae35e
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 135 deletions.
241 changes: 150 additions & 91 deletions api/cosmos/vesting/v1beta1/tx.pulsar.go

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions proto/cosmos/vesting/v1beta1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ message MsgCreateVestingAccount {
// end of vesting as unix time (in seconds).
int64 end_time = 4;
bool delayed = 5;
// start of vesting as unix time (in seconds).
int64 start_time = 6;
}

// MsgCreateVestingAccountResponse defines the Msg/CreateVestingAccount response type.
Expand Down
10 changes: 8 additions & 2 deletions x/auth/vesting/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import (

// Transaction command flags
const (
FlagDelayed = "delayed"
FlagDelayed = "delayed"
FlagStartTime = "start-time"
)

// GetTxCmd returns vesting module's transaction commands.
Expand Down Expand Up @@ -79,13 +80,18 @@ timestamp.`,
}

delayed, _ := cmd.Flags().GetBool(FlagDelayed)
startTime, err := cmd.Flags().GetInt64(FlagStartTime)
if err != nil {
return err
}

msg := types.NewMsgCreateVestingAccount(clientCtx.GetFromAddress(), toAddr, amount, endTime, delayed)
msg := types.NewMsgCreateVestingAccount(clientCtx.GetFromAddress(), toAddr, amount, startTime, endTime, delayed)
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

cmd.Flags().Bool(FlagDelayed, false, "Create a delayed vesting account if true")
cmd.Flags().Int64(FlagStartTime, 0, "Optional start time (as a UNIX epoch timestamp) for continuous vesting accounts. If 0 (default), the block's time of the block this tx is committed to will be used.")
flags.AddTxFlagsToCmd(cmd)

return cmd
Expand Down
2 changes: 2 additions & 0 deletions x/auth/vesting/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,15 @@ func FuzzMsgServerCreateVestingAccount(f *testing.F) {
to2Addr,
sdk.Coins{fooCoin},
time.Now().Unix(),
time.Now().Unix()+1,
true,
),
vestingtypes.NewMsgCreateVestingAccount(
fromAddr,
to3Addr,
sdk.Coins{fooCoin},
time.Now().Unix(),
time.Now().Unix()+1,
false,
),
}
Expand Down
10 changes: 9 additions & 1 deletion x/auth/vesting/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ func (s msgServer) CreateVestingAccount(goCtx context.Context, msg *types.MsgCre
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid end time")
}

if msg.EndTime <= msg.StartTime {
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid start and end time (must be start < end)")
}

ctx := sdk.UnwrapSDKContext(goCtx)
if err := s.BankKeeper.IsSendEnabledCoins(ctx, msg.Amount...); err != nil {
return nil, err
Expand All @@ -71,7 +75,11 @@ func (s msgServer) CreateVestingAccount(goCtx context.Context, msg *types.MsgCre
if msg.Delayed {
vestingAccount = types.NewDelayedVestingAccountRaw(baseVestingAccount)
} else {
vestingAccount = types.NewContinuousVestingAccountRaw(baseVestingAccount, ctx.BlockTime().Unix())
start := ctx.BlockTime().Unix()
if msg.StartTime != 0 {
start = msg.StartTime
}
vestingAccount = types.NewContinuousVestingAccountRaw(baseVestingAccount, start)
}

s.AccountKeeper.SetAccount(ctx, vestingAccount)
Expand Down
21 changes: 20 additions & 1 deletion x/auth/vesting/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ func (s *VestingTestSuite) TestCreateVestingAccount() {
to1Addr,
sdk.Coins{fooCoin},
time.Now().Unix(),
time.Now().Unix()+1,
true,
),
expErr: true,
Expand All @@ -92,6 +93,7 @@ func (s *VestingTestSuite) TestCreateVestingAccount() {
[]byte{},
sdk.Coins{fooCoin},
time.Now().Unix(),
time.Now().Unix()+1,
true,
),
expErr: true,
Expand All @@ -103,6 +105,7 @@ func (s *VestingTestSuite) TestCreateVestingAccount() {
to1Addr,
sdk.Coins{sdk.Coin{Denom: "stake", Amount: math.NewInt(-1)}},
time.Now().Unix(),
time.Now().Unix()+1,
true,
),
expErr: true,
Expand All @@ -113,12 +116,25 @@ func (s *VestingTestSuite) TestCreateVestingAccount() {
fromAddr,
to1Addr,
sdk.Coins{fooCoin},
time.Now().Unix(),
-10,
true,
false,
),
expErr: true,
expErrMsg: "invalid end time",
},
"invalid start/end time": {
input: vestingtypes.NewMsgCreateVestingAccount(
fromAddr,
to1Addr,
sdk.Coins{fooCoin},
time.Now().Unix()+1,
time.Now().Unix(),
true,
),
expErr: true,
expErrMsg: "invalid start and end time (must be start < end)",
},
"create for existing account": {
preRun: func() {
toAcc := s.accountKeeper.NewAccountWithAddress(s.ctx, to1Addr)
Expand All @@ -131,6 +147,7 @@ func (s *VestingTestSuite) TestCreateVestingAccount() {
to1Addr,
sdk.Coins{fooCoin},
time.Now().Unix(),
time.Now().Unix()+1,
true,
),
expErr: true,
Expand All @@ -147,6 +164,7 @@ func (s *VestingTestSuite) TestCreateVestingAccount() {
to2Addr,
sdk.Coins{fooCoin},
time.Now().Unix(),
time.Now().Unix()+1,
true,
),
expErr: false,
Expand All @@ -163,6 +181,7 @@ func (s *VestingTestSuite) TestCreateVestingAccount() {
to3Addr,
sdk.Coins{fooCoin},
time.Now().Unix(),
time.Now().Unix()+1,
false,
),
expErr: false,
Expand Down
3 changes: 2 additions & 1 deletion x/auth/vesting/types/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ var (
)

// NewMsgCreateVestingAccount returns a reference to a new MsgCreateVestingAccount.
func NewMsgCreateVestingAccount(fromAddr, toAddr sdk.AccAddress, amount sdk.Coins, endTime int64, delayed bool) *MsgCreateVestingAccount {
func NewMsgCreateVestingAccount(fromAddr, toAddr sdk.AccAddress, amount sdk.Coins, startTime, endTime int64, delayed bool) *MsgCreateVestingAccount {
return &MsgCreateVestingAccount{
FromAddress: fromAddr.String(),
ToAddress: toAddr.String(),
Amount: amount,
StartTime: startTime,
EndTime: endTime,
Delayed: delayed,
}
Expand Down
118 changes: 79 additions & 39 deletions x/auth/vesting/types/tx.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions x/auth/vesting/types/vesting_account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,36 @@ func TestGetVestingCoinsContVestingAcc(t *testing.T) {
require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, vestingCoins)
}

func TestGetVestingCoinsContVestingAccStartTimeInFuture(t *testing.T) {
now := tmtime.Now()
startTime := now.Add(24 * time.Hour)
endTime := startTime.Add(24 * time.Hour)

bacc, origCoins := initBaseAccount()
cva, err := types.NewContinuousVestingAccount(bacc, origCoins, startTime.Unix(), endTime.Unix())
require.NoError(t, err)

// require all coins vesting in the beginning of the vesting schedule
vestingCoins := cva.GetVestingCoins(now)
require.Equal(t, origCoins, vestingCoins)

// require all coins vesting before right start time of the vesting schedule
vestingCoins = cva.GetVestingCoins(startTime.Add(-1))
require.Equal(t, origCoins, vestingCoins)

// require no coins vesting at the end of the vesting schedule
vestingCoins = cva.GetVestingCoins(endTime)
require.Equal(t, emptyCoins, vestingCoins)

// require 50% of coins vesting
vestingCoins = cva.GetVestingCoins(startTime.Add(12 * time.Hour))
require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, vestingCoins)

// require 50% of coins spendable
vestingCoins = cva.GetVestedCoins(startTime.Add(12 * time.Hour))
require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 500), sdk.NewInt64Coin(stakeDenom, 50)}, vestingCoins)
}

func TestSpendableCoinsContVestingAcc(t *testing.T) {
now := tmtime.Now()
endTime := now.Add(24 * time.Hour)
Expand Down

0 comments on commit cbae35e

Please sign in to comment.