From 9519690324b36e2cae0185d553e96c8891b5dea5 Mon Sep 17 00:00:00 2001 From: Ruaridh Date: Wed, 28 Sep 2022 03:28:57 +0100 Subject: [PATCH] Add Combined Earn and Liquid msgs (#1305) * add new msg type definitions * add msg methods and tests * add module and keeper skeleton * add deposit and withdraw methods (no delegation) * untested depsit/withdraw with delegation methods * add cli cmds * fix cli argument parsing * add tests for delegate/undelegate msgs * emit un/delegate events * add godoc comments --- app/app.go | 14 + app/test_common.go | 2 + contrib/devnet/init-new-chain.sh | 14 +- docs/core/proto-docs.md | 151 +++ proto/kava/router/v1beta1/tx.proto | 76 ++ x/liquid/keeper/derivative.go | 18 + x/liquid/keeper/derivative_test.go | 24 + x/liquid/types/expected_keepers.go | 1 + x/router/client/cli/tx.go | 174 +++ x/router/keeper/keeper.go | 26 + x/router/keeper/msg_server.go | 201 +++ x/router/keeper/msg_server_test.go | 321 +++++ x/router/module.go | 137 ++ x/router/testutil/suite.go | 361 ++++++ x/router/types/codec.go | 42 + x/router/types/common_test.go | 13 + x/router/types/expected_keepers.go | 34 + x/router/types/keys.go | 9 + x/router/types/msg.go | 201 +++ x/router/types/msg_test.go | 207 +++ x/router/types/tx.pb.go | 1882 ++++++++++++++++++++++++++++ 21 files changed, 3906 insertions(+), 2 deletions(-) create mode 100644 proto/kava/router/v1beta1/tx.proto create mode 100644 x/router/client/cli/tx.go create mode 100644 x/router/keeper/keeper.go create mode 100644 x/router/keeper/msg_server.go create mode 100644 x/router/keeper/msg_server_test.go create mode 100644 x/router/module.go create mode 100644 x/router/testutil/suite.go create mode 100644 x/router/types/codec.go create mode 100644 x/router/types/common_test.go create mode 100644 x/router/types/expected_keepers.go create mode 100644 x/router/types/keys.go create mode 100644 x/router/types/msg.go create mode 100644 x/router/types/msg_test.go create mode 100644 x/router/types/tx.pb.go diff --git a/app/app.go b/app/app.go index c12a13f5..f0e3af25 100644 --- a/app/app.go +++ b/app/app.go @@ -131,6 +131,9 @@ import ( pricefeed "github.com/kava-labs/kava/x/pricefeed" pricefeedkeeper "github.com/kava-labs/kava/x/pricefeed/keeper" pricefeedtypes "github.com/kava-labs/kava/x/pricefeed/types" + "github.com/kava-labs/kava/x/router" + routerkeeper "github.com/kava-labs/kava/x/router/keeper" + routertypes "github.com/kava-labs/kava/x/router/types" savings "github.com/kava-labs/kava/x/savings" savingskeeper "github.com/kava-labs/kava/x/savings/keeper" savingstypes "github.com/kava-labs/kava/x/savings/types" @@ -195,6 +198,7 @@ var ( evmutil.AppModuleBasic{}, liquid.AppModuleBasic{}, earn.AppModuleBasic{}, + router.AppModuleBasic{}, ) // module account permissions @@ -291,6 +295,7 @@ type App struct { savingsKeeper savingskeeper.Keeper liquidKeeper liquidkeeper.Keeper earnKeeper earnkeeper.Keeper + routerKeeper routerkeeper.Keeper // make scoped keepers public for test purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper @@ -624,6 +629,11 @@ func NewApp( nil, &earnKeeper, ) + app.routerKeeper = routerkeeper.NewKeeper( + &app.earnKeeper, + app.liquidKeeper, + &app.stakingKeeper, + ) // create committee keeper with router committeeGovRouter := govtypes.NewRouter() @@ -718,6 +728,7 @@ func NewApp( savings.NewAppModule(app.savingsKeeper, app.accountKeeper, app.bankKeeper), liquid.NewAppModule(app.liquidKeeper), earn.NewAppModule(app.earnKeeper, app.accountKeeper, app.bankKeeper), + router.NewAppModule(app.routerKeeper), ) // Warning: Some begin blockers must run before others. Ensure the dependencies are understood before modifying this list. @@ -766,6 +777,7 @@ func NewApp( savingstypes.ModuleName, liquidtypes.ModuleName, earntypes.ModuleName, + routertypes.ModuleName, ) // Warning: Some end blockers must run before others. Ensure the dependencies are understood before modifying this list. @@ -806,6 +818,7 @@ func NewApp( savingstypes.ModuleName, liquidtypes.ModuleName, earntypes.ModuleName, + routertypes.ModuleName, ) // Warning: Some init genesis methods must run before others. Ensure the dependencies are understood before modifying this list @@ -845,6 +858,7 @@ func NewApp( upgradetypes.ModuleName, validatorvestingtypes.ModuleName, liquidtypes.ModuleName, + routertypes.ModuleName, ) app.mm.RegisterInvariants(&app.crisisKeeper) diff --git a/app/test_common.go b/app/test_common.go index c458f620..957334e3 100644 --- a/app/test_common.go +++ b/app/test_common.go @@ -42,6 +42,7 @@ import ( kavadistkeeper "github.com/kava-labs/kava/x/kavadist/keeper" liquidkeeper "github.com/kava-labs/kava/x/liquid/keeper" pricefeedkeeper "github.com/kava-labs/kava/x/pricefeed/keeper" + routerkeeper "github.com/kava-labs/kava/x/router/keeper" savingskeeper "github.com/kava-labs/kava/x/savings/keeper" swapkeeper "github.com/kava-labs/kava/x/swap/keeper" ) @@ -112,6 +113,7 @@ func (tApp TestApp) GetSavingsKeeper() savingskeeper.Keeper { return tApp.sa func (tApp TestApp) GetFeeMarketKeeper() feemarketkeeper.Keeper { return tApp.feeMarketKeeper } func (tApp TestApp) GetLiquidKeeper() liquidkeeper.Keeper { return tApp.liquidKeeper } func (tApp TestApp) GetEarnKeeper() earnkeeper.Keeper { return tApp.earnKeeper } +func (tApp TestApp) GetRouterKeeper() routerkeeper.Keeper { return tApp.routerKeeper } func (tApp TestApp) GetStoreKey(s string) sdk.StoreKey { return tApp.keys[s] } diff --git a/contrib/devnet/init-new-chain.sh b/contrib/devnet/init-new-chain.sh index 58e29d20..5bb2715f 100755 --- a/contrib/devnet/init-new-chain.sh +++ b/contrib/devnet/init-new-chain.sh @@ -2,7 +2,8 @@ set -e validatorMnemonic="equip town gesture square tomorrow volume nephew minute witness beef rich gadget actress egg sing secret pole winter alarm law today check violin uncover" -# kava1ffv7nhd3z6sych2qpqkk03ec6hzkmufy0r2s4c +# kava1ffv7nhd3z6sych2qpqkk03ec6hzkmufy0r2s4c +# kavavaloper1ffv7nhd3z6sych2qpqkk03ec6hzkmufyz4scd0 faucetMnemonic="crash sort dwarf disease change advice attract clump avoid mobile clump right junior axis book fresh mask tube front require until face effort vault" # kava1adkm6svtzjsxxvg7g6rshg6kj9qwej8gwqadqd @@ -92,5 +93,14 @@ jq '.app_state.evm.params.chain_config.merge_fork_block = null' $DATA/config/gen jq '.app_state.earn.params.allowed_vaults = [ { denom: "usdx", - vault_strategy: 1, + strategies: ["STRATEGY_TYPE_HARD"], + }, + { + denom: "bkava", + strategies: ["STRATEGY_TYPE_SAVINGS"], }]' $DATA/config/genesis.json | sponge $DATA/config/genesis.json + +jq '.app_state.savings.params.supported_denoms = ["bkava-kavavaloper1ffv7nhd3z6sych2qpqkk03ec6hzkmufyz4scd0"]' $DATA/config/genesis.json | sponge $DATA/config/genesis.json + + +$BINARY config broadcast-mode block \ No newline at end of file diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index 5d14b711..a43648fb 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -430,6 +430,18 @@ - [Msg](#kava.pricefeed.v1beta1.Msg) +- [kava/router/v1beta1/tx.proto](#kava/router/v1beta1/tx.proto) + - [MsgDelegateMintDeposit](#kava.router.v1beta1.MsgDelegateMintDeposit) + - [MsgDelegateMintDepositResponse](#kava.router.v1beta1.MsgDelegateMintDepositResponse) + - [MsgMintDeposit](#kava.router.v1beta1.MsgMintDeposit) + - [MsgMintDepositResponse](#kava.router.v1beta1.MsgMintDepositResponse) + - [MsgWithdrawBurn](#kava.router.v1beta1.MsgWithdrawBurn) + - [MsgWithdrawBurnResponse](#kava.router.v1beta1.MsgWithdrawBurnResponse) + - [MsgWithdrawBurnUndelegate](#kava.router.v1beta1.MsgWithdrawBurnUndelegate) + - [MsgWithdrawBurnUndelegateResponse](#kava.router.v1beta1.MsgWithdrawBurnUndelegateResponse) + + - [Msg](#kava.router.v1beta1.Msg) + - [kava/savings/v1beta1/store.proto](#kava/savings/v1beta1/store.proto) - [Deposit](#kava.savings.v1beta1.Deposit) - [Params](#kava.savings.v1beta1.Params) @@ -5957,6 +5969,145 @@ Msg defines the pricefeed Msg service. + +

Top

+ +## kava/router/v1beta1/tx.proto + + + + + +### MsgDelegateMintDeposit +MsgDelegateMintDeposit delegates tokens to a validator, then converts them into staking derivatives, +then deposits to an earn vault. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `depositor` | [string](#string) | | depositor represents the owner of the tokens to delegate | +| `validator` | [string](#string) | | validator is the address of the validator to delegate to | +| `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | amount is the tokens to delegate | + + + + + + + + +### MsgDelegateMintDepositResponse +MsgDelegateMintDepositResponse defines the Msg/MsgDelegateMintDeposit response type. + + + + + + + + +### MsgMintDeposit +MsgMintDeposit converts a delegation into staking derivatives and deposits it all into an earn vault. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `depositor` | [string](#string) | | depositor represents the owner of the delegation to convert | +| `validator` | [string](#string) | | validator is the validator for the depositor's delegation | +| `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | amount is the delegation balance to convert | + + + + + + + + +### MsgMintDepositResponse +MsgMintDepositResponse defines the Msg/MsgMintDeposit response type. + + + + + + + + +### MsgWithdrawBurn +MsgWithdrawBurn removes staking derivatives from an earn vault and converts them back to a staking delegation. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `from` | [string](#string) | | from is the owner of the earn vault to withdraw from | +| `validator` | [string](#string) | | validator is the address to select the derivative denom to withdraw | +| `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | amount is the staked token equivalent to withdraw | + + + + + + + + +### MsgWithdrawBurnResponse +MsgWithdrawBurnResponse defines the Msg/MsgWithdrawBurn response type. + + + + + + + + +### MsgWithdrawBurnUndelegate +MsgWithdrawBurnUndelegate removes staking derivatives from an earn vault, converts them to a staking delegation, +then undelegates them from their validator. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `from` | [string](#string) | | from is the owner of the earn vault to withdraw from | +| `validator` | [string](#string) | | validator is the address to select the derivative denom to withdraw | +| `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | amount is the staked token equivalent to withdraw | + + + + + + + + +### MsgWithdrawBurnUndelegateResponse +MsgWithdrawBurnUndelegateResponse defines the Msg/MsgWithdrawBurnUndelegate response type. + + + + + + + + + + + + + + +### Msg +Msg defines the router Msg service. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `MintDeposit` | [MsgMintDeposit](#kava.router.v1beta1.MsgMintDeposit) | [MsgMintDepositResponse](#kava.router.v1beta1.MsgMintDepositResponse) | MintDeposit converts a delegation into staking derivatives and deposits it all into an earn vault. | | +| `DelegateMintDeposit` | [MsgDelegateMintDeposit](#kava.router.v1beta1.MsgDelegateMintDeposit) | [MsgDelegateMintDepositResponse](#kava.router.v1beta1.MsgDelegateMintDepositResponse) | DelegateMintDeposit delegates tokens to a validator, then converts them into staking derivatives, then deposits to an earn vault. | | +| `WithdrawBurn` | [MsgWithdrawBurn](#kava.router.v1beta1.MsgWithdrawBurn) | [MsgWithdrawBurnResponse](#kava.router.v1beta1.MsgWithdrawBurnResponse) | WithdrawBurn removes staking derivatives from an earn vault and converts them back to a staking delegation. | | +| `WithdrawBurnUndelegate` | [MsgWithdrawBurnUndelegate](#kava.router.v1beta1.MsgWithdrawBurnUndelegate) | [MsgWithdrawBurnUndelegateResponse](#kava.router.v1beta1.MsgWithdrawBurnUndelegateResponse) | WithdrawBurnUndelegate removes staking derivatives from an earn vault, converts them to a staking delegation, then undelegates them from their validator. | | + + + + +

Top

diff --git a/proto/kava/router/v1beta1/tx.proto b/proto/kava/router/v1beta1/tx.proto new file mode 100644 index 00000000..5d517b74 --- /dev/null +++ b/proto/kava/router/v1beta1/tx.proto @@ -0,0 +1,76 @@ +syntax = "proto3"; +package kava.router.v1beta1; + +import "cosmos_proto/cosmos.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/kava-labs/kava/x/router/types"; +option (gogoproto.goproto_getters_all) = false; + +// Msg defines the router Msg service. +service Msg { + // MintDeposit converts a delegation into staking derivatives and deposits it all into an earn vault. + rpc MintDeposit(MsgMintDeposit) returns (MsgMintDepositResponse); + + // DelegateMintDeposit delegates tokens to a validator, then converts them into staking derivatives, + // then deposits to an earn vault. + rpc DelegateMintDeposit(MsgDelegateMintDeposit) returns (MsgDelegateMintDepositResponse); + + // WithdrawBurn removes staking derivatives from an earn vault and converts them back to a staking delegation. + rpc WithdrawBurn(MsgWithdrawBurn) returns (MsgWithdrawBurnResponse); + + // WithdrawBurnUndelegate removes staking derivatives from an earn vault, converts them to a staking delegation, + // then undelegates them from their validator. + rpc WithdrawBurnUndelegate(MsgWithdrawBurnUndelegate) returns (MsgWithdrawBurnUndelegateResponse); +} + +// MsgMintDeposit converts a delegation into staking derivatives and deposits it all into an earn vault. +message MsgMintDeposit { + // depositor represents the owner of the delegation to convert + string depositor = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // validator is the validator for the depositor's delegation + string validator = 2; + // amount is the delegation balance to convert + cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false]; +} +// MsgMintDepositResponse defines the Msg/MsgMintDeposit response type. +message MsgMintDepositResponse {} + +// MsgDelegateMintDeposit delegates tokens to a validator, then converts them into staking derivatives, +// then deposits to an earn vault. +message MsgDelegateMintDeposit { + // depositor represents the owner of the tokens to delegate + string depositor = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // validator is the address of the validator to delegate to + string validator = 2; + // amount is the tokens to delegate + cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false]; +} +// MsgDelegateMintDepositResponse defines the Msg/MsgDelegateMintDeposit response type. +message MsgDelegateMintDepositResponse {} + +// MsgWithdrawBurn removes staking derivatives from an earn vault and converts them back to a staking delegation. +message MsgWithdrawBurn { + // from is the owner of the earn vault to withdraw from + string from = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // validator is the address to select the derivative denom to withdraw + string validator = 2; + // amount is the staked token equivalent to withdraw + cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false]; +} +// MsgWithdrawBurnResponse defines the Msg/MsgWithdrawBurn response type. +message MsgWithdrawBurnResponse {} + +// MsgWithdrawBurnUndelegate removes staking derivatives from an earn vault, converts them to a staking delegation, +// then undelegates them from their validator. +message MsgWithdrawBurnUndelegate { + // from is the owner of the earn vault to withdraw from + string from = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // validator is the address to select the derivative denom to withdraw + string validator = 2; + // amount is the staked token equivalent to withdraw + cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false]; +} +// MsgWithdrawBurnUndelegateResponse defines the Msg/MsgWithdrawBurnUndelegate response type. +message MsgWithdrawBurnUndelegateResponse {} \ No newline at end of file diff --git a/x/liquid/keeper/derivative.go b/x/liquid/keeper/derivative.go index fe9dd4df..de3c3162 100644 --- a/x/liquid/keeper/derivative.go +++ b/x/liquid/keeper/derivative.go @@ -155,3 +155,21 @@ func (k Keeper) burnCoins(ctx sdk.Context, sender sdk.AccAddress, amount sdk.Coi } return nil } + +// DerivativeFromTokens calculates the approximate amount of derivative coins that would be minted for a given amount of staking tokens. +func (k Keeper) DerivativeFromTokens(ctx sdk.Context, valAddr sdk.ValAddress, tokens sdk.Coin) (sdk.Coin, error) { + bondDenom := k.stakingKeeper.BondDenom(ctx) + if tokens.Denom != bondDenom { + return sdk.Coin{}, sdkerrors.Wrapf(types.ErrInvalidDenom, "'%s' does not match staking denom '%s'", tokens.Denom, bondDenom) + } + + // Use GetModuleAddress instead of GetModuleAccount to avoid creating a module account if it doesn't exist. + modAddress := k.accountKeeper.GetModuleAddress(types.ModuleAccountName) + derivative, _, err := k.CalculateDerivativeSharesFromTokens(ctx, modAddress, valAddr, tokens.Amount) + if err != nil { + return sdk.Coin{}, err + } + liquidTokenDenom := k.GetLiquidStakingTokenDenom(valAddr) + liquidToken := sdk.NewCoin(liquidTokenDenom, derivative) + return liquidToken, nil +} diff --git a/x/liquid/keeper/derivative_test.go b/x/liquid/keeper/derivative_test.go index b3e1303b..4bb4b241 100644 --- a/x/liquid/keeper/derivative_test.go +++ b/x/liquid/keeper/derivative_test.go @@ -469,3 +469,27 @@ func (suite *KeeperTestSuite) TestGetStakedTokensForDerivatives() { }) } } + +func (suite *KeeperTestSuite) TestDerivativeFromTokens() { + _, addrs := app.GeneratePrivKeyAddressPairs(1) + valAccAddr := addrs[0] + valAddr := sdk.ValAddress(valAccAddr) + moduleAccAddress := authtypes.NewModuleAddress(types.ModuleAccountName) + + initialBalance := i(1e9) + + suite.CreateAccountWithAddress(valAccAddr, suite.NewBondCoins(initialBalance)) + suite.AddCoinsToModule(types.ModuleAccountName, suite.NewBondCoins(initialBalance)) + + suite.CreateNewUnbondedValidator(valAddr, initialBalance) + suite.CreateDelegation(valAddr, moduleAccAddress, initialBalance) + staking.EndBlocker(suite.Ctx, suite.StakingKeeper) + + _, err := suite.Keeper.DerivativeFromTokens(suite.Ctx, valAddr, sdk.NewCoin("invalid", initialBalance)) + suite.ErrorIs(err, types.ErrInvalidDenom) + + derivatives, err := suite.Keeper.DerivativeFromTokens(suite.Ctx, valAddr, suite.NewBondCoin(initialBalance)) + suite.NoError(err) + expected := sdk.NewCoin(fmt.Sprintf("bkava-%s", valAddr), initialBalance) + suite.Equal(expected, derivatives) +} diff --git a/x/liquid/types/expected_keepers.go b/x/liquid/types/expected_keepers.go index c3d9ca8a..5466983a 100644 --- a/x/liquid/types/expected_keepers.go +++ b/x/liquid/types/expected_keepers.go @@ -21,6 +21,7 @@ type BankKeeper interface { // AccountKeeper defines the expected keeper interface for interacting with account type AccountKeeper interface { + GetModuleAddress(moduleName string) sdk.AccAddress GetModuleAccount(ctx sdk.Context, name string) authtypes.ModuleAccountI } diff --git a/x/router/client/cli/tx.go b/x/router/client/cli/tx.go new file mode 100644 index 00000000..7f9953bf --- /dev/null +++ b/x/router/client/cli/tx.go @@ -0,0 +1,174 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/version" + + "github.com/kava-labs/kava/x/router/types" +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd() *cobra.Command { + liquidTxCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "router transactions subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmds := []*cobra.Command{ + getCmdMintDeposit(), + getCmdDelegateMintDeposit(), + getCmdWithdrawBurn(), + getCmdWithdrawBurnUndelegate(), + } + + for _, cmd := range cmds { + flags.AddTxFlagsToCmd(cmd) + } + + liquidTxCmd.AddCommand(cmds...) + + return liquidTxCmd +} + +func getCmdMintDeposit() *cobra.Command { + return &cobra.Command{ + Use: "mint-deposit [validator-addr] [amount]", + Short: "mints staking derivative from a delegation and deposits them to earn", + Args: cobra.ExactArgs(2), + Example: fmt.Sprintf( + `%s tx %s mint-deposit kavavaloper16lnfpgn6llvn4fstg5nfrljj6aaxyee9z59jqd 10000000ukava --from `, version.AppName, types.ModuleName, + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + valAddr, err := sdk.ValAddressFromBech32(args[0]) + if err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, err.Error()) + } + + coin, err := sdk.ParseCoinNormalized(args[1]) + if err != nil { + return err + } + + msg := types.NewMsgMintDeposit(clientCtx.GetFromAddress(), valAddr, coin) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } +} + +func getCmdDelegateMintDeposit() *cobra.Command { + return &cobra.Command{ + Use: "delegate-mint-deposit [validator-addr] [amount]", + Short: "delegates tokens, mints staking derivative from a them, and deposits them to earn", + Args: cobra.ExactArgs(2), + Example: fmt.Sprintf( + `%s tx %s delegate-mint-deposit kavavaloper16lnfpgn6llvn4fstg5nfrljj6aaxyee9z59jqd 10000000ukava --from `, version.AppName, types.ModuleName, + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + valAddr, err := sdk.ValAddressFromBech32(args[0]) + if err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, err.Error()) + } + + coin, err := sdk.ParseCoinNormalized(args[1]) + if err != nil { + return err + } + + msg := types.NewMsgDelegateMintDeposit(clientCtx.GetFromAddress(), valAddr, coin) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } +} + +func getCmdWithdrawBurn() *cobra.Command { + return &cobra.Command{ + Use: "withdraw-burn [validator-addr] [amount]", + Short: "withdraws staking derivatives from earn and burns them to redeem a delegation", + Example: fmt.Sprintf( + `%s tx %s withdraw-burn kavavaloper16lnfpgn6llvn4fstg5nfrljj6aaxyee9z59jqd 10000000ukava --from `, version.AppName, types.ModuleName, + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + valAddr, err := sdk.ValAddressFromBech32(args[0]) + if err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, err.Error()) + } + + amount, err := sdk.ParseCoinNormalized(args[1]) + if err != nil { + return err + } + + msg := types.NewMsgWithdrawBurn(clientCtx.GetFromAddress(), valAddr, amount) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } +} + +func getCmdWithdrawBurnUndelegate() *cobra.Command { + return &cobra.Command{ + Use: "withdraw-burn-undelegate [validator-addr] [amount]", + Short: "withdraws staking derivatives from earn, burns them to redeem a delegation, then unstakes the delegation", + Example: fmt.Sprintf( + `%s tx %s withdraw-burn-undelegate kavavaloper16lnfpgn6llvn4fstg5nfrljj6aaxyee9z59jqd 10000000ukava --from `, version.AppName, types.ModuleName, + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + valAddr, err := sdk.ValAddressFromBech32(args[0]) + if err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, err.Error()) + } + + amount, err := sdk.ParseCoinNormalized(args[1]) + if err != nil { + return err + } + + msg := types.NewMsgWithdrawBurnUndelegate(clientCtx.GetFromAddress(), valAddr, amount) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } +} diff --git a/x/router/keeper/keeper.go b/x/router/keeper/keeper.go new file mode 100644 index 00000000..a509ad97 --- /dev/null +++ b/x/router/keeper/keeper.go @@ -0,0 +1,26 @@ +package keeper + +import ( + "github.com/kava-labs/kava/x/router/types" +) + +// Keeper is the keeper for the module +type Keeper struct { + earnKeeper types.EarnKeeper + liquidKeeper types.LiquidKeeper + stakingKeeper types.StakingKeeper +} + +// NewKeeper creates a new keeper +func NewKeeper( + earnKeeper types.EarnKeeper, + liquidKeeper types.LiquidKeeper, + stakingKeeper types.StakingKeeper, +) Keeper { + + return Keeper{ + earnKeeper: earnKeeper, + liquidKeeper: liquidKeeper, + stakingKeeper: stakingKeeper, + } +} diff --git a/x/router/keeper/msg_server.go b/x/router/keeper/msg_server.go new file mode 100644 index 00000000..72015426 --- /dev/null +++ b/x/router/keeper/msg_server.go @@ -0,0 +1,201 @@ +package keeper + +import ( + "context" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + earntypes "github.com/kava-labs/kava/x/earn/types" + "github.com/kava-labs/kava/x/router/types" +) + +type msgServer struct { + keeper Keeper +} + +// NewMsgServerImpl returns an implementation of the module's MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{keeper: keeper} +} + +var _ types.MsgServer = msgServer{} + +// MintDeposit converts a delegation into staking derivatives and deposits it all into an earn vault +func (m msgServer) MintDeposit(goCtx context.Context, msg *types.MsgMintDeposit) (*types.MsgMintDepositResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + depositor, err := sdk.AccAddressFromBech32(msg.Depositor) + if err != nil { + return nil, err + } + val, err := sdk.ValAddressFromBech32(msg.Validator) + if err != nil { + return nil, err + } + + derivative, err := m.keeper.liquidKeeper.MintDerivative(ctx, depositor, val, msg.Amount) + if err != nil { + return nil, err + } + err = m.keeper.earnKeeper.Deposit(ctx, depositor, derivative, earntypes.STRATEGY_TYPE_SAVINGS) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, depositor.String()), + ), + ) + return &types.MsgMintDepositResponse{}, nil +} + +// DelegateMintDeposit delegates tokens to a validator, then converts them into staking derivatives, +// then deposits to an earn vault. +func (m msgServer) DelegateMintDeposit(goCtx context.Context, msg *types.MsgDelegateMintDeposit) (*types.MsgDelegateMintDepositResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + depositor, err := sdk.AccAddressFromBech32(msg.Depositor) + if err != nil { + return nil, err + } + valAddr, err := sdk.ValAddressFromBech32(msg.Validator) + if err != nil { + return nil, err + } + validator, found := m.keeper.stakingKeeper.GetValidator(ctx, valAddr) + if !found { + return nil, stakingtypes.ErrNoValidatorFound + } + bondDenom := m.keeper.stakingKeeper.BondDenom(ctx) + if msg.Amount.Denom != bondDenom { + return nil, sdkerrors.Wrapf( + sdkerrors.ErrInvalidRequest, "invalid coin denomination: got %s, expected %s", msg.Amount.Denom, bondDenom, + ) + } + newShares, err := m.keeper.stakingKeeper.Delegate(ctx, depositor, msg.Amount.Amount, stakingtypes.Unbonded, validator, true) + if err != nil { + return nil, err + } + + derivativeMinted, err := m.keeper.liquidKeeper.MintDerivative(ctx, depositor, valAddr, msg.Amount) + if err != nil { + return nil, err + } + + err = m.keeper.earnKeeper.Deposit(ctx, depositor, derivativeMinted, earntypes.STRATEGY_TYPE_SAVINGS) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + stakingtypes.EventTypeDelegate, + sdk.NewAttribute(stakingtypes.AttributeKeyValidator, valAddr.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), + sdk.NewAttribute(stakingtypes.AttributeKeyNewShares, newShares.String()), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, depositor.String()), + ), + }) + + return &types.MsgDelegateMintDepositResponse{}, nil +} + +// WithdrawBurn removes staking derivatives from an earn vault and converts them back to a staking delegation. +func (m msgServer) WithdrawBurn(goCtx context.Context, msg *types.MsgWithdrawBurn) (*types.MsgWithdrawBurnResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + depositor, err := sdk.AccAddressFromBech32(msg.From) + if err != nil { + return nil, err + } + val, err := sdk.ValAddressFromBech32(msg.Validator) + if err != nil { + return nil, err + } + + tokenAmount, err := m.keeper.liquidKeeper.DerivativeFromTokens(ctx, val, msg.Amount) + if err != nil { + return nil, err + } + + err = m.keeper.earnKeeper.Withdraw(ctx, depositor, tokenAmount, earntypes.STRATEGY_TYPE_SAVINGS) + if err != nil { + return nil, err + } + + _, err = m.keeper.liquidKeeper.BurnDerivative(ctx, depositor, val, tokenAmount) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, depositor.String()), + ), + ) + + return &types.MsgWithdrawBurnResponse{}, nil +} + +// WithdrawBurnUndelegate removes staking derivatives from an earn vault, converts them to a staking delegation, +// then undelegates them from their validator. +func (m msgServer) WithdrawBurnUndelegate(goCtx context.Context, msg *types.MsgWithdrawBurnUndelegate) (*types.MsgWithdrawBurnUndelegateResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + depositor, err := sdk.AccAddressFromBech32(msg.From) + if err != nil { + return nil, err + } + val, err := sdk.ValAddressFromBech32(msg.Validator) + if err != nil { + return nil, err + } + + tokenAmount, err := m.keeper.liquidKeeper.DerivativeFromTokens(ctx, val, msg.Amount) + if err != nil { + return nil, err + } + + err = m.keeper.earnKeeper.Withdraw(ctx, depositor, tokenAmount, earntypes.STRATEGY_TYPE_SAVINGS) + if err != nil { + return nil, err + } + + sharesReturned, err := m.keeper.liquidKeeper.BurnDerivative(ctx, depositor, val, tokenAmount) + if err != nil { + return nil, err + } + + completionTime, err := m.keeper.stakingKeeper.Undelegate(ctx, depositor, val, sharesReturned) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + stakingtypes.EventTypeUnbond, + sdk.NewAttribute(stakingtypes.AttributeKeyValidator, val.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), + sdk.NewAttribute(stakingtypes.AttributeKeyCompletionTime, completionTime.Format(time.RFC3339)), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, depositor.String()), + ), + }) + return &types.MsgWithdrawBurnUndelegateResponse{}, nil +} diff --git a/x/router/keeper/msg_server_test.go b/x/router/keeper/msg_server_test.go new file mode 100644 index 00000000..8e3d4950 --- /dev/null +++ b/x/router/keeper/msg_server_test.go @@ -0,0 +1,321 @@ +package keeper_test + +import ( + "fmt" + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/stretchr/testify/suite" + + "github.com/kava-labs/kava/app" + earntypes "github.com/kava-labs/kava/x/earn/types" + "github.com/kava-labs/kava/x/router/keeper" + "github.com/kava-labs/kava/x/router/testutil" + "github.com/kava-labs/kava/x/router/types" +) + +type msgServerTestSuite struct { + testutil.Suite + + msgServer types.MsgServer +} + +func (suite *msgServerTestSuite) SetupTest() { + suite.Suite.SetupTest() + + suite.msgServer = keeper.NewMsgServerImpl(suite.Keeper) +} + +func TestMsgServerTestSuite(t *testing.T) { + suite.Run(t, new(msgServerTestSuite)) +} + +func (suite *msgServerTestSuite) TestMintDeposit_Events() { + user, valAddr, delegation := suite.setupValidatorAndDelegation() + suite.setupEarnForDeposits(valAddr) + + msg := types.NewMsgMintDeposit( + user, + valAddr, + suite.NewBondCoin(delegation), + ) + _, err := suite.msgServer.MintDeposit(sdk.WrapSDKContext(suite.Ctx), msg) + suite.Require().NoError(err) + + suite.EventsContains(suite.Ctx.EventManager().Events(), + sdk.NewEvent(sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, user.String()), + ), + ) +} + +func (suite *msgServerTestSuite) TestDelegateMintDeposit_Events() { + user, valAddr, balance := suite.setupValidator() + suite.setupEarnForDeposits(valAddr) + + msg := types.NewMsgDelegateMintDeposit( + user, + valAddr, + suite.NewBondCoin(balance), + ) + _, err := suite.msgServer.DelegateMintDeposit(sdk.WrapSDKContext(suite.Ctx), msg) + suite.Require().NoError(err) + + suite.EventsContains(suite.Ctx.EventManager().Events(), + sdk.NewEvent(sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, user.String()), + ), + ) + expectedShares := msg.Amount.Amount.ToDec() // no slashes so shares equal staked tokens + suite.EventsContains(suite.Ctx.EventManager().Events(), + sdk.NewEvent( + stakingtypes.EventTypeDelegate, + sdk.NewAttribute(stakingtypes.AttributeKeyValidator, msg.Validator), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), + sdk.NewAttribute(stakingtypes.AttributeKeyNewShares, expectedShares.String()), + ), + ) +} + +func (suite *msgServerTestSuite) TestWithdrawBurn_Events() { + user, valAddr, delegated := suite.setupDerivatives() + // clear events from setup + suite.Ctx = suite.Ctx.WithEventManager(sdk.NewEventManager()) + + msg := types.NewMsgWithdrawBurn( + user, + valAddr, + // in this setup where the validator is not slashed, the derivative amount is equal to the staked balance + suite.NewBondCoin(delegated.Amount), + ) + _, err := suite.msgServer.WithdrawBurn(sdk.WrapSDKContext(suite.Ctx), msg) + suite.Require().NoError(err) + + suite.EventsContains(suite.Ctx.EventManager().Events(), + sdk.NewEvent(sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, user.String()), + ), + ) +} + +func (suite *msgServerTestSuite) TestWithdrawBurnUndelegate_Events() { + user, valAddr, delegated := suite.setupDerivatives() + // clear events from setup + suite.Ctx = suite.Ctx.WithEventManager(sdk.NewEventManager()) + + msg := types.NewMsgWithdrawBurnUndelegate( + user, + valAddr, + // in this setup where the validator is not slashed, the derivative amount is equal to the staked balance + suite.NewBondCoin(delegated.Amount), + ) + _, err := suite.msgServer.WithdrawBurnUndelegate(sdk.WrapSDKContext(suite.Ctx), msg) + suite.Require().NoError(err) + + suite.EventsContains(suite.Ctx.EventManager().Events(), + sdk.NewEvent(sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, user.String()), + ), + ) + unbondingTime := suite.StakingKeeper.UnbondingTime(suite.Ctx) + completionTime := suite.Ctx.BlockTime().Add(unbondingTime) + suite.EventsContains(suite.Ctx.EventManager().Events(), + sdk.NewEvent( + stakingtypes.EventTypeUnbond, + sdk.NewAttribute(stakingtypes.AttributeKeyValidator, msg.Validator), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), + sdk.NewAttribute(stakingtypes.AttributeKeyCompletionTime, completionTime.Format(time.RFC3339)), + ), + ) +} + +func (suite *msgServerTestSuite) TestMintDepositAndWithdrawBurn_TransferEntireBalance() { + _, addrs := app.GeneratePrivKeyAddressPairs(5) + valAccAddr, user := addrs[0], addrs[1] + valAddr := sdk.ValAddress(valAccAddr) + + derivativeDenom := suite.setupEarnForDeposits(valAddr) + + suite.CreateAccountWithAddress(valAccAddr, suite.NewBondCoins(sdk.NewInt(1e9))) + vesting := sdk.NewInt(1000) + suite.CreateVestingAccountWithAddress(user, + suite.NewBondCoins(sdk.NewInt(1e9).Add(vesting)), + suite.NewBondCoins(vesting), + ) + + // Create a slashed validator, where the delegator owns fractional tokens. + suite.CreateNewUnbondedValidator(valAddr, sdk.NewInt(1e9)) + suite.CreateDelegation(valAddr, user, sdk.NewInt(1e9)) + staking.EndBlocker(suite.Ctx, suite.StakingKeeper) + suite.SlashValidator(valAddr, sdk.MustNewDecFromStr("0.666666666666666667")) + + // Query the full staked balance and convert it all to derivatives + // user technically 333_333_333.333333333333333333 staked tokens without rounding + delegation := suite.QueryStaking_Delegation(valAddr, user) + suite.Equal(sdk.NewInt(333_333_333), delegation.Balance.Amount) + + msgDeposit := types.NewMsgMintDeposit( + user, + valAddr, + delegation.Balance, + ) + _, err := suite.msgServer.MintDeposit(sdk.WrapSDKContext(suite.Ctx), msgDeposit) + suite.Require().NoError(err) + + // There should be no extractable balance left in delegation + suite.DelegationBalanceLessThan(valAddr, user, sdk.NewInt(1)) + // All derivative coins should be deposited to earn + suite.AccountBalanceOfEqual(user, derivativeDenom, sdk.ZeroInt()) + // Earn vault has all minted derivatives + suite.VaultAccountValueEqual(user, sdk.NewInt64Coin(derivativeDenom, 999_999_998)) // 2 lost in conversion + + // Query the full kava balance of the earn deposit and convert all to a delegation + deposit := suite.QueryEarn_VaultValue(user, "bkava") + suite.Equal(suite.NewBondCoins(sdk.NewInt(333_333_332)), deposit.Value) // 1 lost due to lost shares + + msgWithdraw := types.NewMsgWithdrawBurn( + user, + valAddr, + deposit.Value[0], + ) + _, err = suite.msgServer.WithdrawBurn(sdk.WrapSDKContext(suite.Ctx), msgWithdraw) + suite.Require().NoError(err) + + // There should be no earn deposit left (earn removes dust amounts) + suite.VaultAccountSharesEqual(user, nil) + // All derivative coins should be converted to a delegation + suite.AccountBalanceOfEqual(user, derivativeDenom, sdk.ZeroInt()) + // The user should get back most of their original deposited balance + suite.DelegationBalanceInDeltaBelow(valAddr, user, sdk.NewInt(333_333_332), sdk.NewInt(2)) +} + +func (suite *msgServerTestSuite) TestDelegateMintDepositAndWithdrawBurnUndelegate_TransferEntireBalance() { + _, addrs := app.GeneratePrivKeyAddressPairs(5) + valAccAddr, user := addrs[0], addrs[1] + valAddr := sdk.ValAddress(valAccAddr) + + derivativeDenom := suite.setupEarnForDeposits(valAddr) + + valBalance := sdk.NewInt(1e9) + suite.CreateAccountWithAddress(valAccAddr, suite.NewBondCoins(valBalance)) + + // Create a slashed validator, where a future delegator will own fractional tokens. + suite.CreateNewUnbondedValidator(valAddr, valBalance) + staking.EndBlocker(suite.Ctx, suite.StakingKeeper) + suite.SlashValidator(valAddr, sdk.MustNewDecFromStr("0.4")) // tokens remaining 600_000_000 + + userBalance := sdk.NewInt(100e6) + vesting := sdk.NewInt(1000) + suite.CreateVestingAccountWithAddress(user, + suite.NewBondCoins(userBalance.Add(vesting)), + suite.NewBondCoins(vesting), + ) + + // Query the full vested balance and convert it all to derivatives + balance := suite.QueryBank_SpendableBalance(user) + suite.Equal(suite.NewBondCoins(userBalance), balance) + + // When delegation is created it will have 166_666_666.666666666666666666 shares + // newShares = validatorShares * newTokens/validatorTokens, truncated to 18 decimals + msgDeposit := types.NewMsgDelegateMintDeposit( + user, + valAddr, + balance[0], + ) + _, err := suite.msgServer.DelegateMintDeposit(sdk.WrapSDKContext(suite.Ctx), msgDeposit) + suite.Require().NoError(err) + + // All spendable balance should be withdrawn + suite.AccountSpendableBalanceEqual(user, nil) + // Since shares are newly created, the exact amount should be converted to derivatives, leaving none behind + suite.DelegationSharesEqual(valAddr, user, sdk.ZeroDec()) + // All derivative coins should be deposited to earn + suite.AccountBalanceOfEqual(user, derivativeDenom, sdk.ZeroInt()) + + suite.VaultAccountValueEqual(user, sdk.NewInt64Coin(derivativeDenom, 166_666_666)) + + // Query the full kava balance of the earn deposit and convert all to a delegation + deposit := suite.QueryEarn_VaultValue(user, "bkava") + suite.Equal(suite.NewBondCoins(sdk.NewInt(99_999_999)), deposit.Value) // 1 lost due to truncating shares to derivatives + + msgWithdraw := types.NewMsgWithdrawBurnUndelegate( + user, + valAddr, + deposit.Value[0], + ) + _, err = suite.msgServer.WithdrawBurnUndelegate(sdk.WrapSDKContext(suite.Ctx), msgWithdraw) + suite.Require().NoError(err) + + // There should be no earn deposit left (earn removes dust amounts) + suite.VaultAccountSharesEqual(user, nil) + // All derivative coins should be converted to a delegation + suite.AccountBalanceOfEqual(user, derivativeDenom, sdk.ZeroInt()) + // There should be zero shares left because undelegate removes all created by burn. + suite.AccountBalanceOfEqual(user, derivativeDenom, sdk.ZeroInt()) + // User should have most of their original balance back in an unbonding delegation + suite.UnbondingDelegationInDeltaBelow(valAddr, user, userBalance, sdk.NewInt(2)) +} + +func (suite *msgServerTestSuite) setupValidator() (sdk.AccAddress, sdk.ValAddress, sdk.Int) { + _, addrs := app.GeneratePrivKeyAddressPairs(5) + valAccAddr, user := addrs[0], addrs[1] + valAddr := sdk.ValAddress(valAccAddr) + + balance := sdk.NewInt(1e9) + + suite.CreateAccountWithAddress(valAccAddr, suite.NewBondCoins(balance)) + suite.CreateAccountWithAddress(user, suite.NewBondCoins(balance)) + + suite.CreateNewUnbondedValidator(valAddr, balance) + staking.EndBlocker(suite.Ctx, suite.StakingKeeper) + return user, valAddr, balance +} + +func (suite *msgServerTestSuite) setupValidatorAndDelegation() (sdk.AccAddress, sdk.ValAddress, sdk.Int) { + _, addrs := app.GeneratePrivKeyAddressPairs(5) + valAccAddr, user := addrs[0], addrs[1] + valAddr := sdk.ValAddress(valAccAddr) + + balance := sdk.NewInt(1e9) + + suite.CreateAccountWithAddress(valAccAddr, suite.NewBondCoins(balance)) + suite.CreateAccountWithAddress(user, suite.NewBondCoins(balance)) + + suite.CreateNewUnbondedValidator(valAddr, balance) + suite.CreateDelegation(valAddr, user, balance) + staking.EndBlocker(suite.Ctx, suite.StakingKeeper) + return user, valAddr, balance +} + +func (suite *msgServerTestSuite) setupEarnForDeposits(valAddr sdk.ValAddress) string { + suite.CreateVault("bkava", earntypes.StrategyTypes{earntypes.STRATEGY_TYPE_SAVINGS}, false, nil) + derivativeDenom := fmt.Sprintf("bkava-%s", valAddr) + suite.SetSavingsSupportedDenoms([]string{derivativeDenom}) + return derivativeDenom +} + +func (suite *msgServerTestSuite) setupDerivatives() (sdk.AccAddress, sdk.ValAddress, sdk.Coin) { + user, valAddr, delegation := suite.setupValidatorAndDelegation() + suite.setupEarnForDeposits(valAddr) + + msg := types.NewMsgMintDeposit( + user, + valAddr, + suite.NewBondCoin(delegation), + ) + _, err := suite.msgServer.MintDeposit(sdk.WrapSDKContext(suite.Ctx), msg) + suite.Require().NoError(err) + + derivativeDenom := fmt.Sprintf("bkava-%s", valAddr) + derivatives, err := suite.EarnKeeper.GetVaultAccountValue(suite.Ctx, derivativeDenom, user) + suite.Require().NoError(err) + + return user, valAddr, derivatives +} diff --git a/x/router/module.go b/x/router/module.go new file mode 100644 index 00000000..500c1d87 --- /dev/null +++ b/x/router/module.go @@ -0,0 +1,137 @@ +package router + +import ( + "encoding/json" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/kava-labs/kava/x/router/client/cli" + "github.com/kava-labs/kava/x/router/keeper" + "github.com/kava-labs/kava/x/router/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// AppModuleBasic app module basics object +type AppModuleBasic struct{} + +// Name get module name +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec register module codec +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(cdc) +} + +// DefaultGenesis default genesis state +func (AppModuleBasic) DefaultGenesis(_ codec.JSONCodec) json.RawMessage { + return []byte("{}") +} + +// ValidateGenesis module validate genesis +func (AppModuleBasic) ValidateGenesis(_ codec.JSONCodec, _ client.TxEncodingConfig, _ json.RawMessage) error { + return nil +} + +// RegisterInterfaces implements InterfaceModule.RegisterInterfaces +func (a AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { + types.RegisterInterfaces(registry) +} + +// RegisterRESTRoutes registers REST routes for the module. +func (a AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (a AppModuleBasic) RegisterGRPCGatewayRoutes(_ client.Context, _ *runtime.ServeMux) { +} + +// GetTxCmd returns the root tx command for the module. +func (AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// GetQueryCmd returns no root query command for the module. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return nil +} + +//____________________________________________________________________________ + +// AppModule app module type +type AppModule struct { + AppModuleBasic + + keeper keeper.Keeper +} + +// NewAppModule creates a new AppModule object +func NewAppModule(keeper keeper.Keeper) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + } +} + +// Name module name +func (am AppModule) Name() string { + return am.AppModuleBasic.Name() +} + +// RegisterInvariants register module invariants +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// Route module message route name +func (am AppModule) Route() sdk.Route { + return sdk.Route{} +} + +// QuerierRoute module querier route name +func (AppModule) QuerierRoute() string { + return "" +} + +// LegacyQuerierHandler returns no sdk.Querier. +func (am AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier { + return nil +} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { + return 1 +} + +// RegisterServices registers module services. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) +} + +// InitGenesis module init-genesis +func (am AppModule) InitGenesis(_ sdk.Context, _ codec.JSONCodec, _ json.RawMessage) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// ExportGenesis module export genesis +func (am AppModule) ExportGenesis(_ sdk.Context, cdc codec.JSONCodec) json.RawMessage { + return am.DefaultGenesis(cdc) +} + +// BeginBlock module begin-block +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} + +// EndBlock module end-block +func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} diff --git a/x/router/testutil/suite.go b/x/router/testutil/suite.go new file mode 100644 index 00000000..c5517904 --- /dev/null +++ b/x/router/testutil/suite.go @@ -0,0 +1,361 @@ +package testutil + +import ( + "fmt" + "reflect" + + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmtime "github.com/tendermint/tendermint/types/time" + + "github.com/kava-labs/kava/app" + earnkeeper "github.com/kava-labs/kava/x/earn/keeper" + earntypes "github.com/kava-labs/kava/x/earn/types" + "github.com/kava-labs/kava/x/router/keeper" + savingstypes "github.com/kava-labs/kava/x/savings/types" +) + +// Test suite used for all keeper tests +type Suite struct { + suite.Suite + App app.TestApp + Ctx sdk.Context + Keeper keeper.Keeper + BankKeeper bankkeeper.Keeper + StakingKeeper stakingkeeper.Keeper + EarnKeeper earnkeeper.Keeper +} + +// The default state used by each test +func (suite *Suite) SetupTest() { + tApp := app.NewTestApp() + ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: tmtime.Now()}) + + tApp.InitializeFromGenesisStates() + + suite.App = tApp + suite.Ctx = ctx + suite.Keeper = tApp.GetRouterKeeper() + suite.StakingKeeper = tApp.GetStakingKeeper() + suite.BankKeeper = tApp.GetBankKeeper() + suite.EarnKeeper = tApp.GetEarnKeeper() +} + +// CreateAccount creates a new account from the provided balance and address +func (suite *Suite) CreateAccountWithAddress(addr sdk.AccAddress, initialBalance sdk.Coins) authtypes.AccountI { + ak := suite.App.GetAccountKeeper() + + acc := ak.NewAccountWithAddress(suite.Ctx, addr) + ak.SetAccount(suite.Ctx, acc) + + err := simapp.FundAccount(suite.BankKeeper, suite.Ctx, acc.GetAddress(), initialBalance) + suite.Require().NoError(err) + + return acc +} + +// CreateVestingAccount creates a new vesting account. `vestingBalance` should be a fraction of `initialBalance`. +func (suite *Suite) CreateVestingAccountWithAddress(addr sdk.AccAddress, initialBalance sdk.Coins, vestingBalance sdk.Coins) authtypes.AccountI { + if vestingBalance.IsAnyGT(initialBalance) { + panic("vesting balance must be less than initial balance") + } + acc := suite.CreateAccountWithAddress(addr, initialBalance) + bacc := acc.(*authtypes.BaseAccount) + + periods := vestingtypes.Periods{ + vestingtypes.Period{ + Length: 31556952, + Amount: vestingBalance, + }, + } + vacc := vestingtypes.NewPeriodicVestingAccount(bacc, vestingBalance, suite.Ctx.BlockTime().Unix(), periods) + suite.App.GetAccountKeeper().SetAccount(suite.Ctx, vacc) + return vacc +} + +// AddCoinsToModule adds coins to the a module account, creating it if it doesn't exist. +func (suite *Suite) AddCoinsToModule(module string, amount sdk.Coins) { + err := simapp.FundModuleAccount(suite.BankKeeper, suite.Ctx, module, amount) + suite.Require().NoError(err) +} + +// AccountBalanceEqual checks if an account has the specified coins. +func (suite *Suite) AccountBalanceEqual(addr sdk.AccAddress, coins sdk.Coins) { + balance := suite.BankKeeper.GetAllBalances(suite.Ctx, addr) + suite.Equalf(coins, balance, "expected account balance to equal coins %s, but got %s", coins, balance) +} + +// AccountBalanceOfEqual checks if an account has the specified amount of one denom. +func (suite *Suite) AccountBalanceOfEqual(addr sdk.AccAddress, denom string, amount sdk.Int) { + balance := suite.BankKeeper.GetBalance(suite.Ctx, addr, denom).Amount + suite.Equalf(amount, balance, "expected account balance to have %[1]s%[2]s, but got %[3]s%[2]s", amount, denom, balance) +} + +// AccountSpendableBalanceEqual checks if an account has the specified coins unlocked. +func (suite *Suite) AccountSpendableBalanceEqual(addr sdk.AccAddress, amount sdk.Coins) { + balance := suite.BankKeeper.SpendableCoins(suite.Ctx, addr) + suite.Equalf(amount, balance, "expected account spendable balance to equal coins %s, but got %s", amount, balance) +} + +func (suite *Suite) QueryBank_SpendableBalance(user sdk.AccAddress) sdk.Coins { + res, err := suite.BankKeeper.SpendableBalances( + sdk.WrapSDKContext(suite.Ctx), + &banktypes.QuerySpendableBalancesRequest{ + Address: user.String(), + }, + ) + suite.Require().NoError(err) + return *&res.Balances +} + +func (suite *Suite) deliverMsgCreateValidator(ctx sdk.Context, address sdk.ValAddress, selfDelegation sdk.Coin) error { + msg, err := stakingtypes.NewMsgCreateValidator( + address, + ed25519.GenPrivKey().PubKey(), + selfDelegation, + stakingtypes.Description{}, + stakingtypes.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), + sdk.NewInt(1e6), + ) + if err != nil { + return err + } + + msgServer := stakingkeeper.NewMsgServerImpl(suite.StakingKeeper) + _, err = msgServer.CreateValidator(sdk.WrapSDKContext(suite.Ctx), msg) + return err +} + +// NewBondCoin creates a Coin with the current staking denom. +func (suite *Suite) NewBondCoin(amount sdk.Int) sdk.Coin { + stakingDenom := suite.StakingKeeper.BondDenom(suite.Ctx) + return sdk.NewCoin(stakingDenom, amount) +} + +// NewBondCoins creates Coins with the current staking denom. +func (suite *Suite) NewBondCoins(amount sdk.Int) sdk.Coins { + return sdk.NewCoins(suite.NewBondCoin(amount)) +} + +// CreateNewUnbondedValidator creates a new validator in the staking module. +// New validators are unbonded until the end blocker is run. +func (suite *Suite) CreateNewUnbondedValidator(addr sdk.ValAddress, selfDelegation sdk.Int) stakingtypes.Validator { + // Create a validator + err := suite.deliverMsgCreateValidator(suite.Ctx, addr, suite.NewBondCoin(selfDelegation)) + suite.Require().NoError(err) + + // New validators are created in an unbonded state. Note if the end blocker is run later this validator could become bonded. + + validator, found := suite.StakingKeeper.GetValidator(suite.Ctx, addr) + suite.Require().True(found) + return validator +} + +// SlashValidator burns tokens staked in a validator. new_tokens = old_tokens * (1-slashFraction) +func (suite *Suite) SlashValidator(addr sdk.ValAddress, slashFraction sdk.Dec) { + validator, found := suite.StakingKeeper.GetValidator(suite.Ctx, addr) + suite.Require().True(found) + consAddr, err := validator.GetConsAddr() + suite.Require().NoError(err) + + // Assume infraction was at current height. Note unbonding delegations and redelegations are only slashed if created after + // the infraction height so none will be slashed. + infractionHeight := suite.Ctx.BlockHeight() + + power := suite.StakingKeeper.TokensToConsensusPower(suite.Ctx, validator.GetTokens()) + + suite.StakingKeeper.Slash(suite.Ctx, consAddr, infractionHeight, power, slashFraction) +} + +// CreateDelegation delegates tokens to a validator. +func (suite *Suite) CreateDelegation(valAddr sdk.ValAddress, delegator sdk.AccAddress, amount sdk.Int) sdk.Dec { + stakingDenom := suite.StakingKeeper.BondDenom(suite.Ctx) + msg := stakingtypes.NewMsgDelegate( + delegator, + valAddr, + sdk.NewCoin(stakingDenom, amount), + ) + + msgServer := stakingkeeper.NewMsgServerImpl(suite.StakingKeeper) + _, err := msgServer.Delegate(sdk.WrapSDKContext(suite.Ctx), msg) + suite.Require().NoError(err) + + del, found := suite.StakingKeeper.GetDelegation(suite.Ctx, delegator, valAddr) + suite.Require().True(found) + return del.Shares +} + +// DelegationSharesEqual checks if a delegation has the specified shares. +// It expects delegations with zero shares to not be stored in state. +func (suite *Suite) DelegationSharesEqual(valAddr sdk.ValAddress, delegator sdk.AccAddress, shares sdk.Dec) bool { + del, found := suite.StakingKeeper.GetDelegation(suite.Ctx, delegator, valAddr) + + if shares.IsZero() { + return suite.Falsef(found, "expected delegator to not be found, got %s shares", del.Shares) + } else { + res := suite.True(found, "expected delegator to be found") + return res && suite.Truef(shares.Equal(del.Shares), "expected %s delegator shares but got %s", shares, del.Shares) + } +} + +// DelegationBalanceLessThan checks if a delegation's staked token balance is less the specified amount. +// It treats not found delegations as having zero shares. +func (suite *Suite) DelegationBalanceLessThan(valAddr sdk.ValAddress, delegator sdk.AccAddress, max sdk.Int) bool { + shares := sdk.ZeroDec() + del, found := suite.StakingKeeper.GetDelegation(suite.Ctx, delegator, valAddr) + if found { + shares = del.Shares + } + + val, found := suite.StakingKeeper.GetValidator(suite.Ctx, valAddr) + suite.Require().Truef(found, "expected validator to be found") + + tokens := val.TokensFromShares(shares).TruncateInt() + + return suite.Truef(tokens.LT(max), "expected delegation balance to be less than %s, got %s", max, tokens) +} + +// DelegationBalanceInDeltaBelow checks if a delegation's staked token balance is between `expected` and `expected - delta` inclusive. +// It treats not found delegations as having zero shares. +func (suite *Suite) DelegationBalanceInDeltaBelow(valAddr sdk.ValAddress, delegator sdk.AccAddress, expected, delta sdk.Int) bool { + shares := sdk.ZeroDec() + del, found := suite.StakingKeeper.GetDelegation(suite.Ctx, delegator, valAddr) + if found { + shares = del.Shares + } + + val, found := suite.StakingKeeper.GetValidator(suite.Ctx, valAddr) + suite.Require().Truef(found, "expected validator to be found") + + tokens := val.TokensFromShares(shares).TruncateInt() + + lte := suite.Truef(tokens.LTE(expected), "expected delegation balance to be less than or equal to %s, got %s", expected, tokens) + gte := suite.Truef(tokens.GTE(expected.Sub(delta)), "expected delegation balance to be greater than or equal to %s, got %s", expected.Sub(delta), tokens) + return lte && gte +} + +// UnbondingDelegationInDeltaBelow checks if the total balance in an unbonding delegation is between `expected` and `expected - delta` inclusive. +func (suite *Suite) UnbondingDelegationInDeltaBelow(valAddr sdk.ValAddress, delegator sdk.AccAddress, expected, delta sdk.Int) bool { + tokens := sdk.ZeroInt() + ubd, found := suite.StakingKeeper.GetUnbondingDelegation(suite.Ctx, delegator, valAddr) + if found { + for _, entry := range ubd.Entries { + tokens = tokens.Add(entry.Balance) + } + } + + lte := suite.Truef(tokens.LTE(expected), "expected unbonding delegation balance to be less than or equal to %s, got %s", expected, tokens) + gte := suite.Truef(tokens.GTE(expected.Sub(delta)), "expected unbonding delegation balance to be greater than or equal to %s, got %s", expected.Sub(delta), tokens) + return lte && gte +} + +func (suite *Suite) QueryStaking_Delegation(valAddr sdk.ValAddress, delegator sdk.AccAddress) stakingtypes.DelegationResponse { + stakingQuery := stakingkeeper.Querier{Keeper: suite.StakingKeeper} + res, err := stakingQuery.Delegation( + sdk.WrapSDKContext(suite.Ctx), + &stakingtypes.QueryDelegationRequest{ + DelegatorAddr: delegator.String(), + ValidatorAddr: valAddr.String(), + }, + ) + suite.Require().NoError(err) + return *res.DelegationResponse +} + +// EventsContains asserts that the expected event is in the provided events +func (suite *Suite) EventsContains(events sdk.Events, expectedEvent sdk.Event) { + foundMatch := false + for _, event := range events { + if event.Type == expectedEvent.Type { + if reflect.DeepEqual(attrsToMap(expectedEvent.Attributes), attrsToMap(event.Attributes)) { + foundMatch = true + } + } + } + + suite.True(foundMatch, fmt.Sprintf("event of type %s not found or did not match", expectedEvent.Type)) +} + +func attrsToMap(attrs []abci.EventAttribute) []sdk.Attribute { + out := []sdk.Attribute{} + + for _, attr := range attrs { + out = append(out, sdk.NewAttribute(string(attr.Key), string(attr.Value))) + } + + return out +} + +// CreateVault adds a new earn vault to the earn keeper parameters +func (suite *Suite) CreateVault( + vaultDenom string, + vaultStrategies earntypes.StrategyTypes, + isPrivateVault bool, + allowedDepositors []sdk.AccAddress, +) { + vault := earntypes.NewAllowedVault(vaultDenom, vaultStrategies, isPrivateVault, allowedDepositors) + + allowedVaults := suite.EarnKeeper.GetAllowedVaults(suite.Ctx) + allowedVaults = append(allowedVaults, vault) + + params := earntypes.NewParams(allowedVaults) + + suite.EarnKeeper.SetParams( + suite.Ctx, + params, + ) +} + +// SetSavingsSupportedDenoms overwrites the list of supported denoms in the savings module params. +func (suite *Suite) SetSavingsSupportedDenoms(denoms []string) { + sk := suite.App.GetSavingsKeeper() + sk.SetParams(suite.Ctx, savingstypes.NewParams(denoms)) +} + +// VaultAccountValueEqual asserts that the vault account value matches the provided coin amount. +func (suite *Suite) VaultAccountValueEqual(acc sdk.AccAddress, coin sdk.Coin) { + + accVaultBal, err := suite.EarnKeeper.GetVaultAccountValue(suite.Ctx, coin.Denom, acc) + suite.Require().NoError(err) + + suite.Require().Truef( + coin.Equal(accVaultBal), + "expected account vault balance to equal %s, but got %s", + coin, accVaultBal, + ) +} + +// VaultAccountSharesEqual asserts that the vault account shares match the provided values. +func (suite *Suite) VaultAccountSharesEqual(acc sdk.AccAddress, shares earntypes.VaultShares) { // TODO + + accVaultShares, found := suite.EarnKeeper.GetVaultAccountShares(suite.Ctx, acc) + if !found { + suite.Empty(shares) + } else { + suite.Equal(shares, accVaultShares) + } +} + +func (suite *Suite) QueryEarn_VaultValue(depositor sdk.AccAddress, vaultDenom string) earntypes.DepositResponse { + earnQuery := earnkeeper.NewQueryServerImpl(suite.EarnKeeper) + res, err := earnQuery.Deposits( + sdk.WrapSDKContext(suite.Ctx), + &earntypes.QueryDepositsRequest{ + Depositor: depositor.String(), + Denom: vaultDenom, + }, + ) + suite.Require().NoError(err) + suite.Require().Equalf(1, len(res.Deposits), "while earn supports one vault per denom, deposits response should be length 1") + return res.Deposits[0] +} diff --git a/x/router/types/codec.go b/x/router/types/codec.go new file mode 100644 index 00000000..3bee22eb --- /dev/null +++ b/x/router/types/codec.go @@ -0,0 +1,42 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +// RegisterLegacyAminoCodec registers all the necessary types and interfaces for the module. +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgMintDeposit{}, "router/MsgMintDeposit", nil) + cdc.RegisterConcrete(&MsgDelegateMintDeposit{}, "router/MsgDelegateMintDeposit", nil) + cdc.RegisterConcrete(&MsgWithdrawBurn{}, "router/MsgWithdrawBurn", nil) + cdc.RegisterConcrete(&MsgWithdrawBurnUndelegate{}, "router/MsgWithdrawBurnUndelegate", nil) +} + +// RegisterInterfaces registers proto messages under their interfaces for unmarshalling, +// in addition to registering the msg service for handling tx msgs +func RegisterInterfaces(registry types.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgMintDeposit{}, + &MsgDelegateMintDeposit{}, + &MsgWithdrawBurn{}, + &MsgWithdrawBurnUndelegate{}, + ) + + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + amino = codec.NewLegacyAmino() + // ModuleCdc represents the legacy amino codec for the module + ModuleCdc = codec.NewAminoCodec(amino) +) + +func init() { + RegisterLegacyAminoCodec(amino) + cryptocodec.RegisterCrypto(amino) +} diff --git a/x/router/types/common_test.go b/x/router/types/common_test.go new file mode 100644 index 00000000..e88e1d5e --- /dev/null +++ b/x/router/types/common_test.go @@ -0,0 +1,13 @@ +package types_test + +import ( + "os" + "testing" + + "github.com/kava-labs/kava/app" +) + +func TestMain(m *testing.M) { + app.SetSDKConfig() + os.Exit(m.Run()) +} diff --git a/x/router/types/expected_keepers.go b/x/router/types/expected_keepers.go new file mode 100644 index 00000000..4a3dd382 --- /dev/null +++ b/x/router/types/expected_keepers.go @@ -0,0 +1,34 @@ +package types + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + earntypes "github.com/kava-labs/kava/x/earn/types" +) + +type StakingKeeper interface { + BondDenom(ctx sdk.Context) (res string) + GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator stakingtypes.Validator, found bool) + + Delegate( + ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Int, tokenSrc stakingtypes.BondStatus, + validator stakingtypes.Validator, subtractAccount bool, + ) (newShares sdk.Dec, err error) + Undelegate( + ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec, + ) (time.Time, error) +} + +type LiquidKeeper interface { + DerivativeFromTokens(ctx sdk.Context, valAddr sdk.ValAddress, amount sdk.Coin) (sdk.Coin, error) + MintDerivative(ctx sdk.Context, delegatorAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Coin) (sdk.Coin, error) + BurnDerivative(ctx sdk.Context, delegatorAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Coin) (sdk.Dec, error) +} + +type EarnKeeper interface { + Deposit(ctx sdk.Context, depositor sdk.AccAddress, amount sdk.Coin, depositStrategy earntypes.StrategyType) error + Withdraw(ctx sdk.Context, from sdk.AccAddress, wantAmount sdk.Coin, withdrawStrategy earntypes.StrategyType) error +} diff --git a/x/router/types/keys.go b/x/router/types/keys.go new file mode 100644 index 00000000..dbde25a7 --- /dev/null +++ b/x/router/types/keys.go @@ -0,0 +1,9 @@ +package types + +const ( + // ModuleName name that will be used throughout the module + ModuleName = "router" + + // RouterKey top level router key + RouterKey = ModuleName +) diff --git a/x/router/types/msg.go b/x/router/types/msg.go new file mode 100644 index 00000000..e0e7104e --- /dev/null +++ b/x/router/types/msg.go @@ -0,0 +1,201 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx" +) + +const ( + // TypeMsgMintDeposit defines the type for MsgMintDeposit + TypeMsgMintDeposit = "mint_deposit" + // TypeMsgDelegateMintDeposit defines the type for MsgDelegateMintDeposit + TypeMsgDelegateMintDeposit = "delegate_mint_deposit" + // TypeMsgWithdrawBurn defines the type for MsgWithdrawBurn + TypeMsgWithdrawBurn = "withdraw_burn" + // TypeMsgWithdrawBurnUndelegate defines the type for MsgWithdrawBurnUndelegate + TypeMsgWithdrawBurnUndelegate = "withdraw_burn_undelegate" +) + +var ( + _ sdk.Msg = &MsgMintDeposit{} + _ legacytx.LegacyMsg = &MsgMintDeposit{} + _ sdk.Msg = &MsgDelegateMintDeposit{} + _ legacytx.LegacyMsg = &MsgDelegateMintDeposit{} + _ sdk.Msg = &MsgWithdrawBurn{} + _ legacytx.LegacyMsg = &MsgWithdrawBurn{} + _ sdk.Msg = &MsgWithdrawBurnUndelegate{} + _ legacytx.LegacyMsg = &MsgWithdrawBurnUndelegate{} +) + +// NewMsgMintDeposit returns a new MsgMintDeposit. +func NewMsgMintDeposit(depositor sdk.AccAddress, validator sdk.ValAddress, amount sdk.Coin) *MsgMintDeposit { + return &MsgMintDeposit{ + Depositor: depositor.String(), + Validator: validator.String(), + Amount: amount, + } +} + +// Route return the message type used for routing the message. +func (msg MsgMintDeposit) Route() string { return RouterKey } + +// Type returns a human-readable string for the message, intended for utilization within tags. +func (msg MsgMintDeposit) Type() string { return TypeMsgMintDeposit } + +// ValidateBasic does a simple validation check that doesn't require access to any other information. +func (msg MsgMintDeposit) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Depositor); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid depositor address: %s", err) + } + + if _, err := sdk.ValAddressFromBech32(msg.Validator); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid validator address: %s", err) + } + + if msg.Amount.IsNil() || !msg.Amount.IsValid() || msg.Amount.IsZero() { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "'%s'", msg.Amount) + } + return nil +} + +// GetSignBytes gets the canonical byte representation of the Msg. +func (msg MsgMintDeposit) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(&msg) + return sdk.MustSortJSON(bz) +} + +// GetSigners returns the addresses of signers that must sign. +func (msg MsgMintDeposit) GetSigners() []sdk.AccAddress { + depositor, _ := sdk.AccAddressFromBech32(msg.Depositor) + return []sdk.AccAddress{depositor} +} + +// NewMsgDelegateMintDeposit returns a new MsgDelegateMintDeposit. +func NewMsgDelegateMintDeposit(depositor sdk.AccAddress, validator sdk.ValAddress, amount sdk.Coin) *MsgDelegateMintDeposit { + return &MsgDelegateMintDeposit{ + Depositor: depositor.String(), + Validator: validator.String(), + Amount: amount, + } +} + +// Route return the message type used for routing the message. +func (msg MsgDelegateMintDeposit) Route() string { return RouterKey } + +// Type returns a human-readable string for the message, intended for utilization within tags. +func (msg MsgDelegateMintDeposit) Type() string { return TypeMsgDelegateMintDeposit } + +// ValidateBasic does a simple validation check that doesn't require access to any other information. +func (msg MsgDelegateMintDeposit) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Depositor); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid depositor address: %s", err) + } + + if _, err := sdk.ValAddressFromBech32(msg.Validator); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid validator address: %s", err) + } + + if msg.Amount.IsNil() || !msg.Amount.IsValid() || msg.Amount.IsZero() { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "'%s'", msg.Amount) + } + return nil +} + +// GetSignBytes gets the canonical byte representation of the Msg. +func (msg MsgDelegateMintDeposit) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(&msg) + return sdk.MustSortJSON(bz) +} + +// GetSigners returns the addresses of signers that must sign. +func (msg MsgDelegateMintDeposit) GetSigners() []sdk.AccAddress { + depositor, _ := sdk.AccAddressFromBech32(msg.Depositor) + return []sdk.AccAddress{depositor} +} + +// NewMsgWithdrawBurn returns a new MsgWithdrawBurn. +func NewMsgWithdrawBurn(from sdk.AccAddress, validator sdk.ValAddress, amount sdk.Coin) *MsgWithdrawBurn { + return &MsgWithdrawBurn{ + From: from.String(), + Validator: validator.String(), + Amount: amount, + } +} + +// Route return the message type used for routing the message. +func (msg MsgWithdrawBurn) Route() string { return RouterKey } + +// Type returns a human-readable string for the message, intended for utilization within tags. +func (msg MsgWithdrawBurn) Type() string { return TypeMsgWithdrawBurn } + +// ValidateBasic does a simple validation check that doesn't require access to any other information. +func (msg MsgWithdrawBurn) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.From); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid from address: %s", err) + } + + if _, err := sdk.ValAddressFromBech32(msg.Validator); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid validator address: %s", err) + } + + if msg.Amount.IsNil() || !msg.Amount.IsValid() || msg.Amount.IsZero() { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "'%s'", msg.Amount) + } + return nil +} + +// GetSignBytes gets the canonical byte representation of the Msg. +func (msg MsgWithdrawBurn) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(&msg) + return sdk.MustSortJSON(bz) +} + +// GetSigners returns the addresses of signers that must sign. +func (msg MsgWithdrawBurn) GetSigners() []sdk.AccAddress { + from, _ := sdk.AccAddressFromBech32(msg.From) + return []sdk.AccAddress{from} +} + +// NewMsgWithdrawBurnUndelegate returns a new MsgWithdrawBurnUndelegate. +func NewMsgWithdrawBurnUndelegate(from sdk.AccAddress, validator sdk.ValAddress, amount sdk.Coin) *MsgWithdrawBurnUndelegate { + return &MsgWithdrawBurnUndelegate{ + From: from.String(), + Validator: validator.String(), + Amount: amount, + } +} + +// Route return the message type used for routing the message. +func (msg MsgWithdrawBurnUndelegate) Route() string { return RouterKey } + +// Type returns a human-readable string for the message, intended for utilization within tags. +func (msg MsgWithdrawBurnUndelegate) Type() string { return TypeMsgWithdrawBurnUndelegate } + +// ValidateBasic does a simple validation check that doesn't require access to any other information. +func (msg MsgWithdrawBurnUndelegate) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.From); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid from address: %s", err) + } + + if _, err := sdk.ValAddressFromBech32(msg.Validator); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid validator address: %s", err) + } + + if msg.Amount.IsNil() || !msg.Amount.IsValid() || msg.Amount.IsZero() { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "'%s'", msg.Amount) + } + return nil +} + +// GetSignBytes gets the canonical byte representation of the Msg. +func (msg MsgWithdrawBurnUndelegate) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(&msg) + return sdk.MustSortJSON(bz) +} + +// GetSigners returns the addresses of signers that must sign. +func (msg MsgWithdrawBurnUndelegate) GetSigners() []sdk.AccAddress { + from, _ := sdk.AccAddressFromBech32(msg.From) + return []sdk.AccAddress{from} +} diff --git a/x/router/types/msg_test.go b/x/router/types/msg_test.go new file mode 100644 index 00000000..d0ca3a06 --- /dev/null +++ b/x/router/types/msg_test.go @@ -0,0 +1,207 @@ +package types_test + +import ( + fmt "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/kava-labs/kava/x/router/types" +) + +func TestMsgMintDeposit_Signing(t *testing.T) { + address := mustAccAddressFromBech32("kava1gepm4nwzz40gtpur93alv9f9wm5ht4l0hzzw9d") + validatorAddress := mustValAddressFromBech32("kavavaloper1ypjp0m04pyp73hwgtc0dgkx0e9rrydeckewa42") + + msg := types.NewMsgMintDeposit( + address, + validatorAddress, + sdk.NewCoin("ukava", sdk.NewInt(1e9)), + ) + + // checking for the "type" field ensures the msg is registered on the amino codec + signBytes := []byte( + `{"type":"router/MsgMintDeposit","value":{"amount":{"amount":"1000000000","denom":"ukava"},"depositor":"kava1gepm4nwzz40gtpur93alv9f9wm5ht4l0hzzw9d","validator":"kavavaloper1ypjp0m04pyp73hwgtc0dgkx0e9rrydeckewa42"}}`, + ) + + assert.Equal(t, []sdk.AccAddress{address}, msg.GetSigners()) + assert.Equal(t, signBytes, msg.GetSignBytes()) +} + +func TestMsgDelegateMintDeposit_Signing(t *testing.T) { + address := mustAccAddressFromBech32("kava1gepm4nwzz40gtpur93alv9f9wm5ht4l0hzzw9d") + validatorAddress := mustValAddressFromBech32("kavavaloper1ypjp0m04pyp73hwgtc0dgkx0e9rrydeckewa42") + + msg := types.NewMsgDelegateMintDeposit( + address, + validatorAddress, + sdk.NewCoin("ukava", sdk.NewInt(1e9)), + ) + + // checking for the "type" field ensures the msg is registered on the amino codec + signBytes := []byte( + `{"type":"router/MsgDelegateMintDeposit","value":{"amount":{"amount":"1000000000","denom":"ukava"},"depositor":"kava1gepm4nwzz40gtpur93alv9f9wm5ht4l0hzzw9d","validator":"kavavaloper1ypjp0m04pyp73hwgtc0dgkx0e9rrydeckewa42"}}`, + ) + + assert.Equal(t, []sdk.AccAddress{address}, msg.GetSigners()) + assert.Equal(t, signBytes, msg.GetSignBytes()) +} + +func TestMsgWithdrawBurn_Signing(t *testing.T) { + address := mustAccAddressFromBech32("kava1gepm4nwzz40gtpur93alv9f9wm5ht4l0hzzw9d") + validatorAddress := mustValAddressFromBech32("kavavaloper1ypjp0m04pyp73hwgtc0dgkx0e9rrydeckewa42") + + msg := types.NewMsgWithdrawBurn( + address, + validatorAddress, + sdk.NewCoin("ukava", sdk.NewInt(1e9)), + ) + + // checking for the "type" field ensures the msg is registered on the amino codec + signBytes := []byte( + `{"type":"router/MsgWithdrawBurn","value":{"amount":{"amount":"1000000000","denom":"ukava"},"from":"kava1gepm4nwzz40gtpur93alv9f9wm5ht4l0hzzw9d","validator":"kavavaloper1ypjp0m04pyp73hwgtc0dgkx0e9rrydeckewa42"}}`, + ) + + assert.Equal(t, []sdk.AccAddress{address}, msg.GetSigners()) + assert.Equal(t, signBytes, msg.GetSignBytes()) +} + +func TestMsgWithdrawBurnUndelegate_Signing(t *testing.T) { + address := mustAccAddressFromBech32("kava1gepm4nwzz40gtpur93alv9f9wm5ht4l0hzzw9d") + validatorAddress := mustValAddressFromBech32("kavavaloper1ypjp0m04pyp73hwgtc0dgkx0e9rrydeckewa42") + + msg := types.NewMsgWithdrawBurnUndelegate( + address, + validatorAddress, + sdk.NewCoin("ukava", sdk.NewInt(1e9)), + ) + + // checking for the "type" field ensures the msg is registered on the amino codec + signBytes := []byte( + `{"type":"router/MsgWithdrawBurnUndelegate","value":{"amount":{"amount":"1000000000","denom":"ukava"},"from":"kava1gepm4nwzz40gtpur93alv9f9wm5ht4l0hzzw9d","validator":"kavavaloper1ypjp0m04pyp73hwgtc0dgkx0e9rrydeckewa42"}}`, + ) + + assert.Equal(t, []sdk.AccAddress{address}, msg.GetSigners()) + assert.Equal(t, signBytes, msg.GetSignBytes()) +} + +func TestMsg_Validate(t *testing.T) { + validAddress := "kava1gepm4nwzz40gtpur93alv9f9wm5ht4l0hzzw9d" + validValidatorAddress := "kavavaloper1ypjp0m04pyp73hwgtc0dgkx0e9rrydeckewa42" + validCoin := sdk.NewInt64Coin("ukava", 1e9) + + type msgArgs struct { + depositor string + validator string + amount sdk.Coin + } + tests := []struct { + name string + msgArgs msgArgs + expectedErr error + }{ + { + name: "normal multiplier is valid", + msgArgs: msgArgs{ + depositor: validAddress, + validator: validValidatorAddress, + amount: validCoin, + }, + }, + { + name: "invalid depositor", + msgArgs: msgArgs{ + depositor: "invalid", + validator: validValidatorAddress, + amount: validCoin, + }, + expectedErr: sdkerrors.ErrInvalidAddress, + }, + { + name: "empty depositor", + msgArgs: msgArgs{ + depositor: "", + validator: validValidatorAddress, + amount: validCoin, + }, + expectedErr: sdkerrors.ErrInvalidAddress, + }, + { + name: "invalid validator", + msgArgs: msgArgs{ + depositor: validAddress, + validator: "invalid", + amount: validCoin, + }, + expectedErr: sdkerrors.ErrInvalidAddress, + }, + { + name: "nil coin", + msgArgs: msgArgs{ + depositor: validAddress, + validator: validValidatorAddress, + amount: sdk.Coin{}, + }, + expectedErr: sdkerrors.ErrInvalidCoins, + }, + { + name: "zero coin", + msgArgs: msgArgs{ + depositor: validAddress, + validator: validValidatorAddress, + amount: sdk.NewCoin("ukava", sdk.ZeroInt()), + }, + expectedErr: sdkerrors.ErrInvalidCoins, + }, + { + name: "negative coin", + msgArgs: msgArgs{ + depositor: validAddress, + validator: validValidatorAddress, + amount: sdk.Coin{Denom: "ukava", Amount: sdk.NewInt(-1)}, + }, + expectedErr: sdkerrors.ErrInvalidCoins, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + msgMintDeposit := types.MsgMintDeposit{tc.msgArgs.depositor, tc.msgArgs.validator, tc.msgArgs.amount} + msgDelegateMintDeposit := types.MsgDelegateMintDeposit{tc.msgArgs.depositor, tc.msgArgs.validator, tc.msgArgs.amount} + + msgWithdrawBurn := types.MsgWithdrawBurn{tc.msgArgs.depositor, tc.msgArgs.validator, tc.msgArgs.amount} + msgWithdrawBurnUndelegate := types.MsgWithdrawBurnUndelegate{tc.msgArgs.depositor, tc.msgArgs.validator, tc.msgArgs.amount} + + msgs := []sdk.Msg{&msgMintDeposit, &msgDelegateMintDeposit, &msgWithdrawBurn, &msgWithdrawBurnUndelegate} + for _, msg := range msgs { + t.Run(fmt.Sprintf("%T", msg), func(t *testing.T) { + err := msg.ValidateBasic() + if tc.expectedErr == nil { + require.NoError(t, err) + } else { + require.ErrorIs(t, err, tc.expectedErr, "expected error '%s' not found in actual '%s'", tc.expectedErr, err) + } + }) + } + }) + } +} + +func mustAccAddressFromBech32(address string) sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(address) + if err != nil { + panic(err) + } + return addr +} + +func mustValAddressFromBech32(address string) sdk.ValAddress { + addr, err := sdk.ValAddressFromBech32(address) + if err != nil { + panic(err) + } + return addr +} diff --git a/x/router/types/tx.pb.go b/x/router/types/tx.pb.go new file mode 100644 index 00000000..aca80010 --- /dev/null +++ b/x/router/types/tx.pb.go @@ -0,0 +1,1882 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: kava/router/v1beta1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgMintDeposit converts a delegation into staking derivatives and deposits it all into an earn vault. +type MsgMintDeposit struct { + // depositor represents the owner of the delegation to convert + Depositor string `protobuf:"bytes,1,opt,name=depositor,proto3" json:"depositor,omitempty"` + // validator is the validator for the depositor's delegation + Validator string `protobuf:"bytes,2,opt,name=validator,proto3" json:"validator,omitempty"` + // amount is the delegation balance to convert + Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgMintDeposit) Reset() { *m = MsgMintDeposit{} } +func (m *MsgMintDeposit) String() string { return proto.CompactTextString(m) } +func (*MsgMintDeposit) ProtoMessage() {} +func (*MsgMintDeposit) Descriptor() ([]byte, []int) { + return fileDescriptor_63015631bbbf9425, []int{0} +} +func (m *MsgMintDeposit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMintDeposit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMintDeposit.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgMintDeposit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMintDeposit.Merge(m, src) +} +func (m *MsgMintDeposit) XXX_Size() int { + return m.Size() +} +func (m *MsgMintDeposit) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMintDeposit.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMintDeposit proto.InternalMessageInfo + +// MsgMintDepositResponse defines the Msg/MsgMintDeposit response type. +type MsgMintDepositResponse struct { +} + +func (m *MsgMintDepositResponse) Reset() { *m = MsgMintDepositResponse{} } +func (m *MsgMintDepositResponse) String() string { return proto.CompactTextString(m) } +func (*MsgMintDepositResponse) ProtoMessage() {} +func (*MsgMintDepositResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_63015631bbbf9425, []int{1} +} +func (m *MsgMintDepositResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMintDepositResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMintDepositResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgMintDepositResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMintDepositResponse.Merge(m, src) +} +func (m *MsgMintDepositResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgMintDepositResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMintDepositResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMintDepositResponse proto.InternalMessageInfo + +// MsgDelegateMintDeposit delegates tokens to a validator, then converts them into staking derivatives, +// then deposits to an earn vault. +type MsgDelegateMintDeposit struct { + // depositor represents the owner of the tokens to delegate + Depositor string `protobuf:"bytes,1,opt,name=depositor,proto3" json:"depositor,omitempty"` + // validator is the address of the validator to delegate to + Validator string `protobuf:"bytes,2,opt,name=validator,proto3" json:"validator,omitempty"` + // amount is the tokens to delegate + Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgDelegateMintDeposit) Reset() { *m = MsgDelegateMintDeposit{} } +func (m *MsgDelegateMintDeposit) String() string { return proto.CompactTextString(m) } +func (*MsgDelegateMintDeposit) ProtoMessage() {} +func (*MsgDelegateMintDeposit) Descriptor() ([]byte, []int) { + return fileDescriptor_63015631bbbf9425, []int{2} +} +func (m *MsgDelegateMintDeposit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDelegateMintDeposit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDelegateMintDeposit.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgDelegateMintDeposit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDelegateMintDeposit.Merge(m, src) +} +func (m *MsgDelegateMintDeposit) XXX_Size() int { + return m.Size() +} +func (m *MsgDelegateMintDeposit) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDelegateMintDeposit.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDelegateMintDeposit proto.InternalMessageInfo + +// MsgDelegateMintDepositResponse defines the Msg/MsgDelegateMintDeposit response type. +type MsgDelegateMintDepositResponse struct { +} + +func (m *MsgDelegateMintDepositResponse) Reset() { *m = MsgDelegateMintDepositResponse{} } +func (m *MsgDelegateMintDepositResponse) String() string { return proto.CompactTextString(m) } +func (*MsgDelegateMintDepositResponse) ProtoMessage() {} +func (*MsgDelegateMintDepositResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_63015631bbbf9425, []int{3} +} +func (m *MsgDelegateMintDepositResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDelegateMintDepositResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDelegateMintDepositResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgDelegateMintDepositResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDelegateMintDepositResponse.Merge(m, src) +} +func (m *MsgDelegateMintDepositResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgDelegateMintDepositResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDelegateMintDepositResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDelegateMintDepositResponse proto.InternalMessageInfo + +// MsgWithdrawBurn removes staking derivatives from an earn vault and converts them back to a staking delegation. +type MsgWithdrawBurn struct { + // from is the owner of the earn vault to withdraw from + From string `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + // validator is the address to select the derivative denom to withdraw + Validator string `protobuf:"bytes,2,opt,name=validator,proto3" json:"validator,omitempty"` + // amount is the staked token equivalent to withdraw + Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgWithdrawBurn) Reset() { *m = MsgWithdrawBurn{} } +func (m *MsgWithdrawBurn) String() string { return proto.CompactTextString(m) } +func (*MsgWithdrawBurn) ProtoMessage() {} +func (*MsgWithdrawBurn) Descriptor() ([]byte, []int) { + return fileDescriptor_63015631bbbf9425, []int{4} +} +func (m *MsgWithdrawBurn) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgWithdrawBurn) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgWithdrawBurn.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgWithdrawBurn) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithdrawBurn.Merge(m, src) +} +func (m *MsgWithdrawBurn) XXX_Size() int { + return m.Size() +} +func (m *MsgWithdrawBurn) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithdrawBurn.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithdrawBurn proto.InternalMessageInfo + +// MsgWithdrawBurnResponse defines the Msg/MsgWithdrawBurn response type. +type MsgWithdrawBurnResponse struct { +} + +func (m *MsgWithdrawBurnResponse) Reset() { *m = MsgWithdrawBurnResponse{} } +func (m *MsgWithdrawBurnResponse) String() string { return proto.CompactTextString(m) } +func (*MsgWithdrawBurnResponse) ProtoMessage() {} +func (*MsgWithdrawBurnResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_63015631bbbf9425, []int{5} +} +func (m *MsgWithdrawBurnResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgWithdrawBurnResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgWithdrawBurnResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgWithdrawBurnResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithdrawBurnResponse.Merge(m, src) +} +func (m *MsgWithdrawBurnResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgWithdrawBurnResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithdrawBurnResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithdrawBurnResponse proto.InternalMessageInfo + +// MsgWithdrawBurnUndelegate removes staking derivatives from an earn vault, converts them to a staking delegation, +// then undelegates them from their validator. +type MsgWithdrawBurnUndelegate struct { + // from is the owner of the earn vault to withdraw from + From string `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + // validator is the address to select the derivative denom to withdraw + Validator string `protobuf:"bytes,2,opt,name=validator,proto3" json:"validator,omitempty"` + // amount is the staked token equivalent to withdraw + Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgWithdrawBurnUndelegate) Reset() { *m = MsgWithdrawBurnUndelegate{} } +func (m *MsgWithdrawBurnUndelegate) String() string { return proto.CompactTextString(m) } +func (*MsgWithdrawBurnUndelegate) ProtoMessage() {} +func (*MsgWithdrawBurnUndelegate) Descriptor() ([]byte, []int) { + return fileDescriptor_63015631bbbf9425, []int{6} +} +func (m *MsgWithdrawBurnUndelegate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgWithdrawBurnUndelegate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgWithdrawBurnUndelegate.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgWithdrawBurnUndelegate) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithdrawBurnUndelegate.Merge(m, src) +} +func (m *MsgWithdrawBurnUndelegate) XXX_Size() int { + return m.Size() +} +func (m *MsgWithdrawBurnUndelegate) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithdrawBurnUndelegate.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithdrawBurnUndelegate proto.InternalMessageInfo + +// MsgWithdrawBurnUndelegateResponse defines the Msg/MsgWithdrawBurnUndelegate response type. +type MsgWithdrawBurnUndelegateResponse struct { +} + +func (m *MsgWithdrawBurnUndelegateResponse) Reset() { *m = MsgWithdrawBurnUndelegateResponse{} } +func (m *MsgWithdrawBurnUndelegateResponse) String() string { return proto.CompactTextString(m) } +func (*MsgWithdrawBurnUndelegateResponse) ProtoMessage() {} +func (*MsgWithdrawBurnUndelegateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_63015631bbbf9425, []int{7} +} +func (m *MsgWithdrawBurnUndelegateResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgWithdrawBurnUndelegateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgWithdrawBurnUndelegateResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgWithdrawBurnUndelegateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithdrawBurnUndelegateResponse.Merge(m, src) +} +func (m *MsgWithdrawBurnUndelegateResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgWithdrawBurnUndelegateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithdrawBurnUndelegateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithdrawBurnUndelegateResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgMintDeposit)(nil), "kava.router.v1beta1.MsgMintDeposit") + proto.RegisterType((*MsgMintDepositResponse)(nil), "kava.router.v1beta1.MsgMintDepositResponse") + proto.RegisterType((*MsgDelegateMintDeposit)(nil), "kava.router.v1beta1.MsgDelegateMintDeposit") + proto.RegisterType((*MsgDelegateMintDepositResponse)(nil), "kava.router.v1beta1.MsgDelegateMintDepositResponse") + proto.RegisterType((*MsgWithdrawBurn)(nil), "kava.router.v1beta1.MsgWithdrawBurn") + proto.RegisterType((*MsgWithdrawBurnResponse)(nil), "kava.router.v1beta1.MsgWithdrawBurnResponse") + proto.RegisterType((*MsgWithdrawBurnUndelegate)(nil), "kava.router.v1beta1.MsgWithdrawBurnUndelegate") + proto.RegisterType((*MsgWithdrawBurnUndelegateResponse)(nil), "kava.router.v1beta1.MsgWithdrawBurnUndelegateResponse") +} + +func init() { proto.RegisterFile("kava/router/v1beta1/tx.proto", fileDescriptor_63015631bbbf9425) } + +var fileDescriptor_63015631bbbf9425 = []byte{ + // 473 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x94, 0x4f, 0x6b, 0x13, 0x41, + 0x18, 0xc6, 0x77, 0x4c, 0x29, 0xe4, 0xad, 0x28, 0x6c, 0x4b, 0x4d, 0x96, 0x32, 0xc6, 0xd4, 0x43, + 0xc0, 0x76, 0x96, 0xb6, 0x50, 0xcf, 0xc6, 0xe2, 0x2d, 0x97, 0x88, 0x08, 0x5e, 0xca, 0x6c, 0x76, + 0x9c, 0x0e, 0x26, 0x33, 0x61, 0x66, 0x36, 0xad, 0x37, 0x3f, 0x82, 0x27, 0xaf, 0x7a, 0xf3, 0x0b, + 0xf8, 0x19, 0x24, 0xc7, 0xe2, 0xc9, 0x93, 0x68, 0xf2, 0x45, 0x64, 0xff, 0xa6, 0x29, 0xbb, 0x98, + 0x1e, 0x84, 0xde, 0x66, 0xe7, 0xf9, 0xbd, 0xcf, 0xfb, 0xbc, 0xf0, 0xee, 0xc0, 0xce, 0x3b, 0x3a, + 0xa1, 0xbe, 0x56, 0x91, 0x65, 0xda, 0x9f, 0x1c, 0x04, 0xcc, 0xd2, 0x03, 0xdf, 0x5e, 0x90, 0xb1, + 0x56, 0x56, 0xb9, 0x9b, 0xb1, 0x4a, 0x52, 0x95, 0x64, 0xaa, 0xd7, 0x1c, 0x28, 0x33, 0x52, 0xe6, + 0x34, 0x41, 0xfc, 0xf4, 0x23, 0xe5, 0x3d, 0x9c, 0x7e, 0xf9, 0x01, 0x35, 0xac, 0x70, 0x1b, 0x28, + 0x21, 0x33, 0x7d, 0x8b, 0x2b, 0xae, 0xd2, 0xba, 0xf8, 0x94, 0xde, 0xb6, 0x3f, 0x23, 0xb8, 0xd7, + 0x33, 0xbc, 0x27, 0xa4, 0x3d, 0x61, 0x63, 0x65, 0x84, 0x75, 0x8f, 0xa1, 0x1e, 0xa6, 0x47, 0xa5, + 0x1b, 0xa8, 0x85, 0x3a, 0xf5, 0x6e, 0xe3, 0xc7, 0xb7, 0xfd, 0xad, 0xac, 0xdb, 0xb3, 0x30, 0xd4, + 0xcc, 0x98, 0x97, 0x56, 0x0b, 0xc9, 0xfb, 0x0b, 0xd4, 0xdd, 0x81, 0xfa, 0x84, 0x0e, 0x45, 0x48, + 0xe3, 0xba, 0x3b, 0x71, 0x5d, 0x7f, 0x71, 0xe1, 0x3e, 0x85, 0x75, 0x3a, 0x52, 0x91, 0xb4, 0x8d, + 0x5a, 0x0b, 0x75, 0x36, 0x0e, 0x9b, 0x24, 0xf3, 0x8b, 0xf3, 0xe6, 0xf3, 0x91, 0xe7, 0x4a, 0xc8, + 0xee, 0xda, 0xf4, 0xd7, 0x43, 0xa7, 0x9f, 0xe1, 0xed, 0x06, 0x6c, 0x2f, 0x07, 0xec, 0x33, 0x33, + 0x56, 0xd2, 0xb0, 0xf6, 0x57, 0x94, 0x48, 0x27, 0x6c, 0xc8, 0x38, 0xb5, 0xec, 0x16, 0xcf, 0xd0, + 0x02, 0x5c, 0x1e, 0xb4, 0x98, 0xe5, 0x13, 0x82, 0xfb, 0x3d, 0xc3, 0x5f, 0x0b, 0x7b, 0x16, 0x6a, + 0x7a, 0xde, 0x8d, 0xb4, 0x74, 0xf7, 0x60, 0xed, 0xad, 0x56, 0xa3, 0x7f, 0xe6, 0x4f, 0xa8, 0xff, + 0x15, 0xbd, 0x09, 0x0f, 0xae, 0xe5, 0x2a, 0x32, 0x7f, 0x41, 0xd0, 0xbc, 0xa6, 0xbd, 0x92, 0x61, + 0x36, 0xe4, 0xed, 0x48, 0xbf, 0x0b, 0x8f, 0x2a, 0x13, 0xe6, 0x73, 0x1c, 0x7e, 0xaf, 0x41, 0xad, + 0x67, 0xb8, 0x7b, 0x0a, 0x1b, 0x57, 0x77, 0x68, 0x97, 0x94, 0xfc, 0x81, 0x64, 0x79, 0x17, 0xbd, + 0x27, 0x2b, 0x40, 0x79, 0x23, 0xf7, 0x1c, 0x36, 0xcb, 0x96, 0xb5, 0xd2, 0xa3, 0x04, 0xf6, 0x8e, + 0x6e, 0x00, 0x17, 0x8d, 0x03, 0xb8, 0xbb, 0xb4, 0x59, 0x8f, 0xab, 0x4c, 0xae, 0x52, 0xde, 0xde, + 0x2a, 0x54, 0xd1, 0xe3, 0x03, 0x82, 0xed, 0x8a, 0x55, 0x20, 0xab, 0x18, 0x2d, 0x78, 0xef, 0xf8, + 0x66, 0x7c, 0x1e, 0xa1, 0xfb, 0x62, 0xfa, 0x07, 0x3b, 0xd3, 0x19, 0x46, 0x97, 0x33, 0x8c, 0x7e, + 0xcf, 0x30, 0xfa, 0x38, 0xc7, 0xce, 0xe5, 0x1c, 0x3b, 0x3f, 0xe7, 0xd8, 0x79, 0xd3, 0xe1, 0xc2, + 0x9e, 0x45, 0x01, 0x19, 0xa8, 0x91, 0x1f, 0xfb, 0xef, 0x0f, 0x69, 0x60, 0x92, 0x93, 0x7f, 0x91, + 0xbf, 0xc2, 0xf6, 0xfd, 0x98, 0x99, 0x60, 0x3d, 0x79, 0x1b, 0x8f, 0xfe, 0x06, 0x00, 0x00, 0xff, + 0xff, 0xb1, 0xc1, 0x92, 0xc8, 0xa1, 0x05, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // MintDeposit converts a delegation into staking derivatives and deposits it all into an earn vault. + MintDeposit(ctx context.Context, in *MsgMintDeposit, opts ...grpc.CallOption) (*MsgMintDepositResponse, error) + // DelegateMintDeposit delegates tokens to a validator, then converts them into staking derivatives, + // then deposits to an earn vault. + DelegateMintDeposit(ctx context.Context, in *MsgDelegateMintDeposit, opts ...grpc.CallOption) (*MsgDelegateMintDepositResponse, error) + // WithdrawBurn removes staking derivatives from an earn vault and converts them back to a staking delegation. + WithdrawBurn(ctx context.Context, in *MsgWithdrawBurn, opts ...grpc.CallOption) (*MsgWithdrawBurnResponse, error) + // WithdrawBurnUndelegate removes staking derivatives from an earn vault, converts them to a staking delegation, + // then undelegates them from their validator. + WithdrawBurnUndelegate(ctx context.Context, in *MsgWithdrawBurnUndelegate, opts ...grpc.CallOption) (*MsgWithdrawBurnUndelegateResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) MintDeposit(ctx context.Context, in *MsgMintDeposit, opts ...grpc.CallOption) (*MsgMintDepositResponse, error) { + out := new(MsgMintDepositResponse) + err := c.cc.Invoke(ctx, "/kava.router.v1beta1.Msg/MintDeposit", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) DelegateMintDeposit(ctx context.Context, in *MsgDelegateMintDeposit, opts ...grpc.CallOption) (*MsgDelegateMintDepositResponse, error) { + out := new(MsgDelegateMintDepositResponse) + err := c.cc.Invoke(ctx, "/kava.router.v1beta1.Msg/DelegateMintDeposit", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) WithdrawBurn(ctx context.Context, in *MsgWithdrawBurn, opts ...grpc.CallOption) (*MsgWithdrawBurnResponse, error) { + out := new(MsgWithdrawBurnResponse) + err := c.cc.Invoke(ctx, "/kava.router.v1beta1.Msg/WithdrawBurn", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) WithdrawBurnUndelegate(ctx context.Context, in *MsgWithdrawBurnUndelegate, opts ...grpc.CallOption) (*MsgWithdrawBurnUndelegateResponse, error) { + out := new(MsgWithdrawBurnUndelegateResponse) + err := c.cc.Invoke(ctx, "/kava.router.v1beta1.Msg/WithdrawBurnUndelegate", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // MintDeposit converts a delegation into staking derivatives and deposits it all into an earn vault. + MintDeposit(context.Context, *MsgMintDeposit) (*MsgMintDepositResponse, error) + // DelegateMintDeposit delegates tokens to a validator, then converts them into staking derivatives, + // then deposits to an earn vault. + DelegateMintDeposit(context.Context, *MsgDelegateMintDeposit) (*MsgDelegateMintDepositResponse, error) + // WithdrawBurn removes staking derivatives from an earn vault and converts them back to a staking delegation. + WithdrawBurn(context.Context, *MsgWithdrawBurn) (*MsgWithdrawBurnResponse, error) + // WithdrawBurnUndelegate removes staking derivatives from an earn vault, converts them to a staking delegation, + // then undelegates them from their validator. + WithdrawBurnUndelegate(context.Context, *MsgWithdrawBurnUndelegate) (*MsgWithdrawBurnUndelegateResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) MintDeposit(ctx context.Context, req *MsgMintDeposit) (*MsgMintDepositResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method MintDeposit not implemented") +} +func (*UnimplementedMsgServer) DelegateMintDeposit(ctx context.Context, req *MsgDelegateMintDeposit) (*MsgDelegateMintDepositResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelegateMintDeposit not implemented") +} +func (*UnimplementedMsgServer) WithdrawBurn(ctx context.Context, req *MsgWithdrawBurn) (*MsgWithdrawBurnResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method WithdrawBurn not implemented") +} +func (*UnimplementedMsgServer) WithdrawBurnUndelegate(ctx context.Context, req *MsgWithdrawBurnUndelegate) (*MsgWithdrawBurnUndelegateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method WithdrawBurnUndelegate not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_MintDeposit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgMintDeposit) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).MintDeposit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/kava.router.v1beta1.Msg/MintDeposit", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).MintDeposit(ctx, req.(*MsgMintDeposit)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_DelegateMintDeposit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgDelegateMintDeposit) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).DelegateMintDeposit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/kava.router.v1beta1.Msg/DelegateMintDeposit", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).DelegateMintDeposit(ctx, req.(*MsgDelegateMintDeposit)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_WithdrawBurn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgWithdrawBurn) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).WithdrawBurn(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/kava.router.v1beta1.Msg/WithdrawBurn", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).WithdrawBurn(ctx, req.(*MsgWithdrawBurn)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_WithdrawBurnUndelegate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgWithdrawBurnUndelegate) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).WithdrawBurnUndelegate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/kava.router.v1beta1.Msg/WithdrawBurnUndelegate", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).WithdrawBurnUndelegate(ctx, req.(*MsgWithdrawBurnUndelegate)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "kava.router.v1beta1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "MintDeposit", + Handler: _Msg_MintDeposit_Handler, + }, + { + MethodName: "DelegateMintDeposit", + Handler: _Msg_DelegateMintDeposit_Handler, + }, + { + MethodName: "WithdrawBurn", + Handler: _Msg_WithdrawBurn_Handler, + }, + { + MethodName: "WithdrawBurnUndelegate", + Handler: _Msg_WithdrawBurnUndelegate_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "kava/router/v1beta1/tx.proto", +} + +func (m *MsgMintDeposit) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgMintDeposit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMintDeposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.Validator) > 0 { + i -= len(m.Validator) + copy(dAtA[i:], m.Validator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Validator))) + i-- + dAtA[i] = 0x12 + } + if len(m.Depositor) > 0 { + i -= len(m.Depositor) + copy(dAtA[i:], m.Depositor) + i = encodeVarintTx(dAtA, i, uint64(len(m.Depositor))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgMintDepositResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgMintDepositResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMintDepositResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgDelegateMintDeposit) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgDelegateMintDeposit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDelegateMintDeposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.Validator) > 0 { + i -= len(m.Validator) + copy(dAtA[i:], m.Validator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Validator))) + i-- + dAtA[i] = 0x12 + } + if len(m.Depositor) > 0 { + i -= len(m.Depositor) + copy(dAtA[i:], m.Depositor) + i = encodeVarintTx(dAtA, i, uint64(len(m.Depositor))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgDelegateMintDepositResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgDelegateMintDepositResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDelegateMintDepositResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgWithdrawBurn) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgWithdrawBurn) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgWithdrawBurn) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.Validator) > 0 { + i -= len(m.Validator) + copy(dAtA[i:], m.Validator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Validator))) + i-- + dAtA[i] = 0x12 + } + if len(m.From) > 0 { + i -= len(m.From) + copy(dAtA[i:], m.From) + i = encodeVarintTx(dAtA, i, uint64(len(m.From))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgWithdrawBurnResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgWithdrawBurnResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgWithdrawBurnResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgWithdrawBurnUndelegate) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgWithdrawBurnUndelegate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgWithdrawBurnUndelegate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.Validator) > 0 { + i -= len(m.Validator) + copy(dAtA[i:], m.Validator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Validator))) + i-- + dAtA[i] = 0x12 + } + if len(m.From) > 0 { + i -= len(m.From) + copy(dAtA[i:], m.From) + i = encodeVarintTx(dAtA, i, uint64(len(m.From))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgWithdrawBurnUndelegateResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgWithdrawBurnUndelegateResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgWithdrawBurnUndelegateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgMintDeposit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Depositor) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Validator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgMintDepositResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgDelegateMintDeposit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Depositor) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Validator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgDelegateMintDepositResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgWithdrawBurn) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.From) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Validator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgWithdrawBurnResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgWithdrawBurnUndelegate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.From) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Validator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgWithdrawBurnUndelegateResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgMintDeposit) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgMintDeposit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgMintDeposit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Depositor", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Depositor = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Validator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Validator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgMintDepositResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgMintDepositResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgMintDepositResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgDelegateMintDeposit) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgDelegateMintDeposit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDelegateMintDeposit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Depositor", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Depositor = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Validator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Validator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgDelegateMintDepositResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgDelegateMintDepositResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDelegateMintDepositResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgWithdrawBurn) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgWithdrawBurn: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgWithdrawBurn: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field From", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.From = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Validator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Validator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgWithdrawBurnResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgWithdrawBurnResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgWithdrawBurnResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgWithdrawBurnUndelegate) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgWithdrawBurnUndelegate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgWithdrawBurnUndelegate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field From", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.From = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Validator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Validator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgWithdrawBurnUndelegateResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgWithdrawBurnUndelegateResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgWithdrawBurnUndelegateResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +)