Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Refactor x/auth/vesting to use ADR-031 #7551

Merged
merged 9 commits into from
Oct 19, 2020
12 changes: 12 additions & 0 deletions proto/cosmos/vesting/v1beta1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ import "cosmos/base/v1beta1/coin.proto";

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


// Msg defines the bank Msg service.
service Msg {
// CreateVestingAccount defines a method that enables creating a vesting
// account.
rpc CreateVestingAccount(MsgCreateVestingAccount) returns (MsgCreateVestingAccountResponse);
}


// MsgCreateVestingAccount defines a message that enables creating a vesting
// account.
message MsgCreateVestingAccount {
Expand All @@ -19,3 +28,6 @@ message MsgCreateVestingAccount {
int64 end_time = 4 [(gogoproto.moretags) = "yaml:\"end_time\""];
bool delayed = 5;
}

// MsgCreateVestingAccountResponse defines the Msg/CreateVestingAccount response type.
message MsgCreateVestingAccountResponse { }
7 changes: 3 additions & 4 deletions types/tx/tx.pb.go

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

77 changes: 4 additions & 73 deletions x/auth/vesting/handler.go
Original file line number Diff line number Diff line change
@@ -1,95 +1,26 @@
package vesting

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

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

// NewHandler returns a handler for x/auth message types.
func NewHandler(ak keeper.AccountKeeper, bk types.BankKeeper) sdk.Handler {
msgServer := NewMsgServerImpl(ak, bk)

return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())

switch msg := msg.(type) {
case *types.MsgCreateVestingAccount:
return handleMsgCreateVestingAccount(ctx, ak, bk, msg)
res, err := msgServer.CreateVestingAccount(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)

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

func handleMsgCreateVestingAccount(ctx sdk.Context, ak keeper.AccountKeeper, bk types.BankKeeper, msg *types.MsgCreateVestingAccount) (*sdk.Result, error) {
if err := bk.SendEnabledCoins(ctx, msg.Amount...); err != nil {
return nil, err
}

from, err := sdk.AccAddressFromBech32(msg.FromAddress)
if err != nil {
return nil, err
}
to, err := sdk.AccAddressFromBech32(msg.ToAddress)
if err != nil {
return nil, err
}

if bk.BlockedAddr(to) {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", msg.ToAddress)
}

if acc := ak.GetAccount(ctx, to); acc != nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "account %s already exists", msg.ToAddress)
}

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

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

var acc authtypes.AccountI

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

ak.SetAccount(ctx, acc)

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

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

err = bk.SendCoins(ctx, from, to, msg.Amount)
if err != nil {
return nil, err
}

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

return &sdk.Result{Events: ctx.EventManager().ABCIEvents()}, nil
}
100 changes: 100 additions & 0 deletions x/auth/vesting/msg_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package vesting

import (
"context"

authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"

"github.com/armon/go-metrics"

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

type msgServer struct {
keeper.AccountKeeper
types.BankKeeper
}

// NewMsgServerImpl returns an implementation of the vesting MsgServer interface,
// wrapping the corresponding AccountKeeper and BankKeeper.
func NewMsgServerImpl(k keeper.AccountKeeper, bk types.BankKeeper) types.MsgServer {
return &msgServer{AccountKeeper: k, BankKeeper: bk}
}

var _ types.MsgServer = msgServer{}

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.SendEnabledCoins(ctx, msg.Amount...); err != nil {
return nil, err
}

from, err := sdk.AccAddressFromBech32(msg.FromAddress)
if err != nil {
return nil, err
}
to, err := sdk.AccAddressFromBech32(msg.ToAddress)
if err != nil {
return nil, err
}

if bk.BlockedAddr(to) {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", msg.ToAddress)
}

if acc := ak.GetAccount(ctx, to); acc != nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "account %s already exists", msg.ToAddress)
}

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

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

var acc authtypes.AccountI

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

ak.SetAccount(ctx, acc)

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

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

err = bk.SendCoins(ctx, from, to, msg.Amount)
if err != nil {
return nil, err
}

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

return &types.MsgCreateVestingAccountResponse{}, nil
}
Loading