diff --git a/app/test_common.go b/app/test_common.go index 58d48f57..33f95f8e 100644 --- a/app/test_common.go +++ b/app/test_common.go @@ -33,6 +33,7 @@ import ( bep3keeper "github.com/kava-labs/kava/x/bep3/keeper" cdpkeeper "github.com/kava-labs/kava/x/cdp/keeper" committeekeeper "github.com/kava-labs/kava/x/committee/keeper" + earnkeeper "github.com/kava-labs/kava/x/earn/keeper" evmutilkeeper "github.com/kava-labs/kava/x/evmutil/keeper" hardkeeper "github.com/kava-labs/kava/x/hard/keeper" incentivekeeper "github.com/kava-labs/kava/x/incentive/keeper" @@ -106,6 +107,7 @@ func (tApp TestApp) GetIncentiveKeeper() incentivekeeper.Keeper { return tApp.in func (tApp TestApp) GetEvmutilKeeper() evmutilkeeper.Keeper { return tApp.evmutilKeeper } func (tApp TestApp) GetEvmKeeper() *evmkeeper.Keeper { return tApp.evmKeeper } func (tApp TestApp) GetSavingsKeeper() savingskeeper.Keeper { return tApp.savingsKeeper } +func (tApp TestApp) GetEarnKeeper() earnkeeper.Keeper { return tApp.earnKeeper } // LegacyAmino returns the app's amino codec. func (app *App) LegacyAmino() *codec.LegacyAmino { diff --git a/contrib/devnet/init-new-chain.sh b/contrib/devnet/init-new-chain.sh index 521faf24..fbe643fe 100755 --- a/contrib/devnet/init-new-chain.sh +++ b/contrib/devnet/init-new-chain.sh @@ -115,3 +115,9 @@ jq '.app_state.bridge.params.enabled_conversion_pairs = [ denom: "erc20/weth", }]' $DATA/config/genesis.json | sponge $DATA/config/genesis.json +# Add earn vault +jq '.app_state.earn.params.allowed_vaults = [ + { + denom: "ukava", + vault_strategy: 2, + }]' $DATA/config/genesis.json | sponge $DATA/config/genesis.json diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index 9aff526b..931be305 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -178,9 +178,19 @@ - [Msg](#kava.committee.v1beta1.Msg) +- [kava/earn/v1beta1/strategy.proto](#kava/earn/v1beta1/strategy.proto) + - [StrategyType](#kava.earn.v1beta1.StrategyType) + +- [kava/earn/v1beta1/vault.proto](#kava/earn/v1beta1/vault.proto) + - [AllowedVault](#kava.earn.v1beta1.AllowedVault) + - [VaultRecord](#kava.earn.v1beta1.VaultRecord) + - [VaultShareRecord](#kava.earn.v1beta1.VaultShareRecord) + +- [kava/earn/v1beta1/params.proto](#kava/earn/v1beta1/params.proto) + - [Params](#kava.earn.v1beta1.Params) + - [kava/earn/v1beta1/genesis.proto](#kava/earn/v1beta1/genesis.proto) - [GenesisState](#kava.earn.v1beta1.GenesisState) - - [Params](#kava.earn.v1beta1.Params) - [kava/earn/v1beta1/query.proto](#kava/earn/v1beta1/query.proto) - [QueryParamsRequest](#kava.earn.v1beta1.QueryParamsRequest) @@ -189,6 +199,11 @@ - [Query](#kava.earn.v1beta1.Query) - [kava/earn/v1beta1/tx.proto](#kava/earn/v1beta1/tx.proto) + - [MsgDeposit](#kava.earn.v1beta1.MsgDeposit) + - [MsgDepositResponse](#kava.earn.v1beta1.MsgDepositResponse) + - [MsgWithdraw](#kava.earn.v1beta1.MsgWithdraw) + - [MsgWithdrawResponse](#kava.earn.v1beta1.MsgWithdrawResponse) + - [Msg](#kava.earn.v1beta1.Msg) - [kava/evmutil/v1beta1/genesis.proto](#kava/evmutil/v1beta1/genesis.proto) @@ -2720,6 +2735,133 @@ Msg defines the committee Msg service + +

Top

+ +## kava/earn/v1beta1/strategy.proto + + + + + + + +### StrategyType + + +| Name | Number | Description | +| ---- | ------ | ----------- | +| STRATEGY_TYPE_UNKNOWN | 0 | | +| STRATEGY_TYPE_KAVA_STAKERS | 1 | | +| STRATEGY_TYPE_STABLECOIN_STAKERS | 2 | USDC / BUSD vaults use the same strategy but with the denom set in VaultRecord | +| STRATEGY_TYPE_KAVA_FOUNDATION | 3 | | + + + + + + + + + + + +

Top

+ +## kava/earn/v1beta1/vault.proto + + + + + +### AllowedVault +AllowedVault is a vault that is allowed to be created. These can be +modified via parameter governance. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `denom` | [string](#string) | | Denom is the only supported denomination of the vault for deposits and withdrawals. | +| `vault_strategy` | [StrategyType](#kava.earn.v1beta1.StrategyType) | | VaultStrategy is the strategies to use for this vault. | + + + + + + + + +### VaultRecord +VaultRecord is the state of a vault and is used to store the state of a +vault. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `denom` | [string](#string) | | Denom is the only supported denomination of the vault for deposits and withdrawals. | +| `total_supply` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | TotalSupply is the total supply of the vault, denominated **only** in the user deposit/withdrawal denom, must be the same as the Denom field. | + + + + + + + + +### VaultShareRecord +VaultShareRecord defines the shares owned by a depositor and vault. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `depositor` | [bytes](#bytes) | | depositor represents the owner of the shares | +| `amount_supplied` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | amount_supplied represents the total amount a depositor has supplied to the vault. The vault is determined by the coin denom. | + + + + + + + + + + + + + + + + +

Top

+ +## kava/earn/v1beta1/params.proto + + + + + +### Params + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `allowed_vaults` | [AllowedVault](#kava.earn.v1beta1.AllowedVault) | repeated | | + + + + + + + + + + + + + + +

Top

@@ -2730,22 +2872,14 @@ Msg defines the committee Msg service ### GenesisState -GenesisState defines the earn module's genesis state. +GenesisState defines the swap module's genesis state. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `params` | [Params](#kava.earn.v1beta1.Params) | | params defines all the paramaters related to earn | - - - - - - - - -### Params -Params defines the parameters for the earn module. +| `vault_records` | [VaultRecord](#kava.earn.v1beta1.VaultRecord) | repeated | vault_records defines the available vaults | +| `vault_share_records` | [VaultShareRecord](#kava.earn.v1beta1.VaultShareRecord) | repeated | share_records defines the owned shares of each vault | @@ -2818,6 +2952,58 @@ Query defines the gRPC querier service for earn module ## kava/earn/v1beta1/tx.proto + + + +### MsgDeposit +MsgDeposit represents a message for depositing assedts into a vault + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `depositor` | [string](#string) | | depositor represents the address to deposit funds from | +| `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | Amount represents the token to deposit. The vault corresponds to the denom of the amount coin. | + + + + + + + + +### MsgDepositResponse +MsgDepositResponse defines the Msg/Deposit response type. + + + + + + + + +### MsgWithdraw +MsgWithdraw represents a message for withdrawing liquidity from a vault + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `from` | [string](#string) | | from represents the address we are withdrawing for | +| `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | Amount represents the token to withdraw. The vault corresponds to the denom of the amount coin. | + + + + + + + + +### MsgWithdrawResponse +MsgWithdrawResponse defines the Msg/Withdraw response type. + + + + + @@ -2832,6 +3018,8 @@ Msg defines the earn Msg service. | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `Deposit` | [MsgDeposit](#kava.earn.v1beta1.MsgDeposit) | [MsgDepositResponse](#kava.earn.v1beta1.MsgDepositResponse) | Deposit defines a method for depositing assets into a vault | | +| `Withdraw` | [MsgWithdraw](#kava.earn.v1beta1.MsgWithdraw) | [MsgWithdrawResponse](#kava.earn.v1beta1.MsgWithdrawResponse) | Withdraw defines a method for withdrawing assets into a vault | | diff --git a/proto/kava/earn/v1beta1/genesis.proto b/proto/kava/earn/v1beta1/genesis.proto index 384bfc05..cb6c889e 100644 --- a/proto/kava/earn/v1beta1/genesis.proto +++ b/proto/kava/earn/v1beta1/genesis.proto @@ -3,13 +3,17 @@ package kava.earn.v1beta1; option go_package = "github.com/kava-labs/kava/x/earn/types"; +import "kava/earn/v1beta1/vault.proto"; +import "kava/earn/v1beta1/params.proto"; import "gogoproto/gogo.proto"; -// GenesisState defines the earn module's genesis state. +// GenesisState defines the swap module's genesis state. message GenesisState { // params defines all the paramaters related to earn Params params = 1 [(gogoproto.nullable) = false]; + // vault_records defines the available vaults + repeated VaultRecord vault_records = 2 [(gogoproto.castrepeated) = "VaultRecords", (gogoproto.nullable) = false]; + // share_records defines the owned shares of each vault + repeated VaultShareRecord vault_share_records = 3 + [(gogoproto.castrepeated) = "VaultShareRecords", (gogoproto.nullable) = false]; } - -// Params defines the parameters for the earn module. -message Params {} diff --git a/proto/kava/earn/v1beta1/params.proto b/proto/kava/earn/v1beta1/params.proto new file mode 100644 index 00000000..3481aea2 --- /dev/null +++ b/proto/kava/earn/v1beta1/params.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; +package kava.earn.v1beta1; + +option go_package = "github.com/kava-labs/kava/x/earn/types"; + +import "gogoproto/gogo.proto"; +import "kava/earn/v1beta1/vault.proto"; + +message Params { + repeated AllowedVault allowed_vaults = 1 [(gogoproto.castrepeated) = "AllowedVaults", (gogoproto.nullable) = false]; +} diff --git a/proto/kava/earn/v1beta1/query.proto b/proto/kava/earn/v1beta1/query.proto index 2e6a9578..a1a5cf8c 100644 --- a/proto/kava/earn/v1beta1/query.proto +++ b/proto/kava/earn/v1beta1/query.proto @@ -6,7 +6,7 @@ option go_package = "github.com/kava-labs/kava/x/earn/types"; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; import "cosmos_proto/cosmos.proto"; -import "kava/earn/v1beta1/genesis.proto"; +import "kava/earn/v1beta1/params.proto"; // Query defines the gRPC querier service for earn module service Query { diff --git a/proto/kava/earn/v1beta1/strategy.proto b/proto/kava/earn/v1beta1/strategy.proto new file mode 100644 index 00000000..4af69980 --- /dev/null +++ b/proto/kava/earn/v1beta1/strategy.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; +package kava.earn.v1beta1; + +option go_package = "github.com/kava-labs/kava/x/earn/types"; + +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos_proto/cosmos.proto"; + +enum StrategyType { + option (gogoproto.goproto_enum_prefix) = false; + + STRATEGY_TYPE_UNKNOWN = 0; + STRATEGY_TYPE_KAVA_STAKERS = 1; + // USDC / BUSD vaults use the same strategy but with the denom set in VaultRecord + STRATEGY_TYPE_STABLECOIN_STAKERS = 2; + STRATEGY_TYPE_KAVA_FOUNDATION = 3; +} diff --git a/proto/kava/earn/v1beta1/tx.proto b/proto/kava/earn/v1beta1/tx.proto index 7f178677..6c7de65e 100644 --- a/proto/kava/earn/v1beta1/tx.proto +++ b/proto/kava/earn/v1beta1/tx.proto @@ -1,7 +1,45 @@ syntax = "proto3"; package kava.earn.v1beta1; +import "gogoproto/gogo.proto"; +import "cosmos_proto/cosmos.proto"; +import "cosmos/base/v1beta1/coin.proto"; + option go_package = "github.com/kava-labs/kava/x/earn/types"; // Msg defines the earn Msg service. -service Msg {} +service Msg { + // Deposit defines a method for depositing assets into a vault + rpc Deposit(MsgDeposit) returns (MsgDepositResponse); + // Withdraw defines a method for withdrawing assets into a vault + rpc Withdraw(MsgWithdraw) returns (MsgWithdrawResponse); +} + +// MsgDeposit represents a message for depositing assedts into a vault +message MsgDeposit { + option (gogoproto.goproto_getters) = false; + + // depositor represents the address to deposit funds from + string depositor = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // Amount represents the token to deposit. The vault corresponds to the denom + // of the amount coin. + cosmos.base.v1beta1.Coin amount = 2 [(gogoproto.nullable) = false]; +} + +// MsgDepositResponse defines the Msg/Deposit response type. +message MsgDepositResponse {} + +// MsgWithdraw represents a message for withdrawing liquidity from a vault +message MsgWithdraw { + option (gogoproto.goproto_getters) = false; + + // from represents the address we are withdrawing for + string from = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // Amount represents the token to withdraw. The vault corresponds to the denom + // of the amount coin. + cosmos.base.v1beta1.Coin amount = 2 [(gogoproto.nullable) = false]; +} + +// MsgWithdrawResponse defines the Msg/Withdraw response type. +message MsgWithdrawResponse {} \ No newline at end of file diff --git a/proto/kava/earn/v1beta1/vault.proto b/proto/kava/earn/v1beta1/vault.proto new file mode 100644 index 00000000..b133b41d --- /dev/null +++ b/proto/kava/earn/v1beta1/vault.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; +package kava.earn.v1beta1; + +option go_package = "github.com/kava-labs/kava/x/earn/types"; + +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos_proto/cosmos.proto"; +import "kava/earn/v1beta1/strategy.proto"; + +// AllowedVault is a vault that is allowed to be created. These can be +// modified via parameter governance. +message AllowedVault { + // Denom is the only supported denomination of the vault for deposits and withdrawals. + string denom = 1; + + // VaultStrategy is the strategies to use for this vault. + StrategyType vault_strategy = 2; +} + +// VaultRecord is the state of a vault and is used to store the state of a +// vault. +message VaultRecord { + // Denom is the only supported denomination of the vault for deposits and + // withdrawals. + string denom = 1; + // TotalSupply is the total supply of the vault, denominated **only** in the + // user deposit/withdrawal denom, must be the same as the Denom field. + cosmos.base.v1beta1.Coin total_supply = 2 [(gogoproto.nullable) = false]; +} + +// VaultShareRecord defines the shares owned by a depositor and vault. +message VaultShareRecord { + // depositor represents the owner of the shares + bytes depositor = 1 [ + (cosmos_proto.scalar) = "cosmos.AddressBytes", + (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress" + ]; + // amount_supplied represents the total amount a depositor has supplied to the + // vault. The vault is determined by the coin denom. + cosmos.base.v1beta1.Coin amount_supplied = 2 [(gogoproto.nullable) = false]; +} \ No newline at end of file diff --git a/x/earn/client/cli/query.go b/x/earn/client/cli/query.go new file mode 100644 index 00000000..c1e7097b --- /dev/null +++ b/x/earn/client/cli/query.go @@ -0,0 +1,60 @@ +package cli + +import ( + "context" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + + "github.com/kava-labs/kava/x/earn/types" +) + +// GetQueryCmd returns the cli query commands for the earn module +func GetQueryCmd() *cobra.Command { + earnQueryCommand := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the earn module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmds := []*cobra.Command{ + queryParamsCmd(), + } + + for _, cmd := range cmds { + flags.AddQueryFlagsToCmd(cmd) + } + + earnQueryCommand.AddCommand(cmds...) + + return earnQueryCommand +} + +func queryParamsCmd() *cobra.Command { + return &cobra.Command{ + Use: "params", + Short: "get the earn module parameters", + Long: "Get the current earn module parameters.", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + req := types.NewQueryParamsRequest() + res, err := queryClient.Params(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(&res.Params) + }, + } +} diff --git a/x/earn/client/cli/tx.go b/x/earn/client/cli/tx.go new file mode 100644 index 00000000..0591782c --- /dev/null +++ b/x/earn/client/cli/tx.go @@ -0,0 +1,101 @@ +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" + "github.com/cosmos/cosmos-sdk/version" + + "github.com/kava-labs/kava/x/earn/types" +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd() *cobra.Command { + swapTxCmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmds := []*cobra.Command{ + getCmdDeposit(), + getCmdWithdraw(), + } + + for _, cmd := range cmds { + flags.AddTxFlagsToCmd(cmd) + } + + swapTxCmd.AddCommand(cmds...) + + return swapTxCmd +} + +func getCmdDeposit() *cobra.Command { + return &cobra.Command{ + Use: "deposit [amount]", + Short: "deposit coins to an earn vault", + Example: fmt.Sprintf( + `%s tx %s deposit 10000000ukava --from `, + version.AppName, types.ModuleName, + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + amount, err := sdk.ParseCoinNormalized(args[0]) + if err != nil { + return err + } + + signer := clientCtx.GetFromAddress() + msg := types.NewMsgDeposit(signer.String(), amount) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } +} + +func getCmdWithdraw() *cobra.Command { + return &cobra.Command{ + Use: "withdraw [amount]", + Short: "withdraw coins from an earn vault", + Example: fmt.Sprintf( + `%s tx %s withdraw 10000000ukava --from `, + version.AppName, types.ModuleName, + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + amount, err := sdk.ParseCoinNormalized(args[0]) + if err != nil { + return err + } + + fromAddr := clientCtx.GetFromAddress() + msg := types.NewMsgWithdraw(fromAddr.String(), amount) + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } +} diff --git a/x/earn/keeper/deposit.go b/x/earn/keeper/deposit.go new file mode 100644 index 00000000..e0bc6209 --- /dev/null +++ b/x/earn/keeper/deposit.go @@ -0,0 +1,76 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/kava-labs/kava/x/earn/types" +) + +// Deposit adds the provided amount from a depositor to a vault. The vault is +// specified by the denom in the amount. +func (k *Keeper) Deposit(ctx sdk.Context, depositor sdk.AccAddress, amount sdk.Coin) error { + // Get AllowedVault, if not found (not a valid vault), return error + allowedVault, found := k.GetAllowedVault(ctx, amount.Denom) + if !found { + return types.ErrInvalidVaultDenom + } + + if amount.IsZero() { + return types.ErrInsufficientAmount + } + + // Check if VaultRecord exists, create if not exist + vaultRecord, found := k.GetVaultRecord(ctx, amount.Denom) + if !found { + // Create a new VaultRecord with 0 supply + vaultRecord = types.NewVaultRecord(amount.Denom) + } + + // Transfer amount to module account + if err := k.bankKeeper.SendCoinsFromAccountToModule( + ctx, + depositor, + types.ModuleName, + sdk.NewCoins(amount), + ); err != nil { + return err + } + + // Get VaultShareRecord for account, create if not exist + vaultShareRecord, found := k.GetVaultShareRecord(ctx, amount.Denom, depositor) + if !found { + // Create a new empty VaultShareRecord with 0 supply + vaultShareRecord = types.NewVaultShareRecord(depositor, amount.Denom) + } + + // Increment VaultRecord supply + vaultRecord.TotalSupply = vaultRecord.TotalSupply.Add(amount) + + // Increment VaultShareRecord supply + vaultShareRecord.AmountSupplied = vaultShareRecord.AmountSupplied.Add(amount) + + // Update VaultRecord and VaultShareRecord + k.SetVaultRecord(ctx, vaultRecord) + k.SetVaultShareRecord(ctx, vaultShareRecord) + + // Get the strategy for the vault + strategy, err := k.GetStrategy(allowedVault.VaultStrategy) + if err != nil { + return err + } + + // Deposit to the strategy + if err := strategy.Deposit(amount); err != nil { + return err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeVaultDeposit, + sdk.NewAttribute(types.AttributeKeyVaultDenom, amount.Denom), + sdk.NewAttribute(types.AttributeKeyDepositor, depositor.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, amount.Amount.String()), + ), + ) + + return nil +} diff --git a/x/earn/keeper/deposit_test.go b/x/earn/keeper/deposit_test.go new file mode 100644 index 00000000..1499edde --- /dev/null +++ b/x/earn/keeper/deposit_test.go @@ -0,0 +1,132 @@ +package keeper_test + +import ( + "os" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/kava-labs/kava/app" + "github.com/kava-labs/kava/x/earn/testutil" + "github.com/kava-labs/kava/x/earn/types" + "github.com/stretchr/testify/suite" +) + +func TestMain(m *testing.M) { + config := sdk.GetConfig() + app.SetBech32AddressPrefixes(config) + + os.Exit(m.Run()) +} + +type depositTestSuite struct { + testutil.Suite +} + +func (suite *depositTestSuite) SetupTest() { + suite.Suite.SetupTest() + suite.Keeper.SetParams(suite.Ctx, types.DefaultParams()) +} + +func TestDepositTestSuite(t *testing.T) { + suite.Run(t, new(depositTestSuite)) +} + +func (suite *depositTestSuite) TestDeposit_Balances() { + vaultDenom := "busd" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 100) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + suite.Require().NoError(err) + + suite.AccountBalanceEqual( + acc.GetAddress(), + sdk.NewCoins(startBalance.Sub(depositAmount)), // Account decreases by deposit + ) + + // TODO: Module account balance will be zero when strategies are implemented + suite.ModuleAccountBalanceEqual( + sdk.NewCoins(depositAmount), + ) +} + +func (suite *depositTestSuite) TestDeposit_Exceed() { + vaultDenom := "busd" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 1001) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + suite.Require().Error(err) + suite.Require().ErrorIs(err, sdkerrors.ErrInsufficientFunds) + + // No changes in balances + + suite.AccountBalanceEqual( + acc.GetAddress(), + sdk.NewCoins(startBalance), + ) + + suite.ModuleAccountBalanceEqual( + sdk.NewCoins(), + ) +} + +func (suite *depositTestSuite) TestDeposit_Zero() { + vaultDenom := "busd" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 0) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrInsufficientAmount) + + // No changes in balances + + suite.AccountBalanceEqual( + acc.GetAddress(), + sdk.NewCoins(startBalance), + ) + + suite.ModuleAccountBalanceEqual( + sdk.NewCoins(), + ) +} + +func (suite *depositTestSuite) TestDeposit_InvalidVault() { + vaultDenom := "busd" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 1001) + + // Vault not created -- doesn't exist + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrInvalidVaultDenom) + + // No changes in balances + + suite.AccountBalanceEqual( + acc.GetAddress(), + sdk.NewCoins(startBalance), + ) + + suite.ModuleAccountBalanceEqual( + sdk.NewCoins(), + ) +} diff --git a/x/earn/keeper/grpc_query_test.go b/x/earn/keeper/grpc_query_test.go new file mode 100644 index 00000000..d0789bc8 --- /dev/null +++ b/x/earn/keeper/grpc_query_test.go @@ -0,0 +1,55 @@ +package keeper_test + +import ( + "context" + "testing" + + "github.com/cosmos/cosmos-sdk/baseapp" + + "github.com/kava-labs/kava/x/earn/keeper" + "github.com/kava-labs/kava/x/earn/testutil" + "github.com/kava-labs/kava/x/earn/types" + "github.com/stretchr/testify/suite" +) + +type grpcQueryTestSuite struct { + testutil.Suite + + queryClient types.QueryClient +} + +func (suite *grpcQueryTestSuite) SetupTest() { + suite.Suite.SetupTest() + suite.Keeper.SetParams(suite.Ctx, types.DefaultParams()) + + queryHelper := baseapp.NewQueryServerTestHelper(suite.Ctx, suite.App.InterfaceRegistry()) + types.RegisterQueryServer(queryHelper, keeper.NewQueryServerImpl(suite.Keeper)) + + suite.queryClient = types.NewQueryClient(queryHelper) +} + +func TestGrpcQueryTestSuite(t *testing.T) { + suite.Run(t, new(grpcQueryTestSuite)) +} + +func (suite *grpcQueryTestSuite) TestQueryParams() { + vaultDenom := "busd" + + res, err := suite.queryClient.Params(context.Background(), types.NewQueryParamsRequest()) + suite.Require().NoError(err) + // ElementsMatch instead of Equal because AllowedVaults{} != AllowedVaults(nil) + suite.Require().ElementsMatch(types.DefaultParams().AllowedVaults, res.Params.AllowedVaults) + + // Add vault to params + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + // Query again for added vault + res, err = suite.queryClient.Params(context.Background(), types.NewQueryParamsRequest()) + suite.Require().NoError(err) + suite.Require().Equal( + types.AllowedVaults{ + types.NewAllowedVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS), + }, + res.Params.AllowedVaults, + ) +} diff --git a/x/earn/keeper/msg_server.go b/x/earn/keeper/msg_server.go index 2e427393..ed8ffc55 100644 --- a/x/earn/keeper/msg_server.go +++ b/x/earn/keeper/msg_server.go @@ -1,6 +1,10 @@ package keeper import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/kava-labs/kava/x/earn/types" ) @@ -15,3 +19,51 @@ func NewMsgServerImpl(keeper Keeper) types.MsgServer { } var _ types.MsgServer = msgServer{} + +// Deposit handles MsgDeposit messages +func (m msgServer) Deposit(goCtx context.Context, msg *types.MsgDeposit) (*types.MsgDepositResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + depositor, err := sdk.AccAddressFromBech32(msg.Depositor) + if err != nil { + return nil, err + } + + if err := m.keeper.Deposit(ctx, depositor, msg.Amount); 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.MsgDepositResponse{}, nil +} + +// Withdraw handles MsgWithdraw messages +func (m msgServer) Withdraw(goCtx context.Context, msg *types.MsgWithdraw) (*types.MsgWithdrawResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + from, err := sdk.AccAddressFromBech32(msg.From) + if err != nil { + return nil, err + } + + if err := m.keeper.Withdraw(ctx, from, msg.Amount); err != nil { + return nil, err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, from.String()), + ), + ) + + return &types.MsgWithdrawResponse{}, nil +} diff --git a/x/earn/keeper/msg_server_test.go b/x/earn/keeper/msg_server_test.go new file mode 100644 index 00000000..57e62bd2 --- /dev/null +++ b/x/earn/keeper/msg_server_test.go @@ -0,0 +1,136 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + "github.com/kava-labs/kava/x/earn/keeper" + "github.com/kava-labs/kava/x/earn/testutil" + "github.com/kava-labs/kava/x/earn/types" + "github.com/stretchr/testify/suite" + "github.com/tendermint/tendermint/crypto" +) + +var moduleAccAddress = sdk.AccAddress(crypto.AddressHash([]byte(types.ModuleAccountName))) + +type msgServerTestSuite struct { + testutil.Suite + + msgServer types.MsgServer +} + +func (suite *msgServerTestSuite) SetupTest() { + suite.Suite.SetupTest() + suite.Keeper.SetParams(suite.Ctx, types.DefaultParams()) + + suite.msgServer = keeper.NewMsgServerImpl(suite.Keeper) +} + +func TestMsgServerTestSuite(t *testing.T) { + suite.Run(t, new(msgServerTestSuite)) +} + +func (suite *msgServerTestSuite) TestDeposit() { + vaultDenom := "usdx" + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 100) + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + msg := types.NewMsgDeposit(acc.GetAddress().String(), depositAmount) + _, err := suite.msgServer.Deposit(sdk.WrapSDKContext(suite.Ctx), msg) + suite.Require().NoError(err) + + suite.AccountBalanceEqual( + acc.GetAddress(), + sdk.NewCoins(startBalance.Sub(depositAmount)), + ) + + // Bank: Send deposit Account -> Module account + suite.EventsContains( + suite.GetEvents(), + sdk.NewEvent( + banktypes.EventTypeTransfer, + sdk.NewAttribute(banktypes.AttributeKeyRecipient, moduleAccAddress.String()), + sdk.NewAttribute(banktypes.AttributeKeySender, acc.GetAddress().String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, depositAmount.String()), + ), + ) + + // Keeper Deposit() + suite.EventsContains( + suite.GetEvents(), + sdk.NewEvent( + types.EventTypeVaultDeposit, + sdk.NewAttribute(types.AttributeKeyVaultDenom, depositAmount.Denom), + sdk.NewAttribute(types.AttributeKeyDepositor, acc.GetAddress().String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, depositAmount.Amount.String()), + ), + ) + + // Msg server module + suite.EventsContains( + suite.GetEvents(), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, acc.GetAddress().String()), + ), + ) +} + +func (suite *msgServerTestSuite) TestWithdraw() { + vaultDenom := "usdx" + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 100) + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + msgDeposit := types.NewMsgDeposit(acc.GetAddress().String(), depositAmount) + _, err := suite.msgServer.Deposit(sdk.WrapSDKContext(suite.Ctx), msgDeposit) + suite.Require().NoError(err) + + // Withdraw all + msgWithdraw := types.NewMsgWithdraw(acc.GetAddress().String(), depositAmount) + _, err = suite.msgServer.Withdraw(sdk.WrapSDKContext(suite.Ctx), msgWithdraw) + suite.Require().NoError(err) + + // Bank: Send deposit Account -> Module account + suite.EventsContains( + suite.GetEvents(), + sdk.NewEvent( + banktypes.EventTypeTransfer, + // Direction opposite from Deposit() + sdk.NewAttribute(banktypes.AttributeKeyRecipient, acc.GetAddress().String()), + sdk.NewAttribute(banktypes.AttributeKeySender, moduleAccAddress.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, depositAmount.String()), + ), + ) + + // Keeper Withdraw() + suite.EventsContains( + suite.GetEvents(), + sdk.NewEvent( + types.EventTypeVaultWithdraw, + sdk.NewAttribute(types.AttributeKeyVaultDenom, depositAmount.Denom), + sdk.NewAttribute(types.AttributeKeyOwner, acc.GetAddress().String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, depositAmount.Amount.String()), + ), + ) + + // Msg server module + suite.EventsContains( + suite.GetEvents(), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, acc.GetAddress().String()), + ), + ) +} diff --git a/x/earn/keeper/params.go b/x/earn/keeper/params.go index 63463b49..641b40c1 100644 --- a/x/earn/keeper/params.go +++ b/x/earn/keeper/params.go @@ -10,6 +10,7 @@ import ( func (k Keeper) GetParams(ctx sdk.Context) types.Params { var p types.Params k.paramSubspace.GetParamSet(ctx, &p) + return p } @@ -17,3 +18,20 @@ func (k Keeper) GetParams(ctx sdk.Context) types.Params { func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { k.paramSubspace.SetParamSet(ctx, ¶ms) } + +// GetAllowedVaults returns the list of allowed vaults from the module params. +func (k Keeper) GetAllowedVaults(ctx sdk.Context) types.AllowedVaults { + return k.GetParams(ctx).AllowedVaults +} + +// GetAllowedVault returns a single vault from the module params specified by +// the denom. +func (k Keeper) GetAllowedVault(ctx sdk.Context, vaultDenom string) (types.AllowedVault, bool) { + for _, allowedVault := range k.GetAllowedVaults(ctx) { + if allowedVault.Denom == vaultDenom { + return allowedVault, true + } + } + + return types.AllowedVault{}, false +} diff --git a/x/earn/keeper/strategy.go b/x/earn/keeper/strategy.go new file mode 100644 index 00000000..de8c0365 --- /dev/null +++ b/x/earn/keeper/strategy.go @@ -0,0 +1,55 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/kava-labs/kava/x/earn/types" +) + +// Strategy is the interface that must be implemented by a strategy. +type Strategy interface { + // GetName returns the name of the strategy. + GetName() string + + // GetDescription returns the description of the strategy. + GetDescription() string + + // GetSupportedDenoms returns a slice of supported denom for this strategy. + // For example, stablecoin stakers strategy supports both "busd" and "usdc". + GetSupportedDenoms() []string + + // GetEstimatedTotalAssets returns the estimated total assets denominated in + // GetDenom() of this strategy. This is the value if the strategy were to + // liquidate all assets. + // + // **Note:** This may not reflect the true value as it may become outdated + // from market changes. + GetEstimatedTotalAssets(denom string) (sdk.Coin, error) + + // Deposit the specified amount of coins into this strategy. The amount + // must be denominated in GetDenom(). + Deposit(amount sdk.Coin) error + + // Withdraw the specified amount of coins from this strategy. The amount + // must be denominated in GetDenom(). + Withdraw(amount sdk.Coin) error + + // LiquidateAll liquidates all of the entire strategy's positions, returning + // the amount of liquidated denominated in GetDenom(). This should be only + // called during use of emergency via governance. + LiquidateAll() (amount sdk.Coin, err error) +} + +func (k *Keeper) GetStrategy(strategyType types.StrategyType) (Strategy, error) { + switch strategyType { + case types.STRATEGY_TYPE_STABLECOIN_STAKERS: + return (*StableCoinStrategy)(k), nil + case types.STRATEGY_TYPE_KAVA_STAKERS: + panic("unimplemented") + case types.STRATEGY_TYPE_KAVA_FOUNDATION: + panic("unimplemented") + default: + return nil, fmt.Errorf("unknown strategy type: %s", strategyType) + } +} diff --git a/x/earn/keeper/strategy_stablecoin.go b/x/earn/keeper/strategy_stablecoin.go new file mode 100644 index 00000000..f1c3ea7c --- /dev/null +++ b/x/earn/keeper/strategy_stablecoin.go @@ -0,0 +1,42 @@ +package keeper + +import sdk "github.com/cosmos/cosmos-sdk/types" + +// StableCoinStrategy defines the stablecoin strategy: +// 1. Supply USDX to Lend +type StableCoinStrategy Keeper + +var _ Strategy = (*StableCoinStrategy)(nil) + +func (s *StableCoinStrategy) GetName() string { + return "USDX" +} + +func (s *StableCoinStrategy) GetDescription() string { + return "Supplies the USDX to Lend" +} + +func (s *StableCoinStrategy) GetSupportedDenoms() []string { + return []string{"usdx"} +} + +func (s *StableCoinStrategy) GetEstimatedTotalAssets(denom string) (sdk.Coin, error) { + // 1. Get amount of USDX in Lend + + return sdk.Coin{}, nil +} + +func (s *StableCoinStrategy) Deposit(amount sdk.Coin) error { + return nil +} + +func (s *StableCoinStrategy) Withdraw(amount sdk.Coin) error { + return nil +} + +// LiquidateAll liquidates all assets in the strategy, this should be called +// only in case of emergency or when all assets should be moved to a new +// strategy. +func (s *StableCoinStrategy) LiquidateAll() (amount sdk.Coin, err error) { + return sdk.Coin{}, nil +} diff --git a/x/earn/keeper/vault.go b/x/earn/keeper/vault.go new file mode 100644 index 00000000..fb4f1504 --- /dev/null +++ b/x/earn/keeper/vault.go @@ -0,0 +1,215 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/kava-labs/kava/x/earn/types" +) + +// ViewVaultKeeper defines the read-only methods used for querying vaults. +type ViewVaultKeeper interface { + // GetVaultTotalSupplied returns the total balance supplied to a vault. This + // may not necessarily be the current value of the vault, as it is the sum + // of the supplied denom. + GetVaultTotalSupplied(ctx sdk.Context, denom string) (sdk.Coin, error) + + // GetVaultTotalValue returns the total **value** of all coins in a vault, + // i.e. the realizable total value denominated by GetDenom() if the vault + // were to liquidate its entire strategies. + GetVaultTotalValue(ctx sdk.Context, denom string) (sdk.Coin, error) + + // GetVaultAccountSupplied returns the supplied amount for a single address + // within the vault. + GetVaultAccountSupplied(ctx sdk.Context, denom string, acc sdk.AccAddress) (sdk.Coin, error) + + // GetVaultAccountValue returns the value of a single address within a vault + // if the account were to withdraw their entire balance. + GetVaultAccountValue(ctx sdk.Context, denom string, acc sdk.AccAddress) (sdk.Coin, error) +} + +var _ ViewVaultKeeper = (*Keeper)(nil) + +// GetVaultTotalSupplied returns the total balance supplied to the vault. This +// may not necessarily be the current value of the vault, as it is the sum +// of the supplied denom and the value may be higher due to accumulated APYs. +func (k *Keeper) GetVaultTotalSupplied( + ctx sdk.Context, + denom string, +) (sdk.Coin, error) { + vault, found := k.GetVaultRecord(ctx, denom) + if !found { + return sdk.Coin{}, types.ErrVaultRecordNotFound + } + + return vault.TotalSupply, nil +} + +// GetTotalValue returns the total **value** of all coins in this vault, +// i.e. the realizable total value denominated by GetDenom() if the vault +// were to liquidate its entire strategies. +func (k *Keeper) GetVaultTotalValue( + ctx sdk.Context, + denom string, +) (sdk.Coin, error) { + enabledVault, found := k.GetAllowedVault(ctx, denom) + if !found { + return sdk.Coin{}, types.ErrVaultRecordNotFound + } + + strategy, err := k.GetStrategy(enabledVault.VaultStrategy) + if err != nil { + return sdk.Coin{}, types.ErrInvalidVaultStrategy + } + + return strategy.GetEstimatedTotalAssets(enabledVault.Denom) +} + +// GetVaultAccountSupplied returns the supplied amount for a single address +// within a vault. +func (k *Keeper) GetVaultAccountSupplied( + ctx sdk.Context, + denom string, + acc sdk.AccAddress, +) (sdk.Coin, error) { + vaultShareRecord, found := k.GetVaultShareRecord(ctx, denom, acc) + if !found { + return sdk.Coin{}, types.ErrVaultShareRecordNotFound + } + + return vaultShareRecord.AmountSupplied, nil +} + +// GetVaultAccountValue returns the value of a single address within a vault +// if the account were to withdraw their entire balance. +func (k *Keeper) GetVaultAccountValue( + ctx sdk.Context, + denom string, + acc sdk.AccAddress, +) (sdk.Coin, error) { + totalSupplied, err := k.GetVaultTotalSupplied(ctx, denom) + if err != nil { + return sdk.Coin{}, err + } + + accSupplied, err := k.GetVaultAccountSupplied(ctx, denom, acc) + if err != nil { + return sdk.Coin{}, err + } + + vaultTotalValue, err := k.GetVaultTotalValue(ctx, denom) + if err != nil { + return sdk.Coin{}, err + } + + // percent of vault account ownership = accountSupply / totalSupply + // value of vault account ownership = percentOwned * totalValue + vaultShare := accSupplied.Amount.Quo(totalSupplied.Amount) + shareValue := vaultTotalValue.Amount.Mul(vaultShare) + + return sdk.NewCoin(denom, shareValue), nil +} + +// ---------------------------------------------------------------------------- +// VaultRecord -- vault total supplies + +// GetVaultRecord returns the vault record for a given denom. +func (k *Keeper) GetVaultRecord( + ctx sdk.Context, + vaultDenom string, +) (types.VaultRecord, bool) { + store := prefix.NewStore(ctx.KVStore(k.key), types.VaultRecordKeyPrefix) + + bz := store.Get(types.VaultKey(vaultDenom)) + if bz == nil { + return types.VaultRecord{}, false + } + + var record types.VaultRecord + k.cdc.MustUnmarshal(bz, &record) + + return record, true +} + +// UpdateVaultRecord updates the vault record in state for a given denom. This +// deletes it if the supply is zero and updates the state if supply is non-zero. +func (k *Keeper) UpdateVaultRecord( + ctx sdk.Context, + vaultRecord types.VaultRecord, +) { + if vaultRecord.TotalSupply.IsZero() { + k.DeleteVaultRecord(ctx, vaultRecord.Denom) + } else { + k.SetVaultRecord(ctx, vaultRecord) + } +} + +// DeleteVaultRecord deletes the vault record for a given denom. +func (k *Keeper) DeleteVaultRecord(ctx sdk.Context, vaultDenom string) { + store := prefix.NewStore(ctx.KVStore(k.key), types.VaultRecordKeyPrefix) + store.Delete(types.VaultKey(vaultDenom)) +} + +// SetVaultRecord sets the vault record for a given denom. +func (k *Keeper) SetVaultRecord(ctx sdk.Context, record types.VaultRecord) { + store := prefix.NewStore(ctx.KVStore(k.key), types.VaultRecordKeyPrefix) + bz := k.cdc.MustMarshal(&record) + store.Set(types.VaultKey(record.Denom), bz) +} + +// ---------------------------------------------------------------------------- +// VaultShare -- user shares per vault + +// GetVaultShareRecord returns the vault share record for a given denom and +// account. +func (k *Keeper) GetVaultShareRecord( + ctx sdk.Context, + vaultDenom string, + acc sdk.AccAddress, +) (types.VaultShareRecord, bool) { + store := prefix.NewStore(ctx.KVStore(k.key), types.VaultRecordKeyPrefix) + + bz := store.Get(types.DepositorVaultSharesKey(acc, vaultDenom)) + if bz == nil { + return types.VaultShareRecord{}, false + } + + var record types.VaultShareRecord + k.cdc.MustUnmarshal(bz, &record) + + return record, true +} + +// UpdateVaultShareRecord updates the vault share record in state for a given +// denom and account. This deletes it if the supply is zero and updates the +// state if supply is non-zero. +func (k *Keeper) UpdateVaultShareRecord( + ctx sdk.Context, + record types.VaultShareRecord, +) { + if record.AmountSupplied.IsZero() { + k.DeleteVaultShareRecord(ctx, record.AmountSupplied.Denom, record.Depositor) + } else { + k.SetVaultShareRecord(ctx, record) + } +} + +// DeleteVaultShareRecord deletes the vault share record for a given denom and +// account. +func (k *Keeper) DeleteVaultShareRecord( + ctx sdk.Context, + vaultDenom string, + acc sdk.AccAddress, +) { + store := prefix.NewStore(ctx.KVStore(k.key), types.VaultRecordKeyPrefix) + store.Delete(types.DepositorVaultSharesKey(acc, vaultDenom)) +} + +// SetVaultShareRecord sets the vault share record for a given denom and account. +func (k *Keeper) SetVaultShareRecord( + ctx sdk.Context, + record types.VaultShareRecord, +) { + store := prefix.NewStore(ctx.KVStore(k.key), types.VaultRecordKeyPrefix) + bz := k.cdc.MustMarshal(&record) + store.Set(types.DepositorVaultSharesKey(record.Depositor, record.AmountSupplied.Denom), bz) +} diff --git a/x/earn/keeper/vault_test.go b/x/earn/keeper/vault_test.go new file mode 100644 index 00000000..31687c6f --- /dev/null +++ b/x/earn/keeper/vault_test.go @@ -0,0 +1,245 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/kava-labs/kava/x/earn/testutil" + "github.com/kava-labs/kava/x/earn/types" + "github.com/stretchr/testify/suite" +) + +type vaultTestSuite struct { + testutil.Suite +} + +func (suite *vaultTestSuite) SetupTest() { + suite.Suite.SetupTest() + suite.Keeper.SetParams(suite.Ctx, types.DefaultParams()) +} + +func TestVaultTestSuite(t *testing.T) { + suite.Run(t, new(vaultTestSuite)) +} + +func (suite *vaultTestSuite) TestGetVaultTotalSupplied() { + vaultDenom := "usdx" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 100) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + suite.Require().NoError(err) + + vaultTotalSupplied, err := suite.Keeper.GetVaultTotalSupplied(suite.Ctx, vaultDenom) + suite.Require().NoError(err) + + suite.Equal(depositAmount, vaultTotalSupplied) +} + +func (suite *vaultTestSuite) TestGetVaultTotalSupplied_NotFound() { + vaultDenom := "usdx" + + _, err := suite.Keeper.GetVaultTotalSupplied(suite.Ctx, vaultDenom) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrVaultRecordNotFound) +} + +func (suite *vaultTestSuite) TestGetVaultTotalValue() { + // TODO: After strategy implemented GetEstimatedTotalAssets +} + +func (suite *vaultTestSuite) TestGetVaultTotalValue_NotFound() { + vaultDenom := "usdx" + + _, err := suite.Keeper.GetVaultTotalValue(suite.Ctx, vaultDenom) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrVaultRecordNotFound) +} + +func (suite *vaultTestSuite) TestGetVaultTotalValue_InvalidStrategy() { + vaultDenom := "usdx" + suite.CreateVault(vaultDenom, 99999) // not valid strategy type + + _, err := suite.Keeper.GetVaultTotalValue(suite.Ctx, vaultDenom) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrInvalidVaultStrategy) +} + +func (suite *vaultTestSuite) TestGetVaultAccountSupplied() { + vaultDenom := "usdx" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + deposit1Amount := sdk.NewInt64Coin(vaultDenom, 100) + deposit2Amount := sdk.NewInt64Coin(vaultDenom, 100) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1) + + // Before deposit, account supplied is 0 + + _, err := suite.Keeper.GetVaultAccountSupplied(suite.Ctx, vaultDenom, acc1.GetAddress()) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrVaultShareRecordNotFound) + + _, err = suite.Keeper.GetVaultAccountSupplied(suite.Ctx, vaultDenom, acc2.GetAddress()) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrVaultShareRecordNotFound) + + // Deposits from both accounts + + err = suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), deposit1Amount) + suite.Require().NoError(err) + + err = suite.Keeper.Deposit(suite.Ctx, acc2.GetAddress(), deposit2Amount) + suite.Require().NoError(err) + + // Check balances + + vaultAcc1Supplied, err := suite.Keeper.GetVaultAccountSupplied(suite.Ctx, vaultDenom, acc1.GetAddress()) + suite.Require().NoError(err) + + vaultAcc2Supplied, err := suite.Keeper.GetVaultAccountSupplied(suite.Ctx, vaultDenom, acc2.GetAddress()) + suite.Require().NoError(err) + + // Account supply only includes the deposit from respective accounts + suite.Equal(deposit1Amount, vaultAcc1Supplied) + suite.Equal(deposit1Amount, vaultAcc2Supplied) +} + +func (suite *vaultTestSuite) TestGetVaultAccountValue() { + vaultDenom := "usdx" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 100) + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + suite.Require().NoError(err) + + suite.T().Skip("TODO: After strategy GetEstimatedTotalAssets implemented") + + _, err = suite.Keeper.GetVaultAccountValue(suite.Ctx, vaultDenom, acc.GetAddress()) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrVaultShareRecordNotFound) +} + +func (suite *vaultTestSuite) TestGetVaultAccountValue_VaultNotFound() { + vaultDenom := "usdx" + acc := suite.CreateAccount(sdk.NewCoins(), 0) + + _, err := suite.Keeper.GetVaultAccountValue(suite.Ctx, vaultDenom, acc.GetAddress()) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrVaultRecordNotFound) +} + +func (suite *vaultTestSuite) TestGetVaultAccountValue_ShareNotFound() { + vaultDenom := "usdx" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 100) + + acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + // Deposit from acc1 so that vault record exists + err := suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), depositAmount) + suite.Require().NoError(err) + + // Query from acc2 with no share record + _, err = suite.Keeper.GetVaultAccountValue(suite.Ctx, vaultDenom, acc2.GetAddress()) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrVaultShareRecordNotFound) +} + +// ---------------------------------------------------------------------------- +// State methods + +func (suite *vaultTestSuite) TestGetVaultRecord() { + record := types.NewVaultRecord("usdx") + + _, found := suite.Keeper.GetVaultRecord(suite.Ctx, record.Denom) + suite.Require().False(found) + + suite.Keeper.SetVaultRecord(suite.Ctx, record) + + stateRecord, found := suite.Keeper.GetVaultRecord(suite.Ctx, record.Denom) + suite.Require().True(found) + suite.Require().Equal(record, stateRecord) +} + +func (suite *vaultTestSuite) TestUpdateVaultRecord() { + record := types.NewVaultRecord("usdx") + + record.TotalSupply = sdk.NewInt64Coin("usdx", 100) + + // Update vault + suite.Keeper.UpdateVaultRecord(suite.Ctx, record) + + stateRecord, found := suite.Keeper.GetVaultRecord(suite.Ctx, record.Denom) + suite.Require().True(found, "vault record with supply should exist") + suite.Require().Equal(record, stateRecord) + + // Remove supply + record.TotalSupply = sdk.NewInt64Coin("usdx", 0) + suite.Keeper.UpdateVaultRecord(suite.Ctx, record) + + _, found = suite.Keeper.GetVaultRecord(suite.Ctx, record.Denom) + suite.Require().False(found, "vault record with 0 supply should be deleted") +} + +func (suite *vaultTestSuite) TestGetVaultShareRecord() { + vaultDenom := "usdx" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 100) + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + record := types.NewVaultShareRecord(acc.GetAddress(), vaultDenom) + + // Check share doesn't exist before deposit + + _, found := suite.Keeper.GetVaultShareRecord(suite.Ctx, vaultDenom, acc.GetAddress()) + suite.Require().False(found, "vault share record should not exist before deposit") + + // Update share record + record.AmountSupplied = depositAmount + suite.Keeper.SetVaultShareRecord(suite.Ctx, record) + + // Check share exists and matches set value + stateRecord, found := suite.Keeper.GetVaultShareRecord(suite.Ctx, vaultDenom, acc.GetAddress()) + suite.Require().True(found) + suite.Require().Equal(record, stateRecord) +} + +func (suite *vaultTestSuite) TestUpdateVaultShareRecord() { + vaultDenom := "usdx" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 100) + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + record := types.NewVaultShareRecord(acc.GetAddress(), vaultDenom) + + record.AmountSupplied = depositAmount + + // Update vault + suite.Keeper.UpdateVaultShareRecord(suite.Ctx, record) + + stateRecord, found := suite.Keeper.GetVaultShareRecord(suite.Ctx, vaultDenom, acc.GetAddress()) + suite.Require().True(found, "vault share record with supply should exist") + suite.Require().Equal(record, stateRecord) + + // Remove supply + record.AmountSupplied = sdk.NewInt64Coin("usdx", 0) + suite.Keeper.UpdateVaultShareRecord(suite.Ctx, record) + + _, found = suite.Keeper.GetVaultShareRecord(suite.Ctx, vaultDenom, acc.GetAddress()) + suite.Require().False(found, "vault share record with 0 supply should be deleted") +} diff --git a/x/earn/keeper/withdraw.go b/x/earn/keeper/withdraw.go new file mode 100644 index 00000000..02f8ed88 --- /dev/null +++ b/x/earn/keeper/withdraw.go @@ -0,0 +1,84 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/kava-labs/kava/x/earn/types" +) + +// Withdraw removes the amount of supplied tokens from a vault and transfers it +// back to the account. +func (k *Keeper) Withdraw(ctx sdk.Context, from sdk.AccAddress, amount sdk.Coin) error { + // Get AllowedVault, if not found (not a valid vault), return error + allowedVault, found := k.GetAllowedVault(ctx, amount.Denom) + if !found { + return types.ErrInvalidVaultDenom + } + + if amount.IsZero() { + return types.ErrInsufficientAmount + } + + // Check if VaultRecord exists, return error if not exist as it's empty + vaultRecord, found := k.GetVaultRecord(ctx, amount.Denom) + if !found { + return types.ErrVaultRecordNotFound + } + + // Get VaultShareRecord for account, create if not exist + vaultShareRecord, found := k.GetVaultShareRecord(ctx, amount.Denom, from) + if !found { + return types.ErrVaultShareRecordNotFound + } + + // Check if VaultShareRecord has enough supplied to withdraw + if vaultShareRecord.AmountSupplied.Amount.LT(amount.Amount) { + return sdkerrors.Wrapf( + types.ErrInvalidShares, + "withdraw of %s shares greater than %s shares supplied", + amount, + vaultShareRecord.AmountSupplied, + ) + } + + // Send coins back to account + if err := k.bankKeeper.SendCoinsFromModuleToAccount( + ctx, + types.ModuleName, + from, + sdk.NewCoins(amount), + ); err != nil { + return err + } + + // Decrement VaultRecord and VaultShareRecord supplies + vaultRecord.TotalSupply = vaultRecord.TotalSupply.Sub(amount) + vaultShareRecord.AmountSupplied = vaultShareRecord.AmountSupplied.Sub(amount) + + // Update VaultRecord and VaultShareRecord, deletes if zero supply + k.UpdateVaultRecord(ctx, vaultRecord) + k.UpdateVaultShareRecord(ctx, vaultShareRecord) + + // Get the strategy for the vault + strategy, err := k.GetStrategy(allowedVault.VaultStrategy) + if err != nil { + return err + } + + // Deposit to the strategy + if err := strategy.Withdraw(amount); err != nil { + return err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeVaultWithdraw, + sdk.NewAttribute(types.AttributeKeyVaultDenom, amount.Denom), + sdk.NewAttribute(types.AttributeKeyOwner, from.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, amount.Amount.String()), + ), + ) + + return nil +} diff --git a/x/earn/keeper/withdraw_test.go b/x/earn/keeper/withdraw_test.go new file mode 100644 index 00000000..a2955b4f --- /dev/null +++ b/x/earn/keeper/withdraw_test.go @@ -0,0 +1,227 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/kava-labs/kava/x/earn/testutil" + "github.com/kava-labs/kava/x/earn/types" + "github.com/stretchr/testify/suite" +) + +type withdrawTestSuite struct { + testutil.Suite +} + +func (suite *withdrawTestSuite) SetupTest() { + suite.Suite.SetupTest() + suite.Keeper.SetParams(suite.Ctx, types.DefaultParams()) +} + +func TestWithdrawTestSuite(t *testing.T) { + suite.Run(t, new(withdrawTestSuite)) +} + +func (suite *withdrawTestSuite) TestWithdraw_NoVaultRecord() { + vaultDenom := "busd" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + withdrawAmount := sdk.NewInt64Coin(vaultDenom, 100) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + // Withdraw without having any prior deposits + err := suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrVaultRecordNotFound) + + // No balance changes + suite.AccountBalanceEqual( + acc.GetAddress(), + sdk.NewCoins(startBalance), + ) + + suite.ModuleAccountBalanceEqual( + sdk.NewCoins(), + ) +} + +func (suite *withdrawTestSuite) TestWithdraw_NoVaultShareRecord() { + vaultDenom := "busd" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + + acc1DepositAmount := sdk.NewCoin(vaultDenom, sdk.NewInt(100)) + acc2WithdrawAmount := sdk.NewInt64Coin(vaultDenom, 100) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + // Create deposit from acc1 so the VaultRecord exists in state + acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + err := suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), acc1DepositAmount) + suite.Require().NoError(err) + + acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1) + + // Withdraw from acc2 without having any prior deposits + err = suite.Keeper.Withdraw(suite.Ctx, acc2.GetAddress(), acc2WithdrawAmount) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrVaultShareRecordNotFound) + + // No balance changes in acc2 + suite.AccountBalanceEqual( + acc2.GetAddress(), + sdk.NewCoins(startBalance), + ) + + suite.ModuleAccountBalanceEqual( + sdk.NewCoins(acc1DepositAmount), + ) +} + +func (suite *withdrawTestSuite) TestWithdraw_ExceedBalance() { + vaultDenom := "busd" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 100) + withdrawAmount := sdk.NewInt64Coin(vaultDenom, 200) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + suite.Require().NoError(err) + + err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrInvalidShares) + + // Balances still the same after deposit + suite.AccountBalanceEqual( + acc.GetAddress(), + sdk.NewCoins(startBalance.Sub(depositAmount)), + ) + + suite.ModuleAccountBalanceEqual( + sdk.NewCoins(depositAmount), + ) +} + +func (suite *withdrawTestSuite) TestWithdraw_Zero() { + vaultDenom := "busd" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + withdrawAmount := sdk.NewInt64Coin(vaultDenom, 0) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + err := suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrInsufficientAmount) + + // No changes in balances + + suite.AccountBalanceEqual( + acc.GetAddress(), + sdk.NewCoins(startBalance), + ) + + suite.ModuleAccountBalanceEqual( + sdk.NewCoins(), + ) +} + +func (suite *withdrawTestSuite) TestWithdraw_InvalidVault() { + vaultDenom := "busd" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + withdrawAmount := sdk.NewInt64Coin(vaultDenom, 1001) + + // Vault not created -- doesn't exist + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + err := suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrInvalidVaultDenom) + + // No changes in balances + + suite.AccountBalanceEqual( + acc.GetAddress(), + sdk.NewCoins(startBalance), + ) + + suite.ModuleAccountBalanceEqual( + sdk.NewCoins(), + ) +} + +func (suite *withdrawTestSuite) TestWithdraw_FullBalance() { + vaultDenom := "busd" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 100) + withdrawAmount := sdk.NewInt64Coin(vaultDenom, 100) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + suite.Require().NoError(err) + + err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount) + suite.Require().NoError(err) + + // No net changes in balances + suite.AccountBalanceEqual( + acc.GetAddress(), + sdk.NewCoins(startBalance), + ) + + suite.ModuleAccountBalanceEqual( + sdk.NewCoins(), + ) +} + +func (suite *withdrawTestSuite) TestWithdraw_Partial() { + vaultDenom := "busd" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 100) + partialWithdrawAmount := sdk.NewInt64Coin(vaultDenom, 50) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_STABLECOIN_STAKERS) + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + suite.Require().NoError(err) + + err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), partialWithdrawAmount) + suite.Require().NoError(err) + + suite.AccountBalanceEqual( + acc.GetAddress(), + sdk.NewCoins(startBalance.Sub(depositAmount).Add(partialWithdrawAmount)), + ) + + // Second withdraw for remaining 50 + err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), partialWithdrawAmount) + suite.Require().NoError(err) + + // No more balance to withdraw + err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), partialWithdrawAmount) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrVaultRecordNotFound, "vault record should be deleted after no more supplied") + + // No net changes in balances + suite.AccountBalanceEqual( + acc.GetAddress(), + sdk.NewCoins(startBalance), + ) + + suite.ModuleAccountBalanceEqual( + sdk.NewCoins(), + ) +} diff --git a/x/earn/module.go b/x/earn/module.go index 7b8e03ff..32297c69 100644 --- a/x/earn/module.go +++ b/x/earn/module.go @@ -17,6 +17,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" + "github.com/kava-labs/kava/x/earn/client/cli" "github.com/kava-labs/kava/x/earn/keeper" "github.com/kava-labs/kava/x/earn/types" ) @@ -75,12 +76,12 @@ func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux // GetTxCmd returns the root tx command for the module. func (AppModuleBasic) GetTxCmd() *cobra.Command { - return nil // TODO: cli.GetTxCmd() + return cli.GetTxCmd() } // GetQueryCmd returns no root query command for the module. func (AppModuleBasic) GetQueryCmd() *cobra.Command { - return nil // TODO: cli.GetQueryCmd() + return cli.GetQueryCmd() } //____________________________________________________________________________ diff --git a/x/earn/testutil/suite.go b/x/earn/testutil/suite.go new file mode 100644 index 00000000..f98e04c4 --- /dev/null +++ b/x/earn/testutil/suite.go @@ -0,0 +1,145 @@ +package testutil + +import ( + "fmt" + "reflect" + + "github.com/kava-labs/kava/app" + "github.com/kava-labs/kava/x/earn/keeper" + "github.com/kava-labs/kava/x/earn/types" + + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + BankKeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/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" +) + +// Suite implements a test suite for the swap module integration tests +type Suite struct { + suite.Suite + Keeper keeper.Keeper + App app.TestApp + Ctx sdk.Context + BankKeeper BankKeeper.Keeper + AccountKeeper authkeeper.AccountKeeper +} + +// SetupTest instantiates a new app, keepers, and sets suite state +func (suite *Suite) SetupTest() { + tApp := app.NewTestApp() + ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: tmtime.Now()}) + + suite.Ctx = ctx + suite.App = tApp + suite.Keeper = tApp.GetEarnKeeper() + suite.BankKeeper = tApp.GetBankKeeper() + suite.AccountKeeper = tApp.GetAccountKeeper() +} + +// GetEvents returns emitted events on the sdk context +func (suite *Suite) GetEvents() sdk.Events { + return suite.Ctx.EventManager().Events() +} + +// AddCoinsToModule adds coins to the swap module account +func (suite *Suite) AddCoinsToModule(amount sdk.Coins) { + // Does not use suite.BankKeeper.MintCoins as module account would not have permission to mint + err := simapp.FundModuleAccount(suite.BankKeeper, suite.Ctx, types.ModuleName, amount) + suite.Require().NoError(err) +} + +// RemoveCoinsFromModule removes coins to the swap module account +func (suite *Suite) RemoveCoinsFromModule(amount sdk.Coins) { + // Swap module does not have BurnCoins permission so we need to transfer to gov first to burn + err := suite.BankKeeper.SendCoinsFromModuleToModule(suite.Ctx, types.ModuleAccountName, govtypes.ModuleName, amount) + suite.Require().NoError(err) + err = suite.BankKeeper.BurnCoins(suite.Ctx, govtypes.ModuleName, amount) + suite.Require().NoError(err) +} + +// CreateAccount creates a new account from the provided balance, using index +// to create different new addresses. +func (suite *Suite) CreateAccount(initialBalance sdk.Coins, index int) authtypes.AccountI { + _, addrs := app.GeneratePrivKeyAddressPairs(index + 1) + ak := suite.App.GetAccountKeeper() + + acc := ak.NewAccountWithAddress(suite.Ctx, addrs[index]) + ak.SetAccount(suite.Ctx, acc) + + err := simapp.FundAccount(suite.BankKeeper, suite.Ctx, acc.GetAddress(), initialBalance) + suite.Require().NoError(err) + + return acc +} + +// NewAccountFromAddr creates a new account from the provided address with the provided balance +func (suite *Suite) NewAccountFromAddr(addr sdk.AccAddress, balance 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(), balance) + suite.Require().NoError(err) + + return acc +} + +// CreateVault adds a new vault to the keeper parameters +func (suite *Suite) CreateVault(vaultDenom string, vaultStrategy types.StrategyType) { + vault := types.NewAllowedVault(vaultDenom, vaultStrategy) + suite.Require().NoError(vault.Validate()) + + // allowedVaults := suite.Keeper.GetAllowedVaults(suite.Ctx) + // allowedVaults = append(allowedVaults, vault) + + suite.Keeper.SetParams( + suite.Ctx, + types.NewParams(types.AllowedVaults{vault}), + ) +} + +// AccountBalanceEqual asserts that the coins match the account balance +func (suite *Suite) AccountBalanceEqual(addr sdk.AccAddress, coins sdk.Coins) { + balance := suite.BankKeeper.GetAllBalances(suite.Ctx, addr) + suite.Equal(coins, balance, fmt.Sprintf("expected account balance to equal coins %s, but got %s", coins, balance)) +} + +// ModuleAccountBalanceEqual asserts that the swap module account balance matches the provided coins +func (suite *Suite) ModuleAccountBalanceEqual(coins sdk.Coins) { + balance := suite.BankKeeper.GetAllBalances( + suite.Ctx, + suite.AccountKeeper.GetModuleAddress(types.ModuleAccountName), + ) + suite.Equal(coins, balance, fmt.Sprintf("expected module account balance to equal coins %s, but got %s", coins, balance)) +} + +// 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 { // new cosmos changed the event attribute type + out := []sdk.Attribute{} + + for _, attr := range attrs { + out = append(out, sdk.NewAttribute(string(attr.Key), string(attr.Value))) + } + + return out +} diff --git a/x/earn/types/codec.go b/x/earn/types/codec.go index d353668d..38e6eeb3 100644 --- a/x/earn/types/codec.go +++ b/x/earn/types/codec.go @@ -3,6 +3,7 @@ package types import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -11,14 +12,19 @@ import ( // RegisterLegacyAminoCodec registers all the necessary types and interfaces for the // earn module. func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgDeposit{}, "earn/MsgDeposit", nil) + cdc.RegisterConcrete(&MsgWithdraw{}, "earn/MsgWithdraw", nil) } // RegisterInterfaces registers proto messages under their interfaces for unmarshalling, // in addition to registerting the msg service for handling tx msgs func RegisterInterfaces(registry types.InterfaceRegistry) { - registry.RegisterImplementations((*sdk.Msg)(nil)) + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgDeposit{}, + &MsgWithdraw{}, + ) - // msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } var ( diff --git a/x/earn/types/errors.go b/x/earn/types/errors.go new file mode 100644 index 00000000..88a286d9 --- /dev/null +++ b/x/earn/types/errors.go @@ -0,0 +1,15 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// earn module errors +var ( + ErrInvalidVaultDenom = sdkerrors.Register(ModuleName, 2, "invalid vault denom") + ErrInvalidVaultStrategy = sdkerrors.Register(ModuleName, 3, "invalid vault strategy") + ErrInsufficientAmount = sdkerrors.Register(ModuleName, 4, "insufficient amount") + ErrInvalidShares = sdkerrors.Register(ModuleName, 5, "invalid shares") + ErrVaultRecordNotFound = sdkerrors.Register(ModuleName, 6, "vault record not found") + ErrVaultShareRecordNotFound = sdkerrors.Register(ModuleName, 7, "vault share record not found") +) diff --git a/x/earn/types/events.go b/x/earn/types/events.go new file mode 100644 index 00000000..00a12506 --- /dev/null +++ b/x/earn/types/events.go @@ -0,0 +1,12 @@ +package types + +// Event types for swap module +const ( + AttributeValueCategory = ModuleName + EventTypeVaultDeposit = "vault_deposit" + EventTypeVaultWithdraw = "vault_withdraw" + AttributeKeyVaultDenom = "vault_denom" + AttributeKeyDepositor = "depositor" + AttributeKeyShares = "shares" + AttributeKeyOwner = "owner" +) diff --git a/x/earn/types/genesis.pb.go b/x/earn/types/genesis.pb.go index 064526f7..74639846 100644 --- a/x/earn/types/genesis.pb.go +++ b/x/earn/types/genesis.pb.go @@ -23,10 +23,14 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// GenesisState defines the earn module's genesis state. +// GenesisState defines the swap module's genesis state. type GenesisState struct { // params defines all the paramaters related to earn Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + // vault_records defines the available vaults + VaultRecords VaultRecords `protobuf:"bytes,2,rep,name=vault_records,json=vaultRecords,proto3,castrepeated=VaultRecords" json:"vault_records"` + // share_records defines the owned shares of each vault + VaultShareRecords VaultShareRecords `protobuf:"bytes,3,rep,name=vault_share_records,json=vaultShareRecords,proto3,castrepeated=VaultShareRecords" json:"vault_share_records"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -69,65 +73,47 @@ func (m *GenesisState) GetParams() Params { return Params{} } -// Params defines the parameters for the earn module. -type Params struct { -} - -func (m *Params) Reset() { *m = Params{} } -func (m *Params) String() string { return proto.CompactTextString(m) } -func (*Params) ProtoMessage() {} -func (*Params) Descriptor() ([]byte, []int) { - return fileDescriptor_514fe130cb964f8c, []int{1} -} -func (m *Params) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Params.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 *GenesisState) GetVaultRecords() VaultRecords { + if m != nil { + return m.VaultRecords } -} -func (m *Params) XXX_Merge(src proto.Message) { - xxx_messageInfo_Params.Merge(m, src) -} -func (m *Params) XXX_Size() int { - return m.Size() -} -func (m *Params) XXX_DiscardUnknown() { - xxx_messageInfo_Params.DiscardUnknown(m) + return nil } -var xxx_messageInfo_Params proto.InternalMessageInfo +func (m *GenesisState) GetVaultShareRecords() VaultShareRecords { + if m != nil { + return m.VaultShareRecords + } + return nil +} func init() { proto.RegisterType((*GenesisState)(nil), "kava.earn.v1beta1.GenesisState") - proto.RegisterType((*Params)(nil), "kava.earn.v1beta1.Params") } func init() { proto.RegisterFile("kava/earn/v1beta1/genesis.proto", fileDescriptor_514fe130cb964f8c) } var fileDescriptor_514fe130cb964f8c = []byte{ - // 195 bytes of a gzipped FileDescriptorProto + // 293 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcf, 0x4e, 0x2c, 0x4b, 0xd4, 0x4f, 0x4d, 0x2c, 0xca, 0xd3, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x04, 0x29, 0xd0, - 0x03, 0x29, 0xd0, 0x83, 0x2a, 0x90, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xcb, 0xea, 0x83, 0x58, - 0x10, 0x85, 0x4a, 0xee, 0x5c, 0x3c, 0xee, 0x10, 0x9d, 0xc1, 0x25, 0x89, 0x25, 0xa9, 0x42, 0xe6, - 0x5c, 0x6c, 0x05, 0x89, 0x45, 0x89, 0xb9, 0xc5, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0xdc, 0x46, 0x92, - 0x7a, 0x18, 0x26, 0xe9, 0x05, 0x80, 0x15, 0x38, 0xb1, 0x9c, 0xb8, 0x27, 0xcf, 0x10, 0x04, 0x55, - 0xae, 0xc4, 0xc1, 0xc5, 0x06, 0x15, 0x77, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, - 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, - 0x86, 0x28, 0xb5, 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0x7d, 0x90, 0xb1, - 0xba, 0x39, 0x89, 0x49, 0xc5, 0x60, 0x96, 0x7e, 0x05, 0xc4, 0x37, 0x25, 0x95, 0x05, 0xa9, 0xc5, - 0x49, 0x6c, 0x60, 0xb7, 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x8c, 0x51, 0x81, 0x77, 0xe7, - 0x00, 0x00, 0x00, + 0x03, 0x29, 0xd0, 0x83, 0x2a, 0x90, 0x92, 0xc5, 0xd4, 0x53, 0x96, 0x58, 0x9a, 0x53, 0x02, 0xd1, + 0x21, 0x25, 0x87, 0x29, 0x5d, 0x90, 0x58, 0x94, 0x98, 0x0b, 0x35, 0x51, 0x4a, 0x24, 0x3d, 0x3f, + 0x3d, 0x1f, 0xcc, 0xd4, 0x07, 0xb1, 0x20, 0xa2, 0x4a, 0x93, 0x98, 0xb8, 0x78, 0xdc, 0x21, 0x36, + 0x07, 0x97, 0x24, 0x96, 0xa4, 0x0a, 0x99, 0x73, 0xb1, 0x41, 0xb4, 0x49, 0x30, 0x2a, 0x30, 0x6a, + 0x70, 0x1b, 0x49, 0xea, 0x61, 0xb8, 0x44, 0x2f, 0x00, 0xac, 0xc0, 0x89, 0xe5, 0xc4, 0x3d, 0x79, + 0x86, 0x20, 0xa8, 0x72, 0xa1, 0x48, 0x2e, 0x5e, 0xb0, 0x73, 0xe2, 0x8b, 0x52, 0x93, 0xf3, 0x8b, + 0x52, 0x8a, 0x25, 0x98, 0x14, 0x98, 0x35, 0xb8, 0x8d, 0xe4, 0xb0, 0xe8, 0x0f, 0x03, 0xa9, 0x0b, + 0x02, 0x2b, 0x73, 0x12, 0x01, 0x19, 0xb2, 0xea, 0xbe, 0x3c, 0x0f, 0x92, 0x60, 0x71, 0x10, 0x4f, + 0x19, 0x12, 0x4f, 0x28, 0x8f, 0x4b, 0x18, 0x62, 0x74, 0x71, 0x46, 0x62, 0x51, 0x2a, 0xdc, 0x02, + 0x66, 0xb0, 0x05, 0xca, 0xb8, 0x2c, 0x08, 0x06, 0x29, 0x86, 0xda, 0x22, 0x09, 0xb5, 0x45, 0x10, + 0x5d, 0xa6, 0x38, 0x48, 0xb0, 0x0c, 0x5d, 0xc8, 0xc9, 0xe1, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, + 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, + 0x8f, 0xe5, 0x18, 0xa2, 0xd4, 0xd2, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xf5, + 0x41, 0xd6, 0xea, 0xe6, 0x24, 0x26, 0x15, 0x83, 0x59, 0xfa, 0x15, 0x90, 0xb0, 0x2f, 0xa9, 0x2c, + 0x48, 0x2d, 0x4e, 0x62, 0x03, 0x87, 0xae, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x97, 0x15, 0xe4, + 0xfa, 0xe8, 0x01, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -150,6 +136,34 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.VaultShareRecords) > 0 { + for iNdEx := len(m.VaultShareRecords) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.VaultShareRecords[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.VaultRecords) > 0 { + for iNdEx := len(m.VaultRecords) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.VaultRecords[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } { size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -163,29 +177,6 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { offset -= sovGenesis(v) base := offset @@ -205,15 +196,18 @@ func (m *GenesisState) Size() (n int) { _ = l l = m.Params.Size() n += 1 + l + sovGenesis(uint64(l)) - return n -} - -func (m *Params) Size() (n int) { - if m == nil { - return 0 + if len(m.VaultRecords) > 0 { + for _, e := range m.VaultRecords { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.VaultShareRecords) > 0 { + for _, e := range m.VaultShareRecords { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } } - var l int - _ = l return n } @@ -285,56 +279,74 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGenesis(dAtA[iNdEx:]) - if err != nil { - return err + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VaultRecords", wireType) } - if (skippy < 0) || (iNdEx+skippy) < 0 { + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { return ErrInvalidLengthGenesis } - if (iNdEx + skippy) > l { + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { return io.ErrUnexpectedEOF } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Params) 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 ErrIntOverflowGenesis + m.VaultRecords = append(m.VaultRecords, VaultRecord{}) + if err := m.VaultRecords[len(m.VaultRecords)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - if iNdEx >= l { + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VaultShareRecords", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + m.VaultShareRecords = append(m.VaultShareRecords, VaultShareRecord{}) + if err := m.VaultShareRecords[len(m.VaultShareRecords)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Params: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/earn/types/keys.go b/x/earn/types/keys.go index f81cdc5d..ae5bd25d 100644 --- a/x/earn/types/keys.go +++ b/x/earn/types/keys.go @@ -1,5 +1,7 @@ package types +import sdk "github.com/cosmos/cosmos-sdk/types" + const ( // ModuleName name that will be used throughout the module ModuleName = "earn" @@ -19,3 +21,28 @@ const ( // DefaultParamspace default name for parameter store DefaultParamspace = ModuleName ) + +// key prefixes for store +var ( + VaultRecordKeyPrefix = []byte{0x01} // denom -> vault + VaultSharePrefix = []byte{0x02} + + sep = []byte("|") +) + +// Vault returns a key generated from a vault denom +func VaultKey(denom string) []byte { + return []byte(denom) +} + +// DepositorVaultSharesKey returns a key from a depositor and vault denom +func DepositorVaultSharesKey(depositor sdk.AccAddress, vaultDenom string) []byte { + return createKey(depositor, sep, []byte(vaultDenom)) +} + +func createKey(bytes ...[]byte) (r []byte) { + for _, b := range bytes { + r = append(r, b...) + } + return +} diff --git a/x/earn/types/msg.go b/x/earn/types/msg.go new file mode 100644 index 00000000..cde644f9 --- /dev/null +++ b/x/earn/types/msg.go @@ -0,0 +1,85 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +var ( + _ sdk.Msg = &MsgDeposit{} + _ sdk.Msg = &MsgWithdraw{} +) + +// NewMsgDeposit returns a new MsgDeposit. +func NewMsgDeposit(depositor string, amount sdk.Coin) *MsgDeposit { + return &MsgDeposit{ + Depositor: depositor, + Amount: amount, + } +} + +// ValidateBasic does a simple validation check that doesn't require access to any other information. +func (msg MsgDeposit) ValidateBasic() error { + if msg.Depositor == "" { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "depositor address cannot be empty") + } + + if err := msg.Amount.Validate(); err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, err.Error()) + } + + return nil +} + +// GetSignBytes gets the canonical byte representation of the Msg. +func (msg MsgDeposit) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(&msg) + return sdk.MustSortJSON(bz) +} + +// GetSigners returns the addresses of signers that must sign. +func (msg MsgDeposit) GetSigners() []sdk.AccAddress { + depositor, err := sdk.AccAddressFromBech32(msg.Depositor) + if err != nil { + panic(err) + } + + return []sdk.AccAddress{depositor} +} + +// NewMsgWithdraw returns a new MsgWithdraw. +func NewMsgWithdraw(from string, amount sdk.Coin) *MsgWithdraw { + return &MsgWithdraw{ + From: from, + Amount: amount, + } +} + +// ValidateBasic does a simple validation check that doesn't require access to any other information. +func (msg MsgWithdraw) ValidateBasic() error { + if msg.From == "" { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "depositor address cannot be empty") + } + + if err := msg.Amount.Validate(); err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, err.Error()) + } + + return nil +} + +// GetSignBytes gets the canonical byte representation of the Msg. +func (msg MsgWithdraw) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(&msg) + return sdk.MustSortJSON(bz) +} + +// GetSigners returns the addresses of signers that must sign. +func (msg MsgWithdraw) GetSigners() []sdk.AccAddress { + depositor, err := sdk.AccAddressFromBech32(msg.From) + if err != nil { + panic(err) + } + + return []sdk.AccAddress{depositor} +} diff --git a/x/earn/types/params.go b/x/earn/types/params.go index f23792eb..5a5b18e2 100644 --- a/x/earn/types/params.go +++ b/x/earn/types/params.go @@ -1,20 +1,27 @@ package types import ( + fmt "fmt" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // Parameter keys and default values -var () +var ( + KeyAllowedVaults = []byte("AllowedVaults") + DefaultAllowedVaults = AllowedVaults{} +) // NewParams returns a new params object -func NewParams() Params { - return Params{} +func NewParams(allowedVaults AllowedVaults) Params { + return Params{ + AllowedVaults: allowedVaults, + } } // DefaultParams returns default params for earn module func DefaultParams() Params { - return NewParams() + return NewParams(DefaultAllowedVaults) } // ParamKeyTable for earn module. @@ -25,12 +32,20 @@ func ParamKeyTable() paramtypes.KeyTable { // ParamSetPairs implements params.ParamSet func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { return paramtypes.ParamSetPairs{ - // paramtypes.NewParamSetPair(...), + paramtypes.NewParamSetPair(KeyAllowedVaults, &p.AllowedVaults, validateAllowedVaultsParams), } } // Validate checks that the parameters have valid values. func (p Params) Validate() error { - // TODO: - return nil + return p.AllowedVaults.Validate() +} + +func validateAllowedVaultsParams(i interface{}) error { + p, ok := i.(AllowedVaults) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + return p.Validate() } diff --git a/x/earn/types/params.pb.go b/x/earn/types/params.pb.go new file mode 100644 index 00000000..652f43f4 --- /dev/null +++ b/x/earn/types/params.pb.go @@ -0,0 +1,330 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: kava/earn/v1beta1/params.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + 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 + +type Params struct { + AllowedVaults AllowedVaults `protobuf:"bytes,1,rep,name=allowed_vaults,json=allowedVaults,proto3,castrepeated=AllowedVaults" json:"allowed_vaults"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_b9b515f90f68dc5a, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.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 *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetAllowedVaults() AllowedVaults { + if m != nil { + return m.AllowedVaults + } + return nil +} + +func init() { + proto.RegisterType((*Params)(nil), "kava.earn.v1beta1.Params") +} + +func init() { proto.RegisterFile("kava/earn/v1beta1/params.proto", fileDescriptor_b9b515f90f68dc5a) } + +var fileDescriptor_b9b515f90f68dc5a = []byte{ + // 212 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcb, 0x4e, 0x2c, 0x4b, + 0xd4, 0x4f, 0x4d, 0x2c, 0xca, 0xd3, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x2f, 0x48, + 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x04, 0xc9, 0xeb, 0x81, + 0xe4, 0xf5, 0xa0, 0xf2, 0x52, 0x22, 0xe9, 0xf9, 0xe9, 0xf9, 0x60, 0x59, 0x7d, 0x10, 0x0b, 0xa2, + 0x50, 0x4a, 0x16, 0xd3, 0xa0, 0xb2, 0xc4, 0xd2, 0x9c, 0x12, 0x88, 0xb4, 0x52, 0x3a, 0x17, 0x5b, + 0x00, 0xd8, 0x5c, 0xa1, 0x58, 0x2e, 0xbe, 0xc4, 0x9c, 0x9c, 0xfc, 0xf2, 0xd4, 0x94, 0x78, 0xb0, + 0x82, 0x62, 0x09, 0x46, 0x05, 0x66, 0x0d, 0x6e, 0x23, 0x79, 0x3d, 0x0c, 0xab, 0xf4, 0x1c, 0x21, + 0x0a, 0xc3, 0x40, 0xea, 0x9c, 0x44, 0x4f, 0xdc, 0x93, 0x67, 0x58, 0x75, 0x5f, 0x9e, 0x17, 0x59, + 0xb4, 0x38, 0x88, 0x37, 0x11, 0x99, 0xeb, 0xe4, 0x70, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, + 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, + 0x72, 0x0c, 0x51, 0x6a, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x20, + 0xab, 0x74, 0x73, 0x12, 0x93, 0x8a, 0xc1, 0x2c, 0xfd, 0x0a, 0x88, 0xc3, 0x4b, 0x2a, 0x0b, 0x52, + 0x8b, 0x93, 0xd8, 0xc0, 0x2e, 0x36, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x93, 0xe4, 0x56, 0x4c, + 0x1b, 0x01, 0x00, 0x00, +} + +func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AllowedVaults) > 0 { + for iNdEx := len(m.AllowedVaults) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AllowedVaults[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintParams(dAtA []byte, offset int, v uint64) int { + offset -= sovParams(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.AllowedVaults) > 0 { + for _, e := range m.AllowedVaults { + l = e.Size() + n += 1 + l + sovParams(uint64(l)) + } + } + return n +} + +func sovParams(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozParams(x uint64) (n int) { + return sovParams(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) 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 ErrIntOverflowParams + } + 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowedVaults", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AllowedVaults = append(m.AllowedVaults, AllowedVault{}) + if err := m.AllowedVaults[len(m.AllowedVaults)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipParams(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthParams + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipParams(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, ErrIntOverflowParams + } + 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, ErrIntOverflowParams + } + 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, ErrIntOverflowParams + } + 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, ErrInvalidLengthParams + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupParams + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthParams + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthParams = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowParams = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupParams = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/earn/types/query.go b/x/earn/types/query.go new file mode 100644 index 00000000..6323482a --- /dev/null +++ b/x/earn/types/query.go @@ -0,0 +1,5 @@ +package types + +func NewQueryParamsRequest() *QueryParamsRequest { + return &QueryParamsRequest{} +} diff --git a/x/earn/types/query.pb.go b/x/earn/types/query.pb.go index c9ff2246..f6b002e4 100644 --- a/x/earn/types/query.pb.go +++ b/x/earn/types/query.pb.go @@ -114,26 +114,26 @@ func init() { func init() { proto.RegisterFile("kava/earn/v1beta1/query.proto", fileDescriptor_63f8dee2f3192a6b) } var fileDescriptor_63f8dee2f3192a6b = []byte{ - // 304 bytes of a gzipped FileDescriptorProto + // 297 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcd, 0x4e, 0x2c, 0x4b, 0xd4, 0x4f, 0x4d, 0x2c, 0xca, 0xd3, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x2f, 0x2c, 0x4d, 0x2d, 0xaa, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x04, 0x49, 0xeb, 0x81, 0xa4, 0xf5, 0xa0, 0xd2, 0x52, 0x22, 0xe9, 0xf9, 0xe9, 0xf9, 0x60, 0x59, 0x7d, 0x10, 0x0b, 0xa2, 0x50, 0x4a, 0x26, 0x3d, 0x3f, 0x3f, 0x3d, 0x27, 0x55, 0x3f, 0xb1, 0x20, 0x53, 0x3f, 0x31, 0x2f, 0x2f, 0xbf, 0x24, 0xb1, 0x24, 0x33, 0x3f, 0xaf, 0x18, 0x2a, 0x2b, 0x99, 0x9c, 0x5f, 0x9c, 0x9b, 0x5f, - 0x1c, 0x0f, 0xd1, 0x06, 0xe1, 0x40, 0xa5, 0xe4, 0x31, 0x1d, 0x90, 0x9e, 0x9a, 0x97, 0x5a, 0x9c, - 0x09, 0x55, 0xa0, 0x24, 0xc5, 0x25, 0x14, 0x08, 0x72, 0x51, 0x40, 0x62, 0x51, 0x62, 0x6e, 0x71, - 0x50, 0x6a, 0x61, 0x69, 0x6a, 0x71, 0x89, 0x15, 0x4b, 0xc7, 0x02, 0x79, 0x06, 0xa5, 0x10, 0x2e, - 0x61, 0x14, 0xb9, 0xe2, 0x82, 0xfc, 0xbc, 0xe2, 0x54, 0x21, 0x73, 0x2e, 0xb6, 0x02, 0xb0, 0x88, - 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xb7, 0x91, 0xa4, 0x1e, 0x86, 0x37, 0xf4, 0x20, 0x5a, 0x9c, 0x58, - 0x4e, 0xdc, 0x93, 0x67, 0x08, 0x82, 0x2a, 0x87, 0x98, 0x6a, 0xd4, 0xcc, 0xc8, 0xc5, 0x0a, 0x36, - 0x56, 0xa8, 0x8a, 0x8b, 0x0d, 0xa2, 0x4e, 0x48, 0x15, 0x8b, 0x11, 0x98, 0xce, 0x92, 0x52, 0x23, - 0xa4, 0x0c, 0xe2, 0x42, 0x25, 0xc5, 0xa6, 0xcb, 0x4f, 0x26, 0x33, 0x49, 0x0b, 0x49, 0xea, 0x63, - 0x7a, 0x1f, 0xe2, 0x16, 0x27, 0x87, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, - 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, - 0x52, 0x4b, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0x05, 0x6b, 0xd7, 0xcd, 0x49, - 0x4c, 0x2a, 0x86, 0x18, 0x54, 0x01, 0x31, 0xaa, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, 0x1c, - 0x80, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2b, 0x93, 0x51, 0x95, 0xe4, 0x01, 0x00, 0x00, + 0x1c, 0x0f, 0xd1, 0x06, 0xe1, 0x40, 0xa5, 0xe4, 0x30, 0x1d, 0x50, 0x90, 0x58, 0x94, 0x98, 0x0b, + 0x95, 0x57, 0x92, 0xe2, 0x12, 0x0a, 0x04, 0x39, 0x28, 0x00, 0x2c, 0x18, 0x94, 0x5a, 0x58, 0x9a, + 0x5a, 0x5c, 0x62, 0xc5, 0xd2, 0xb1, 0x40, 0x9e, 0x41, 0x29, 0x84, 0x4b, 0x18, 0x45, 0xae, 0xb8, + 0x20, 0x3f, 0xaf, 0x38, 0x55, 0xc8, 0x9c, 0x8b, 0x0d, 0x62, 0x84, 0x04, 0xa3, 0x02, 0xa3, 0x06, + 0xb7, 0x91, 0xa4, 0x1e, 0x86, 0x2f, 0xf4, 0x20, 0x5a, 0x9c, 0x58, 0x4e, 0xdc, 0x93, 0x67, 0x08, + 0x82, 0x2a, 0x87, 0x98, 0x6a, 0xd4, 0xcc, 0xc8, 0xc5, 0x0a, 0x36, 0x56, 0xa8, 0x8a, 0x8b, 0x0d, + 0xa2, 0x4e, 0x48, 0x15, 0x8b, 0x11, 0x98, 0xce, 0x92, 0x52, 0x23, 0xa4, 0x0c, 0xe2, 0x42, 0x25, + 0xc5, 0xa6, 0xcb, 0x4f, 0x26, 0x33, 0x49, 0x0b, 0x49, 0xea, 0xe3, 0xf2, 0xbd, 0x93, 0xc3, 0x89, + 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, + 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0xa9, 0xa5, 0x67, 0x96, 0x64, 0x94, 0x26, + 0xe9, 0x25, 0xe7, 0xe7, 0x82, 0xb5, 0xeb, 0xe6, 0x24, 0x26, 0x15, 0x43, 0x0c, 0xaa, 0x80, 0x18, + 0x55, 0x52, 0x59, 0x90, 0x5a, 0x9c, 0xc4, 0x06, 0x0e, 0x40, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x84, 0xd8, 0x0f, 0xf9, 0xe3, 0x01, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/earn/types/strategy.pb.go b/x/earn/types/strategy.pb.go new file mode 100644 index 00000000..99beb5c0 --- /dev/null +++ b/x/earn/types/strategy.pb.go @@ -0,0 +1,84 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: kava/earn/v1beta1/strategy.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + math "math" +) + +// 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 + +type StrategyType int32 + +const ( + STRATEGY_TYPE_UNKNOWN StrategyType = 0 + STRATEGY_TYPE_KAVA_STAKERS StrategyType = 1 + // USDC / BUSD vaults use the same strategy but with the denom set in VaultRecord + STRATEGY_TYPE_STABLECOIN_STAKERS StrategyType = 2 + STRATEGY_TYPE_KAVA_FOUNDATION StrategyType = 3 +) + +var StrategyType_name = map[int32]string{ + 0: "STRATEGY_TYPE_UNKNOWN", + 1: "STRATEGY_TYPE_KAVA_STAKERS", + 2: "STRATEGY_TYPE_STABLECOIN_STAKERS", + 3: "STRATEGY_TYPE_KAVA_FOUNDATION", +} + +var StrategyType_value = map[string]int32{ + "STRATEGY_TYPE_UNKNOWN": 0, + "STRATEGY_TYPE_KAVA_STAKERS": 1, + "STRATEGY_TYPE_STABLECOIN_STAKERS": 2, + "STRATEGY_TYPE_KAVA_FOUNDATION": 3, +} + +func (x StrategyType) String() string { + return proto.EnumName(StrategyType_name, int32(x)) +} + +func (StrategyType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_257c4968dd48fa09, []int{0} +} + +func init() { + proto.RegisterEnum("kava.earn.v1beta1.StrategyType", StrategyType_name, StrategyType_value) +} + +func init() { proto.RegisterFile("kava/earn/v1beta1/strategy.proto", fileDescriptor_257c4968dd48fa09) } + +var fileDescriptor_257c4968dd48fa09 = []byte{ + // 278 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xc8, 0x4e, 0x2c, 0x4b, + 0xd4, 0x4f, 0x4d, 0x2c, 0xca, 0xd3, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x2f, 0x2e, + 0x29, 0x4a, 0x2c, 0x49, 0x4d, 0xaf, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x04, 0xa9, + 0xd0, 0x03, 0xa9, 0xd0, 0x83, 0xaa, 0x90, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xcb, 0xea, 0x83, + 0x58, 0x10, 0x85, 0x52, 0x72, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xfa, 0x49, 0x89, 0xc5, 0xa9, + 0x70, 0xc3, 0x92, 0xf3, 0x33, 0xf3, 0xa0, 0xf2, 0x92, 0x10, 0xf9, 0x78, 0x88, 0x46, 0x08, 0x07, + 0x22, 0xa5, 0x35, 0x83, 0x91, 0x8b, 0x27, 0x18, 0x6a, 0x6d, 0x48, 0x65, 0x41, 0xaa, 0x90, 0x24, + 0x97, 0x68, 0x70, 0x48, 0x90, 0x63, 0x88, 0xab, 0x7b, 0x64, 0x7c, 0x48, 0x64, 0x80, 0x6b, 0x7c, + 0xa8, 0x9f, 0xb7, 0x9f, 0x7f, 0xb8, 0x9f, 0x00, 0x83, 0x90, 0x1c, 0x97, 0x14, 0xaa, 0x94, 0xb7, + 0x63, 0x98, 0x63, 0x7c, 0x70, 0x88, 0xa3, 0xb7, 0x6b, 0x50, 0xb0, 0x00, 0xa3, 0x90, 0x0a, 0x97, + 0x02, 0xaa, 0x7c, 0x70, 0x88, 0xa3, 0x93, 0x8f, 0xab, 0xb3, 0xbf, 0xa7, 0x1f, 0x5c, 0x15, 0x93, + 0x90, 0x22, 0x97, 0x2c, 0x16, 0x53, 0xdc, 0xfc, 0x43, 0xfd, 0x5c, 0x1c, 0x43, 0x3c, 0xfd, 0xfd, + 0x04, 0x98, 0xa5, 0x58, 0x3a, 0x16, 0xcb, 0x31, 0x38, 0x39, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, + 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, + 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x5a, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, + 0x3e, 0x28, 0x8c, 0x74, 0x73, 0x12, 0x93, 0x8a, 0xc1, 0x2c, 0xfd, 0x0a, 0x48, 0x88, 0x96, 0x54, + 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0xfd, 0x68, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x85, 0x84, + 0x93, 0x9f, 0x6b, 0x01, 0x00, 0x00, +} diff --git a/x/earn/types/tx.pb.go b/x/earn/types/tx.pb.go index 36cf61f1..d270a601 100644 --- a/x/earn/types/tx.pb.go +++ b/x/earn/types/tx.pb.go @@ -6,10 +6,17 @@ 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. @@ -23,19 +30,198 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// MsgDeposit represents a message for depositing assedts into a vault +type MsgDeposit struct { + // depositor represents the address to deposit funds from + Depositor string `protobuf:"bytes,1,opt,name=depositor,proto3" json:"depositor,omitempty"` + // Amount represents the token to deposit. The vault corresponds to the denom + // of the amount coin. + Amount types.Coin `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgDeposit) Reset() { *m = MsgDeposit{} } +func (m *MsgDeposit) String() string { return proto.CompactTextString(m) } +func (*MsgDeposit) ProtoMessage() {} +func (*MsgDeposit) Descriptor() ([]byte, []int) { + return fileDescriptor_2e9dcf48a3fa0009, []int{0} +} +func (m *MsgDeposit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDeposit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDeposit.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 *MsgDeposit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDeposit.Merge(m, src) +} +func (m *MsgDeposit) XXX_Size() int { + return m.Size() +} +func (m *MsgDeposit) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDeposit.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDeposit proto.InternalMessageInfo + +// MsgDepositResponse defines the Msg/Deposit response type. +type MsgDepositResponse struct { +} + +func (m *MsgDepositResponse) Reset() { *m = MsgDepositResponse{} } +func (m *MsgDepositResponse) String() string { return proto.CompactTextString(m) } +func (*MsgDepositResponse) ProtoMessage() {} +func (*MsgDepositResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_2e9dcf48a3fa0009, []int{1} +} +func (m *MsgDepositResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDepositResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDepositResponse.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 *MsgDepositResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDepositResponse.Merge(m, src) +} +func (m *MsgDepositResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgDepositResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDepositResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDepositResponse proto.InternalMessageInfo + +// MsgWithdraw represents a message for withdrawing liquidity from a vault +type MsgWithdraw struct { + // from represents the address we are withdrawing for + From string `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + // Amount represents the token to withdraw. The vault corresponds to the denom + // of the amount coin. + Amount types.Coin `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgWithdraw) Reset() { *m = MsgWithdraw{} } +func (m *MsgWithdraw) String() string { return proto.CompactTextString(m) } +func (*MsgWithdraw) ProtoMessage() {} +func (*MsgWithdraw) Descriptor() ([]byte, []int) { + return fileDescriptor_2e9dcf48a3fa0009, []int{2} +} +func (m *MsgWithdraw) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgWithdraw) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgWithdraw.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 *MsgWithdraw) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithdraw.Merge(m, src) +} +func (m *MsgWithdraw) XXX_Size() int { + return m.Size() +} +func (m *MsgWithdraw) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithdraw.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithdraw proto.InternalMessageInfo + +// MsgWithdrawResponse defines the Msg/Withdraw response type. +type MsgWithdrawResponse struct { +} + +func (m *MsgWithdrawResponse) Reset() { *m = MsgWithdrawResponse{} } +func (m *MsgWithdrawResponse) String() string { return proto.CompactTextString(m) } +func (*MsgWithdrawResponse) ProtoMessage() {} +func (*MsgWithdrawResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_2e9dcf48a3fa0009, []int{3} +} +func (m *MsgWithdrawResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgWithdrawResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgWithdrawResponse.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 *MsgWithdrawResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithdrawResponse.Merge(m, src) +} +func (m *MsgWithdrawResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgWithdrawResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithdrawResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithdrawResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgDeposit)(nil), "kava.earn.v1beta1.MsgDeposit") + proto.RegisterType((*MsgDepositResponse)(nil), "kava.earn.v1beta1.MsgDepositResponse") + proto.RegisterType((*MsgWithdraw)(nil), "kava.earn.v1beta1.MsgWithdraw") + proto.RegisterType((*MsgWithdrawResponse)(nil), "kava.earn.v1beta1.MsgWithdrawResponse") +} + func init() { proto.RegisterFile("kava/earn/v1beta1/tx.proto", fileDescriptor_2e9dcf48a3fa0009) } var fileDescriptor_2e9dcf48a3fa0009 = []byte{ - // 132 bytes of a gzipped FileDescriptorProto + // 367 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xca, 0x4e, 0x2c, 0x4b, 0xd4, 0x4f, 0x4d, 0x2c, 0xca, 0xd3, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x2f, 0xa9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x04, 0xc9, 0xe9, 0x81, 0xe4, 0xf4, 0xa0, 0x72, - 0x46, 0xac, 0x5c, 0xcc, 0xbe, 0xc5, 0xe9, 0x4e, 0x0e, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, - 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, - 0x2c, 0xc7, 0x10, 0xa5, 0x96, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x0f, - 0xd2, 0xae, 0x9b, 0x93, 0x98, 0x54, 0x0c, 0x66, 0xe9, 0x57, 0x40, 0xac, 0x29, 0xa9, 0x2c, 0x48, - 0x2d, 0x4e, 0x62, 0x03, 0x5b, 0x61, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xc6, 0x97, 0xb1, 0x60, - 0x80, 0x00, 0x00, 0x00, + 0x52, 0x22, 0xe9, 0xf9, 0xe9, 0xf9, 0x60, 0x59, 0x7d, 0x10, 0x0b, 0xa2, 0x50, 0x4a, 0x32, 0x39, + 0xbf, 0x38, 0x37, 0xbf, 0x38, 0x1e, 0x22, 0x01, 0xe1, 0x40, 0xa5, 0xe4, 0x20, 0x3c, 0xfd, 0xa4, + 0xc4, 0xe2, 0x54, 0xb8, 0x0d, 0xc9, 0xf9, 0x99, 0x79, 0x10, 0x79, 0xa5, 0x66, 0x46, 0x2e, 0x2e, + 0xdf, 0xe2, 0x74, 0x97, 0xd4, 0x82, 0xfc, 0xe2, 0xcc, 0x12, 0x21, 0x33, 0x2e, 0xce, 0x14, 0x08, + 0x33, 0xbf, 0x48, 0x82, 0x51, 0x81, 0x51, 0x83, 0xd3, 0x49, 0xe2, 0xd2, 0x16, 0x5d, 0x11, 0xa8, + 0x99, 0x8e, 0x29, 0x29, 0x45, 0xa9, 0xc5, 0xc5, 0xc1, 0x25, 0x45, 0x99, 0x79, 0xe9, 0x41, 0x08, + 0xa5, 0x42, 0xe6, 0x5c, 0x6c, 0x89, 0xb9, 0xf9, 0xa5, 0x79, 0x25, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, + 0xdc, 0x46, 0x92, 0x7a, 0x50, 0x1d, 0x20, 0x7b, 0x61, 0xae, 0xd7, 0x73, 0xce, 0xcf, 0xcc, 0x73, + 0x62, 0x39, 0x71, 0x4f, 0x9e, 0x21, 0x08, 0xaa, 0xdc, 0x8a, 0xa5, 0x63, 0x81, 0x3c, 0x83, 0x92, + 0x08, 0x97, 0x10, 0xc2, 0x11, 0x41, 0xa9, 0xc5, 0x05, 0xf9, 0x79, 0xc5, 0xa9, 0x4a, 0x55, 0x5c, + 0xdc, 0xbe, 0xc5, 0xe9, 0xe1, 0x99, 0x25, 0x19, 0x29, 0x45, 0x89, 0xe5, 0x42, 0x3a, 0x5c, 0x2c, + 0x69, 0x45, 0xf9, 0xb9, 0x04, 0x9d, 0x05, 0x56, 0x45, 0xa9, 0x8b, 0x44, 0xb9, 0x84, 0x91, 0xec, + 0x86, 0x39, 0xc9, 0x68, 0x15, 0x23, 0x17, 0xb3, 0x6f, 0x71, 0xba, 0x90, 0x3f, 0x17, 0x3b, 0x2c, + 0xc8, 0x64, 0xf5, 0x30, 0xa2, 0x49, 0x0f, 0xe1, 0x19, 0x29, 0x55, 0xbc, 0xd2, 0x30, 0x83, 0x85, + 0x82, 0xb8, 0x38, 0xe0, 0x1e, 0x95, 0xc3, 0xae, 0x05, 0x26, 0x2f, 0xa5, 0x86, 0x5f, 0x1e, 0x66, + 0xa6, 0x93, 0xc3, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, + 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0xa9, 0xa5, 0x67, + 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x83, 0xcc, 0xd2, 0xcd, 0x49, 0x4c, 0x2a, + 0x06, 0xb3, 0xf4, 0x2b, 0x20, 0x89, 0xb1, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, 0x9c, 0x48, + 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x0d, 0x62, 0xb1, 0xf7, 0xa6, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -50,6 +236,10 @@ const _ = grpc.SupportPackageIsVersion4 // // 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 { + // Deposit defines a method for depositing assets into a vault + Deposit(ctx context.Context, in *MsgDeposit, opts ...grpc.CallOption) (*MsgDepositResponse, error) + // Withdraw defines a method for withdrawing assets into a vault + Withdraw(ctx context.Context, in *MsgWithdraw, opts ...grpc.CallOption) (*MsgWithdrawResponse, error) } type msgClient struct { @@ -60,22 +250,702 @@ func NewMsgClient(cc grpc1.ClientConn) MsgClient { return &msgClient{cc} } +func (c *msgClient) Deposit(ctx context.Context, in *MsgDeposit, opts ...grpc.CallOption) (*MsgDepositResponse, error) { + out := new(MsgDepositResponse) + err := c.cc.Invoke(ctx, "/kava.earn.v1beta1.Msg/Deposit", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Withdraw(ctx context.Context, in *MsgWithdraw, opts ...grpc.CallOption) (*MsgWithdrawResponse, error) { + out := new(MsgWithdrawResponse) + err := c.cc.Invoke(ctx, "/kava.earn.v1beta1.Msg/Withdraw", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { + // Deposit defines a method for depositing assets into a vault + Deposit(context.Context, *MsgDeposit) (*MsgDepositResponse, error) + // Withdraw defines a method for withdrawing assets into a vault + Withdraw(context.Context, *MsgWithdraw) (*MsgWithdrawResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. type UnimplementedMsgServer struct { } +func (*UnimplementedMsgServer) Deposit(ctx context.Context, req *MsgDeposit) (*MsgDepositResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Deposit not implemented") +} +func (*UnimplementedMsgServer) Withdraw(ctx context.Context, req *MsgWithdraw) (*MsgWithdrawResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Withdraw not implemented") +} + func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) } +func _Msg_Deposit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgDeposit) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Deposit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/kava.earn.v1beta1.Msg/Deposit", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Deposit(ctx, req.(*MsgDeposit)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Withdraw_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgWithdraw) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Withdraw(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/kava.earn.v1beta1.Msg/Withdraw", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Withdraw(ctx, req.(*MsgWithdraw)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "kava.earn.v1beta1.Msg", HandlerType: (*MsgServer)(nil), - Methods: []grpc.MethodDesc{}, - Streams: []grpc.StreamDesc{}, - Metadata: "kava/earn/v1beta1/tx.proto", + Methods: []grpc.MethodDesc{ + { + MethodName: "Deposit", + Handler: _Msg_Deposit_Handler, + }, + { + MethodName: "Withdraw", + Handler: _Msg_Withdraw_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "kava/earn/v1beta1/tx.proto", } + +func (m *MsgDeposit) 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 *MsgDeposit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDeposit) 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] = 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 *MsgDepositResponse) 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 *MsgDepositResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDepositResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgWithdraw) 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 *MsgWithdraw) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgWithdraw) 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] = 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 *MsgWithdrawResponse) 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 *MsgWithdrawResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgWithdrawResponse) 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 *MsgDeposit) 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 = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgDepositResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgWithdraw) 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 = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgWithdrawResponse) 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 *MsgDeposit) 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: MsgDeposit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDeposit: 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 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 *MsgDepositResponse) 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: MsgDepositResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDepositResponse: 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 *MsgWithdraw) 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: MsgWithdraw: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgWithdraw: 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 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 *MsgWithdrawResponse) 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: MsgWithdrawResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgWithdrawResponse: 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") +) diff --git a/x/earn/types/vault.go b/x/earn/types/vault.go new file mode 100644 index 00000000..723868d2 --- /dev/null +++ b/x/earn/types/vault.go @@ -0,0 +1,66 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// NewVaultRecord returns a new VaultRecord with 0 supply. +func NewVaultRecord(vaultDenom string) VaultRecord { + return VaultRecord{ + Denom: vaultDenom, + TotalSupply: sdk.NewCoin(vaultDenom, sdk.ZeroInt()), + } +} + +type VaultRecords []VaultRecord + +type VaultShareRecords []VaultShareRecord + +// NewVaultShareRecord returns a new VaultShareRecord with 0 supply. +func NewVaultShareRecord(depositor sdk.AccAddress, vaultDenom string) VaultShareRecord { + return VaultShareRecord{ + Depositor: depositor, + AmountSupplied: sdk.NewCoin(vaultDenom, sdk.ZeroInt()), + } +} + +// NewAllowedVaults returns a new AllowedVaults with the given denom and strategy type. +func NewAllowedVault(denom string, strategyType StrategyType) AllowedVault { + return AllowedVault{ + Denom: denom, + VaultStrategy: strategyType, + } +} + +type AllowedVaults []AllowedVault + +func (a AllowedVaults) Validate() error { + denoms := make(map[string]bool) + + for _, v := range a { + if err := v.Validate(); err != nil { + return err + } + + if denoms[v.Denom] { + return fmt.Errorf("duplicate vault denom %s", v.Denom) + } + + denoms[v.Denom] = true + } + return nil +} + +func (a *AllowedVault) Validate() error { + if a.Denom == "" { + return ErrInvalidVaultDenom + } + + if a.VaultStrategy == STRATEGY_TYPE_UNKNOWN { + return ErrInvalidVaultStrategy + } + + return nil +} diff --git a/x/earn/types/vault.pb.go b/x/earn/types/vault.pb.go new file mode 100644 index 00000000..2d1aa65f --- /dev/null +++ b/x/earn/types/vault.pb.go @@ -0,0 +1,830 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: kava/earn/v1beta1/vault.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + 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 + +// AllowedVault is a vault that is allowed to be created. These can be +// modified via parameter governance. +type AllowedVault struct { + // Denom is the only supported denomination of the vault for deposits and withdrawals. + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + // VaultStrategy is the strategies to use for this vault. + VaultStrategy StrategyType `protobuf:"varint,2,opt,name=vault_strategy,json=vaultStrategy,proto3,enum=kava.earn.v1beta1.StrategyType" json:"vault_strategy,omitempty"` +} + +func (m *AllowedVault) Reset() { *m = AllowedVault{} } +func (m *AllowedVault) String() string { return proto.CompactTextString(m) } +func (*AllowedVault) ProtoMessage() {} +func (*AllowedVault) Descriptor() ([]byte, []int) { + return fileDescriptor_884eb89509fbdc04, []int{0} +} +func (m *AllowedVault) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AllowedVault) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AllowedVault.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 *AllowedVault) XXX_Merge(src proto.Message) { + xxx_messageInfo_AllowedVault.Merge(m, src) +} +func (m *AllowedVault) XXX_Size() int { + return m.Size() +} +func (m *AllowedVault) XXX_DiscardUnknown() { + xxx_messageInfo_AllowedVault.DiscardUnknown(m) +} + +var xxx_messageInfo_AllowedVault proto.InternalMessageInfo + +func (m *AllowedVault) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *AllowedVault) GetVaultStrategy() StrategyType { + if m != nil { + return m.VaultStrategy + } + return STRATEGY_TYPE_UNKNOWN +} + +// VaultRecord is the state of a vault and is used to store the state of a +// vault. +type VaultRecord struct { + // Denom is the only supported denomination of the vault for deposits and + // withdrawals. + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + // TotalSupply is the total supply of the vault, denominated **only** in the + // user deposit/withdrawal denom, must be the same as the Denom field. + TotalSupply types.Coin `protobuf:"bytes,2,opt,name=total_supply,json=totalSupply,proto3" json:"total_supply"` +} + +func (m *VaultRecord) Reset() { *m = VaultRecord{} } +func (m *VaultRecord) String() string { return proto.CompactTextString(m) } +func (*VaultRecord) ProtoMessage() {} +func (*VaultRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_884eb89509fbdc04, []int{1} +} +func (m *VaultRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *VaultRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_VaultRecord.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 *VaultRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_VaultRecord.Merge(m, src) +} +func (m *VaultRecord) XXX_Size() int { + return m.Size() +} +func (m *VaultRecord) XXX_DiscardUnknown() { + xxx_messageInfo_VaultRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_VaultRecord proto.InternalMessageInfo + +func (m *VaultRecord) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *VaultRecord) GetTotalSupply() types.Coin { + if m != nil { + return m.TotalSupply + } + return types.Coin{} +} + +// VaultShareRecord defines the shares owned by a depositor and vault. +type VaultShareRecord struct { + // depositor represents the owner of the shares + Depositor github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=depositor,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"depositor,omitempty"` + // amount_supplied represents the total amount a depositor has supplied to the + // vault. The vault is determined by the coin denom. + AmountSupplied types.Coin `protobuf:"bytes,2,opt,name=amount_supplied,json=amountSupplied,proto3" json:"amount_supplied"` +} + +func (m *VaultShareRecord) Reset() { *m = VaultShareRecord{} } +func (m *VaultShareRecord) String() string { return proto.CompactTextString(m) } +func (*VaultShareRecord) ProtoMessage() {} +func (*VaultShareRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_884eb89509fbdc04, []int{2} +} +func (m *VaultShareRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *VaultShareRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_VaultShareRecord.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 *VaultShareRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_VaultShareRecord.Merge(m, src) +} +func (m *VaultShareRecord) XXX_Size() int { + return m.Size() +} +func (m *VaultShareRecord) XXX_DiscardUnknown() { + xxx_messageInfo_VaultShareRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_VaultShareRecord proto.InternalMessageInfo + +func (m *VaultShareRecord) GetDepositor() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.Depositor + } + return nil +} + +func (m *VaultShareRecord) GetAmountSupplied() types.Coin { + if m != nil { + return m.AmountSupplied + } + return types.Coin{} +} + +func init() { + proto.RegisterType((*AllowedVault)(nil), "kava.earn.v1beta1.AllowedVault") + proto.RegisterType((*VaultRecord)(nil), "kava.earn.v1beta1.VaultRecord") + proto.RegisterType((*VaultShareRecord)(nil), "kava.earn.v1beta1.VaultShareRecord") +} + +func init() { proto.RegisterFile("kava/earn/v1beta1/vault.proto", fileDescriptor_884eb89509fbdc04) } + +var fileDescriptor_884eb89509fbdc04 = []byte{ + // 398 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x51, 0xcd, 0xae, 0xd2, 0x40, + 0x14, 0x6e, 0x8d, 0x9a, 0x30, 0x20, 0x6a, 0x65, 0x01, 0x24, 0x16, 0xc2, 0xc2, 0xb0, 0xe9, 0x34, + 0xe0, 0x0b, 0x48, 0x4d, 0x0c, 0xeb, 0xd6, 0xb8, 0x70, 0x43, 0xa6, 0x9d, 0xb1, 0x34, 0xb4, 0x3d, + 0x4d, 0x67, 0x8a, 0xf6, 0x2d, 0x7c, 0x18, 0x1f, 0xc1, 0x05, 0x4b, 0xe2, 0xca, 0x15, 0xb9, 0x81, + 0xb7, 0xb8, 0xab, 0x9b, 0xce, 0x0c, 0xdc, 0x9b, 0x90, 0x9b, 0xdc, 0xd5, 0xfc, 0x7c, 0xe7, 0x3b, + 0xdf, 0xf7, 0x9d, 0x83, 0xde, 0x6f, 0xc8, 0x96, 0xb8, 0x8c, 0x94, 0xb9, 0xbb, 0x9d, 0x85, 0x4c, + 0x90, 0x99, 0xbb, 0x25, 0x55, 0x2a, 0x70, 0x51, 0x82, 0x00, 0xeb, 0x6d, 0x03, 0xe3, 0x06, 0xc6, + 0x1a, 0x1e, 0xf6, 0x62, 0x88, 0x41, 0xa2, 0x6e, 0x73, 0x53, 0x85, 0x43, 0x3b, 0x02, 0x9e, 0x01, + 0x77, 0x43, 0xc2, 0xd9, 0xa5, 0x53, 0x04, 0x49, 0xae, 0xf1, 0x81, 0xc2, 0x57, 0x8a, 0xa8, 0x1e, + 0x1a, 0x1a, 0x5f, 0x5b, 0xe0, 0xa2, 0x24, 0x82, 0xc5, 0xb5, 0xaa, 0x98, 0xa4, 0xa8, 0xb3, 0x48, + 0x53, 0xf8, 0xc9, 0xe8, 0xb7, 0xc6, 0x9b, 0xd5, 0x43, 0x2f, 0x28, 0xcb, 0x21, 0xeb, 0x9b, 0x63, + 0x73, 0xda, 0xf2, 0xd5, 0xc3, 0xfa, 0x82, 0xba, 0xd2, 0xfa, 0xea, 0xcc, 0xee, 0x3f, 0x1b, 0x9b, + 0xd3, 0xee, 0x7c, 0x84, 0xaf, 0x42, 0xe0, 0x40, 0x97, 0x7c, 0xad, 0x0b, 0xe6, 0xbf, 0x92, 0xb4, + 0xf3, 0xd7, 0x24, 0x46, 0x6d, 0x29, 0xe3, 0xb3, 0x08, 0x4a, 0xfa, 0x88, 0x98, 0x87, 0x3a, 0x02, + 0x04, 0x49, 0x57, 0xbc, 0x2a, 0x8a, 0x54, 0x49, 0xb5, 0xe7, 0x03, 0xac, 0x93, 0x35, 0x63, 0xb8, + 0x88, 0x7d, 0x86, 0x24, 0xf7, 0x9e, 0xef, 0x0e, 0x23, 0xc3, 0x6f, 0x4b, 0x52, 0x20, 0x39, 0x93, + 0xbf, 0x26, 0x7a, 0x23, 0x95, 0x82, 0x35, 0x29, 0x99, 0x96, 0xfb, 0x81, 0x5a, 0x94, 0x15, 0xc0, + 0x13, 0x01, 0xa5, 0x94, 0xec, 0x78, 0xcb, 0xdb, 0xc3, 0xc8, 0x89, 0x13, 0xb1, 0xae, 0x42, 0x1c, + 0x41, 0xa6, 0xa7, 0xa7, 0x0f, 0x87, 0xd3, 0x8d, 0x2b, 0xea, 0x82, 0x71, 0xbc, 0x88, 0xa2, 0x05, + 0xa5, 0x25, 0xe3, 0xfc, 0xdf, 0x1f, 0xe7, 0x9d, 0x76, 0xa2, 0x7f, 0xbc, 0x5a, 0x30, 0xee, 0xdf, + 0xb7, 0xb6, 0x96, 0xe8, 0x35, 0xc9, 0xa0, 0xca, 0x85, 0x4a, 0x90, 0x30, 0xfa, 0xd4, 0x0c, 0x5d, + 0xc5, 0x0b, 0x34, 0xcd, 0xfb, 0xb4, 0x3b, 0xda, 0xe6, 0xfe, 0x68, 0x9b, 0x37, 0x47, 0xdb, 0xfc, + 0x7d, 0xb2, 0x8d, 0xfd, 0xc9, 0x36, 0xfe, 0x9f, 0x6c, 0xe3, 0xfb, 0x87, 0x07, 0xa6, 0x9b, 0x1d, + 0x38, 0x29, 0x09, 0xb9, 0xbc, 0xb9, 0xbf, 0xd4, 0xc2, 0xa5, 0xf1, 0xf0, 0xa5, 0x5c, 0xf3, 0xc7, + 0xbb, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc6, 0x8b, 0xa9, 0xd7, 0x8d, 0x02, 0x00, 0x00, +} + +func (m *AllowedVault) 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 *AllowedVault) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AllowedVault) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.VaultStrategy != 0 { + i = encodeVarintVault(dAtA, i, uint64(m.VaultStrategy)) + i-- + dAtA[i] = 0x10 + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintVault(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *VaultRecord) 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 *VaultRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *VaultRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.TotalSupply.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintVault(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintVault(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *VaultShareRecord) 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 *VaultShareRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *VaultShareRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.AmountSupplied.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintVault(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Depositor) > 0 { + i -= len(m.Depositor) + copy(dAtA[i:], m.Depositor) + i = encodeVarintVault(dAtA, i, uint64(len(m.Depositor))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintVault(dAtA []byte, offset int, v uint64) int { + offset -= sovVault(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *AllowedVault) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovVault(uint64(l)) + } + if m.VaultStrategy != 0 { + n += 1 + sovVault(uint64(m.VaultStrategy)) + } + return n +} + +func (m *VaultRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovVault(uint64(l)) + } + l = m.TotalSupply.Size() + n += 1 + l + sovVault(uint64(l)) + return n +} + +func (m *VaultShareRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Depositor) + if l > 0 { + n += 1 + l + sovVault(uint64(l)) + } + l = m.AmountSupplied.Size() + n += 1 + l + sovVault(uint64(l)) + return n +} + +func sovVault(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozVault(x uint64) (n int) { + return sovVault(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *AllowedVault) 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 ErrIntOverflowVault + } + 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: AllowedVault: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AllowedVault: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVault + } + 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 ErrInvalidLengthVault + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthVault + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field VaultStrategy", wireType) + } + m.VaultStrategy = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVault + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.VaultStrategy |= StrategyType(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipVault(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthVault + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *VaultRecord) 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 ErrIntOverflowVault + } + 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: VaultRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: VaultRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVault + } + 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 ErrInvalidLengthVault + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthVault + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalSupply", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVault + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthVault + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthVault + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TotalSupply.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipVault(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthVault + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *VaultShareRecord) 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 ErrIntOverflowVault + } + 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: VaultShareRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: VaultShareRecord: 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 byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVault + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthVault + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthVault + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Depositor = append(m.Depositor[:0], dAtA[iNdEx:postIndex]...) + if m.Depositor == nil { + m.Depositor = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AmountSupplied", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVault + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthVault + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthVault + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.AmountSupplied.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipVault(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthVault + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipVault(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, ErrIntOverflowVault + } + 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, ErrIntOverflowVault + } + 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, ErrIntOverflowVault + } + 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, ErrInvalidLengthVault + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupVault + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthVault + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthVault = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowVault = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupVault = fmt.Errorf("proto: unexpected end of group") +)