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

feature: add vesting token donation feature #88

Merged
merged 2 commits into from
Jul 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions docs/core/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,8 @@
- [MsgCreatePeriodicVestingAccountResponse](#cosmos.vesting.v1beta1.MsgCreatePeriodicVestingAccountResponse)
- [MsgCreateVestingAccount](#cosmos.vesting.v1beta1.MsgCreateVestingAccount)
- [MsgCreateVestingAccountResponse](#cosmos.vesting.v1beta1.MsgCreateVestingAccountResponse)
- [MsgDonateAllVestingTokens](#cosmos.vesting.v1beta1.MsgDonateAllVestingTokens)
- [MsgDonateAllVestingTokensResponse](#cosmos.vesting.v1beta1.MsgDonateAllVestingTokensResponse)

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

Expand Down Expand Up @@ -8458,7 +8460,7 @@ Since: cosmos-sdk 0.43
<a name="cosmos.vesting.v1beta1.MsgCreatePeriodicVestingAccount"></a>

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


Expand All @@ -8477,7 +8479,7 @@ account.
<a name="cosmos.vesting.v1beta1.MsgCreatePeriodicVestingAccountResponse"></a>

### MsgCreatePeriodicVestingAccountResponse
MsgCreateVestingAccountResponse defines the Msg/CreatePeriodicVestingAccount
MsgCreatePeriodicVestingAccountResponse defines the Msg/CreatePeriodicVestingAccount
response type.


Expand Down Expand Up @@ -8514,6 +8516,33 @@ MsgCreateVestingAccountResponse defines the Msg/CreateVestingAccount response ty




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

### MsgDonateAllVestingTokens
MsgDonateAllVestingTokens defines a message that enables donating all vesting
token to community pool.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `from_address` | [string](#string) | | |






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

### MsgDonateAllVestingTokensResponse
MsgDonateAllVestingTokensResponse defines the Msg/MsgDonateAllVestingTokens
response type.





<!-- end messages -->

<!-- end enums -->
Expand All @@ -8530,6 +8559,7 @@ Msg defines the bank Msg service.
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `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) | [MsgCreatePeriodicVestingAccountResponse](#cosmos.vesting.v1beta1.MsgCreatePeriodicVestingAccountResponse) | CreatePeriodicVestingAccount defines a method that enables creating a periodic vesting account. | |
| `DonateAllVestingTokens` | [MsgDonateAllVestingTokens](#cosmos.vesting.v1beta1.MsgDonateAllVestingTokens) | [MsgDonateAllVestingTokensResponse](#cosmos.vesting.v1beta1.MsgDonateAllVestingTokensResponse) | DonateAllVestingTokens defines a method that enables donating all vesting tokens to community pool | |

<!-- end services -->

Expand Down
19 changes: 17 additions & 2 deletions proto/cosmos/vesting/v1beta1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ service Msg {
// CreatePeriodicVestingAccount defines a method that enables creating a
// periodic vesting account.
rpc CreatePeriodicVestingAccount(MsgCreatePeriodicVestingAccount) returns (MsgCreatePeriodicVestingAccountResponse);
// DonateAllVestingTokens defines a method that enables donating all vesting
// tokens to community pool
rpc DonateAllVestingTokens(MsgDonateAllVestingTokens) returns (MsgDonateAllVestingTokensResponse);
}

// MsgCreateVestingAccount defines a message that enables creating a vesting
Expand All @@ -35,7 +38,7 @@ message MsgCreateVestingAccount {
message MsgCreateVestingAccountResponse {}


// MsgCreateVestingAccount defines a message that enables creating a vesting
// MsgCreatePeriodicVestingAccount defines a message that enables creating a vesting
// account.
message MsgCreatePeriodicVestingAccount {
option (gogoproto.equal) = false;
Expand All @@ -46,6 +49,18 @@ message MsgCreatePeriodicVestingAccount {
repeated Period vesting_periods = 4 [(gogoproto.nullable) = false];
}

// MsgCreateVestingAccountResponse defines the Msg/CreatePeriodicVestingAccount
// MsgCreatePeriodicVestingAccountResponse defines the Msg/CreatePeriodicVestingAccount
// response type.
message MsgCreatePeriodicVestingAccountResponse {}

// MsgDonateAllVestingTokens defines a message that enables donating all vesting
// token to community pool.
message MsgDonateAllVestingTokens {
option (gogoproto.equal) = false;

string from_address = 1 [(gogoproto.moretags) = "yaml:\"from_address\""];
}

// MsgDonateAllVestingTokensResponse defines the Msg/MsgDonateAllVestingTokens
// response type.
message MsgDonateAllVestingTokensResponse {}
2 changes: 1 addition & 1 deletion simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ func NewSimApp(
encodingConfig.TxConfig,
),
auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts),
vesting.NewAppModule(app.AccountKeeper, app.BankKeeper),
vesting.NewAppModule(app.AccountKeeper, app.BankKeeper, app.DistrKeeper),
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants),
Expand Down
29 changes: 29 additions & 0 deletions x/auth/vesting/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func GetTxCmd() *cobra.Command {
txCmd.AddCommand(
NewMsgCreateVestingAccountCmd(),
NewMsgCreatePeriodicVestingAccountCmd(),
NewMsgDonateAllVestingTokensCmd(),
)

return txCmd
Expand Down Expand Up @@ -171,3 +172,31 @@ func NewMsgCreatePeriodicVestingAccountCmd() *cobra.Command {

return cmd
}

// NewMsgDonateAllVestingTokensCmd returns a CLI command handler for creating a
// MsgDonateAllVestingTokens transaction.
func NewMsgDonateAllVestingTokensCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "donate-all-vesting-tokens",
Short: "Donate all vesting tokens of a vesting account to community pool.",
Long: `Donate all vesting tokens of a vesting account to community pool.
The account must not have any delegated vesting tokens to prevent complex
vesting logic changes. After donation, the account will be changed to normal
"BaseAccount".`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

msg := types.NewMsgDonateAllVestingTokens(clientCtx.GetFromAddress())

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

flags.AddTxFlagsToCmd(cmd)

return cmd
}
8 changes: 6 additions & 2 deletions x/auth/vesting/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (
)

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

return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
Expand All @@ -23,6 +23,10 @@ func NewHandler(ak keeper.AccountKeeper, bk types.BankKeeper) sdk.Handler {
res, err := msgServer.CreatePeriodicVestingAccount(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)

case *types.MsgDonateAllVestingTokens:
res, err := msgServer.DonateAllVestingTokens(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)
}
Expand Down
79 changes: 78 additions & 1 deletion x/auth/vesting/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (

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

"github.com/cosmos/cosmos-sdk/x/auth/vesting"
"github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
)
Expand All @@ -23,7 +25,7 @@ func (suite *HandlerTestSuite) SetupTest() {
checkTx := false
app := simapp.Setup(checkTx)

suite.handler = vesting.NewHandler(app.AccountKeeper, app.BankKeeper)
suite.handler = vesting.NewHandler(app.AccountKeeper, app.BankKeeper, app.DistrKeeper)
suite.app = app
}

Expand Down Expand Up @@ -91,6 +93,81 @@ func (suite *HandlerTestSuite) TestMsgCreateVestingAccount() {
}
}

func (suite *HandlerTestSuite) TestMsgDonateVestingToken() {
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_______________"))
addr2 := sdk.AccAddress([]byte("addr2_______________"))
addr3 := sdk.AccAddress([]byte("addr3_______________"))

acc1 := suite.app.AccountKeeper.NewAccountWithAddress(ctx, addr1)
suite.app.AccountKeeper.SetAccount(ctx, acc1)
suite.Require().NoError(simapp.FundAccount(suite.app.BankKeeper, ctx, addr1, balances))

acc2 := types.NewPermanentLockedAccount(
suite.app.AccountKeeper.NewAccountWithAddress(ctx, addr2).(*authtypes.BaseAccount), balances,
)
acc2.DelegatedVesting = balances
suite.app.AccountKeeper.SetAccount(ctx, acc2)
suite.Require().NoError(simapp.FundAccount(suite.app.BankKeeper, ctx, addr2, balances))

acc3 := types.NewPermanentLockedAccount(
suite.app.AccountKeeper.NewAccountWithAddress(ctx, addr3).(*authtypes.BaseAccount), balances,
)
suite.app.AccountKeeper.SetAccount(ctx, acc3)
suite.Require().NoError(simapp.FundAccount(suite.app.BankKeeper, ctx, addr3, balances))

testCases := []struct {
name string
msg *types.MsgDonateAllVestingTokens
expectErr bool
}{
{
name: "donate from normal account",
msg: types.NewMsgDonateAllVestingTokens(addr1),
expectErr: true,
},
{
name: "donate from vesting account with delegated vesting",
msg: types.NewMsgDonateAllVestingTokens(addr2),
expectErr: true,
},
{
name: "donate form vesting account",
msg: types.NewMsgDonateAllVestingTokens(addr3),
expectErr: false,
},
}

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)

feePool := suite.app.DistrKeeper.GetFeePool(ctx).CommunityPool
communityFund, _ := feePool.TruncateDecimal()
suite.Require().Equal(balances, communityFund)

fromAddr, err := sdk.AccAddressFromBech32(tc.msg.FromAddress)
suite.Require().NoError(err)
accI := suite.app.AccountKeeper.GetAccount(ctx, fromAddr)
suite.Require().NotNil(accI)
_, ok := accI.(*authtypes.BaseAccount)
suite.Require().True(ok)
balance := suite.app.BankKeeper.GetAllBalances(ctx, fromAddr)
suite.Require().Empty(balance)
}
})
}
}

func TestHandlerTestSuite(t *testing.T) {
suite.Run(t, new(HandlerTestSuite))
}
9 changes: 6 additions & 3 deletions x/auth/vesting/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth/keeper"

"github.com/cosmos/cosmos-sdk/x/auth/vesting/client/cli"
"github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
)
Expand Down Expand Up @@ -78,13 +79,15 @@ type AppModule struct {

accountKeeper keeper.AccountKeeper
bankKeeper types.BankKeeper
distrKeeper types.DistrKeeper
}

func NewAppModule(ak keeper.AccountKeeper, bk types.BankKeeper) AppModule {
func NewAppModule(ak keeper.AccountKeeper, bk types.BankKeeper, dk types.DistrKeeper) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{},
accountKeeper: ak,
bankKeeper: bk,
distrKeeper: dk,
}
}

Expand All @@ -93,7 +96,7 @@ func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}

// Route returns the module's message router and handler.
func (am AppModule) Route() sdk.Route {
return sdk.NewRoute(types.RouterKey, NewHandler(am.accountKeeper, am.bankKeeper))
return sdk.NewRoute(types.RouterKey, NewHandler(am.accountKeeper, am.bankKeeper, am.distrKeeper))
}

// QuerierRoute returns an empty string as the module contains no query
Expand All @@ -102,7 +105,7 @@ func (AppModule) QuerierRoute() string { return "" }

// RegisterServices registers module services.
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), NewMsgServerImpl(am.accountKeeper, am.bankKeeper))
types.RegisterMsgServer(cfg.MsgServer(), NewMsgServerImpl(am.accountKeeper, am.bankKeeper, am.distrKeeper))
}

// LegacyQuerierHandler performs a no-op.
Expand Down
Loading