From b38cd850df9939e2c91a7382a39ce07ccec7552f Mon Sep 17 00:00:00 2001 From: Derrick Lee Date: Mon, 12 Sep 2022 09:43:59 -0700 Subject: [PATCH] Update Earn requests and responses to use multiple strategies (#1284) * Add multiple strategies to params, queries, txs * Check deposit/withdraw strategy if supported by vault * Add note for deposit strategy * Add strategy type to messages * Update swagger docs, ignore ethermint proto linting errors * Update strategy test, move single strategy support to strategytype * Simplify NewStrategyTypeFromString --- client/docs/swagger-ui/swagger.yaml | 438 ++++++++++++++++------------ docs/core/proto-docs.md | 6 +- proto/kava/earn/v1beta1/query.proto | 2 +- proto/kava/earn/v1beta1/tx.proto | 7 + proto/kava/earn/v1beta1/vault.proto | 3 +- third_party/proto/buf.yaml | 1 + x/earn/client/cli/tx.go | 26 +- x/earn/keeper/deposit.go | 18 +- x/earn/keeper/deposit_test.go | 22 +- x/earn/keeper/grpc_query.go | 8 +- x/earn/keeper/grpc_query_test.go | 42 +-- x/earn/keeper/msg_server.go | 4 +- x/earn/keeper/msg_server_test.go | 6 +- x/earn/keeper/strategy_hard_test.go | 60 ++-- x/earn/keeper/vault.go | 2 +- x/earn/keeper/vault_test.go | 19 +- x/earn/keeper/withdraw.go | 14 +- x/earn/keeper/withdraw_test.go | 40 ++- x/earn/testutil/suite.go | 2 - x/earn/types/msg.go | 18 +- x/earn/types/query.pb.go | 204 ++++++++----- x/earn/types/strategy.go | 62 ++++ x/earn/types/strategy_test.go | 120 ++++++++ x/earn/types/tx.pb.go | 114 ++++++-- x/earn/types/vault.go | 24 +- x/earn/types/vault.pb.go | 170 +++++++---- x/earn/types/vault_test.go | 26 +- 27 files changed, 999 insertions(+), 459 deletions(-) create mode 100644 x/earn/types/strategy.go create mode 100644 x/earn/types/strategy_test.go diff --git a/client/docs/swagger-ui/swagger.yaml b/client/docs/swagger-ui/swagger.yaml index 78fce0c7..dafdd2f0 100644 --- a/client/docs/swagger-ui/swagger.yaml +++ b/client/docs/swagger-ui/swagger.yaml @@ -6978,22 +6978,48 @@ paths: depositor: type: string description: depositor represents the owner of the deposit. - denom: - type: string - description: denom represents the vault denom the deposit is for. - account_supplied: - type: string + shares: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + VaultShare defines shares of a vault owned by a + depositor. description: >- - AccountSupplied represents the amount of denom supplied - to the vault. - account_value: - type: string + Shares represent the issued shares from their + corresponding vaults. + value: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an + amount. + + + NOTE: The amount field is an Int which implements the + custom method + + signatures required by gogoproto. description: >- - AccountValue represents the coin value of the - depositor's share of the vault. - description: >- - DepositResponse defines a single deposit query response - type. + Value represents the total accumulated value of denom + coins supplied to + + vaults. This may be greater than or equal to + amount_supplied depending on + + the strategy. + description: DepositResponse defines a deposit query response type. title: >- deposits returns the deposits matching the requested parameters @@ -7135,14 +7161,25 @@ paths: description: >- Denom is the only supported denomination of the vault for deposits and withdrawals. - vault_strategy: + strategies: + type: array + items: + type: string + enum: + - STRATEGY_TYPE_UNSPECIFIED + - STRATEGY_TYPE_HARD + - STRATEGY_TYPE_SAVINGS + default: STRATEGY_TYPE_UNSPECIFIED + description: >- + StrategyType is the type of strategy that a vault + uses to optimize yields. + + - STRATEGY_TYPE_UNSPECIFIED: STRATEGY_TYPE_UNSPECIFIED represents an unspecified or invalid strategy type. + - STRATEGY_TYPE_HARD: STRATEGY_TYPE_HARD represents the strategy that deposits assets in the Hard + module. + - STRATEGY_TYPE_SAVINGS: STRATEGY_TYPE_SAVINGS represents the strategy that deposits assets in the + Savings module. description: VaultStrategy is the strategy used for this vault. - type: string - enum: - - STRATEGY_TYPE_UNSPECIFIED - - STRATEGY_TYPE_HARD - - STRATEGY_TYPE_SAVINGS - default: STRATEGY_TYPE_UNSPECIFIED description: >- AllowedVault is a vault that is allowed to be created. These can be @@ -7176,69 +7213,7 @@ paths: format: byte tags: - Earn - /kava/earn/v1beta1/total-deposited/{denom}: - get: - summary: TotalDeposited queries total deposited amount for each vault. - operationId: EarnTotalDeposited - responses: - '200': - description: A successful response. - schema: - type: object - properties: - supplied_coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the custom - method - - signatures required by gogoproto. - description: >- - QueryTotalDepositedResponse is the response type for the - Query/TotalDeposited RPC method. - default: - description: An unexpected error response - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - value: - type: string - format: byte - parameters: - - name: denom - description: >- - denom represents the vault denom to query total deposited amount - for. - in: path - required: true - type: string - tags: - - Earn - /kava/earn/v1beta1/vaults: + /kava/earn/v1beta1/vaults/{denom}: get: summary: Vaults queries vaults based on vault denom operationId: EarnVaults @@ -7256,19 +7231,30 @@ paths: denom: type: string title: denom represents the denom of the vault - vault_strategy: + strategies: + type: array + items: + type: string + enum: + - STRATEGY_TYPE_UNSPECIFIED + - STRATEGY_TYPE_HARD + - STRATEGY_TYPE_SAVINGS + default: STRATEGY_TYPE_UNSPECIFIED + description: >- + StrategyType is the type of strategy that a vault uses + to optimize yields. + + - STRATEGY_TYPE_UNSPECIFIED: STRATEGY_TYPE_UNSPECIFIED represents an unspecified or invalid strategy type. + - STRATEGY_TYPE_HARD: STRATEGY_TYPE_HARD represents the strategy that deposits assets in the Hard + module. + - STRATEGY_TYPE_SAVINGS: STRATEGY_TYPE_SAVINGS represents the strategy that deposits assets in the + Savings module. description: VaultStrategy is the strategy used for this vault. - type: string - enum: - - STRATEGY_TYPE_UNSPECIFIED - - STRATEGY_TYPE_HARD - - STRATEGY_TYPE_SAVINGS - default: STRATEGY_TYPE_UNSPECIFIED - total_supplied: + total_shares: type: string description: >- - TotalSupplied is the total amount of denom coins - supplied to the vault. + TotalShares is the total amount of shares issued to + depositors. total_value: type: string description: >- @@ -7305,9 +7291,9 @@ paths: format: byte parameters: - name: denom - description: vault filters vault by denom. - in: query - required: false + description: vault filters vault by denom + in: path + required: true type: string tags: - Earn @@ -54207,14 +54193,25 @@ definitions: description: >- Denom is the only supported denomination of the vault for deposits and withdrawals. - vault_strategy: + strategies: + type: array + items: + type: string + enum: + - STRATEGY_TYPE_UNSPECIFIED + - STRATEGY_TYPE_HARD + - STRATEGY_TYPE_SAVINGS + default: STRATEGY_TYPE_UNSPECIFIED + description: >- + StrategyType is the type of strategy that a vault uses to optimize + yields. + + - STRATEGY_TYPE_UNSPECIFIED: STRATEGY_TYPE_UNSPECIFIED represents an unspecified or invalid strategy type. + - STRATEGY_TYPE_HARD: STRATEGY_TYPE_HARD represents the strategy that deposits assets in the Hard + module. + - STRATEGY_TYPE_SAVINGS: STRATEGY_TYPE_SAVINGS represents the strategy that deposits assets in the + Savings module. description: VaultStrategy is the strategy used for this vault. - type: string - enum: - - STRATEGY_TYPE_UNSPECIFIED - - STRATEGY_TYPE_HARD - - STRATEGY_TYPE_SAVINGS - default: STRATEGY_TYPE_UNSPECIFIED description: |- AllowedVault is a vault that is allowed to be created. These can be modified via parameter governance. @@ -54224,18 +54221,40 @@ definitions: depositor: type: string description: depositor represents the owner of the deposit. - denom: - type: string - description: denom represents the vault denom the deposit is for. - account_supplied: - type: string - description: AccountSupplied represents the amount of denom supplied to the vault. - account_value: - type: string + shares: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: VaultShare defines shares of a vault owned by a depositor. + description: Shares represent the issued shares from their corresponding vaults. + value: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: |- + Coin defines a token with a denomination and an amount. + + NOTE: The amount field is an Int which implements the custom method + signatures required by gogoproto. description: >- - AccountValue represents the coin value of the depositor's share of the - vault. - description: DepositResponse defines a single deposit query response type. + Value represents the total accumulated value of denom coins supplied + to + + vaults. This may be greater than or equal to amount_supplied depending + on + + the strategy. + description: DepositResponse defines a deposit query response type. kava.earn.v1beta1.Params: type: object properties: @@ -54249,14 +54268,25 @@ definitions: description: >- Denom is the only supported denomination of the vault for deposits and withdrawals. - vault_strategy: + strategies: + type: array + items: + type: string + enum: + - STRATEGY_TYPE_UNSPECIFIED + - STRATEGY_TYPE_HARD + - STRATEGY_TYPE_SAVINGS + default: STRATEGY_TYPE_UNSPECIFIED + description: >- + StrategyType is the type of strategy that a vault uses to + optimize yields. + + - STRATEGY_TYPE_UNSPECIFIED: STRATEGY_TYPE_UNSPECIFIED represents an unspecified or invalid strategy type. + - STRATEGY_TYPE_HARD: STRATEGY_TYPE_HARD represents the strategy that deposits assets in the Hard + module. + - STRATEGY_TYPE_SAVINGS: STRATEGY_TYPE_SAVINGS represents the strategy that deposits assets in the + Savings module. description: VaultStrategy is the strategy used for this vault. - type: string - enum: - - STRATEGY_TYPE_UNSPECIFIED - - STRATEGY_TYPE_HARD - - STRATEGY_TYPE_SAVINGS - default: STRATEGY_TYPE_UNSPECIFIED description: |- AllowedVault is a vault that is allowed to be created. These can be modified via parameter governance. @@ -54272,20 +54302,45 @@ definitions: depositor: type: string description: depositor represents the owner of the deposit. - denom: - type: string - description: denom represents the vault denom the deposit is for. - account_supplied: - type: string + shares: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: VaultShare defines shares of a vault owned by a depositor. description: >- - AccountSupplied represents the amount of denom supplied to the - vault. - account_value: - type: string + Shares represent the issued shares from their corresponding + vaults. + value: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. + + + NOTE: The amount field is an Int which implements the custom + method + + signatures required by gogoproto. description: >- - AccountValue represents the coin value of the depositor's share - of the vault. - description: DepositResponse defines a single deposit query response type. + Value represents the total accumulated value of denom coins + supplied to + + vaults. This may be greater than or equal to amount_supplied + depending on + + the strategy. + description: DepositResponse defines a deposit query response type. title: deposits returns the deposits matching the requested parameters pagination: description: pagination defines the pagination in the response. @@ -54325,14 +54380,25 @@ definitions: description: >- Denom is the only supported denomination of the vault for deposits and withdrawals. - vault_strategy: + strategies: + type: array + items: + type: string + enum: + - STRATEGY_TYPE_UNSPECIFIED + - STRATEGY_TYPE_HARD + - STRATEGY_TYPE_SAVINGS + default: STRATEGY_TYPE_UNSPECIFIED + description: >- + StrategyType is the type of strategy that a vault uses to + optimize yields. + + - STRATEGY_TYPE_UNSPECIFIED: STRATEGY_TYPE_UNSPECIFIED represents an unspecified or invalid strategy type. + - STRATEGY_TYPE_HARD: STRATEGY_TYPE_HARD represents the strategy that deposits assets in the Hard + module. + - STRATEGY_TYPE_SAVINGS: STRATEGY_TYPE_SAVINGS represents the strategy that deposits assets in the + Savings module. description: VaultStrategy is the strategy used for this vault. - type: string - enum: - - STRATEGY_TYPE_UNSPECIFIED - - STRATEGY_TYPE_HARD - - STRATEGY_TYPE_SAVINGS - default: STRATEGY_TYPE_UNSPECIFIED description: >- AllowedVault is a vault that is allowed to be created. These can be @@ -54342,26 +54408,6 @@ definitions: description: >- QueryParamsResponse defines the response type for querying x/earn parameters. - kava.earn.v1beta1.QueryTotalDepositedResponse: - type: object - properties: - supplied_coins: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: |- - Coin defines a token with a denomination and an amount. - - NOTE: The amount field is an Int which implements the custom method - signatures required by gogoproto. - description: >- - QueryTotalDepositedResponse is the response type for the - Query/TotalDeposited RPC method. kava.earn.v1beta1.QueryVaultsResponse: type: object properties: @@ -54373,19 +54419,28 @@ definitions: denom: type: string title: denom represents the denom of the vault - vault_strategy: + strategies: + type: array + items: + type: string + enum: + - STRATEGY_TYPE_UNSPECIFIED + - STRATEGY_TYPE_HARD + - STRATEGY_TYPE_SAVINGS + default: STRATEGY_TYPE_UNSPECIFIED + description: >- + StrategyType is the type of strategy that a vault uses to + optimize yields. + + - STRATEGY_TYPE_UNSPECIFIED: STRATEGY_TYPE_UNSPECIFIED represents an unspecified or invalid strategy type. + - STRATEGY_TYPE_HARD: STRATEGY_TYPE_HARD represents the strategy that deposits assets in the Hard + module. + - STRATEGY_TYPE_SAVINGS: STRATEGY_TYPE_SAVINGS represents the strategy that deposits assets in the + Savings module. description: VaultStrategy is the strategy used for this vault. + total_shares: type: string - enum: - - STRATEGY_TYPE_UNSPECIFIED - - STRATEGY_TYPE_HARD - - STRATEGY_TYPE_SAVINGS - default: STRATEGY_TYPE_UNSPECIFIED - total_supplied: - type: string - description: >- - TotalSupplied is the total amount of denom coins supplied to the - vault. + description: TotalShares is the total amount of shares issued to depositors. total_value: type: string description: >- @@ -54417,19 +54472,28 @@ definitions: denom: type: string title: denom represents the denom of the vault - vault_strategy: + strategies: + type: array + items: + type: string + enum: + - STRATEGY_TYPE_UNSPECIFIED + - STRATEGY_TYPE_HARD + - STRATEGY_TYPE_SAVINGS + default: STRATEGY_TYPE_UNSPECIFIED + description: >- + StrategyType is the type of strategy that a vault uses to optimize + yields. + + - STRATEGY_TYPE_UNSPECIFIED: STRATEGY_TYPE_UNSPECIFIED represents an unspecified or invalid strategy type. + - STRATEGY_TYPE_HARD: STRATEGY_TYPE_HARD represents the strategy that deposits assets in the Hard + module. + - STRATEGY_TYPE_SAVINGS: STRATEGY_TYPE_SAVINGS represents the strategy that deposits assets in the + Savings module. description: VaultStrategy is the strategy used for this vault. + total_shares: type: string - enum: - - STRATEGY_TYPE_UNSPECIFIED - - STRATEGY_TYPE_HARD - - STRATEGY_TYPE_SAVINGS - default: STRATEGY_TYPE_UNSPECIFIED - total_supplied: - type: string - description: >- - TotalSupplied is the total amount of denom coins supplied to the - vault. + description: TotalShares is the total amount of shares issued to depositors. total_value: type: string description: >- @@ -54438,6 +54502,14 @@ definitions: vault were to be liquidated. description: VaultResponse is the response type for a vault. + kava.earn.v1beta1.VaultShare: + type: object + properties: + denom: + type: string + amount: + type: string + description: VaultShare defines shares of a vault owned by a depositor. kava.hard.v1beta1.BorrowInterestFactorResponse: type: object properties: diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index 3593ff7d..777b52fd 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -2806,7 +2806,7 @@ 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 strategy used for this vault. | +| `strategies` | [StrategyType](#kava.earn.v1beta1.StrategyType) | repeated | VaultStrategy is the strategy used for this vault. | @@ -3054,7 +3054,7 @@ VaultResponse is the response type for a vault. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `denom` | [string](#string) | | denom represents the denom of the vault | -| `vault_strategy` | [StrategyType](#kava.earn.v1beta1.StrategyType) | | VaultStrategy is the strategy used for this vault. | +| `strategies` | [StrategyType](#kava.earn.v1beta1.StrategyType) | repeated | VaultStrategy is the strategy used for this vault. | | `total_shares` | [string](#string) | | TotalShares is the total amount of shares issued to depositors. | | `total_value` | [string](#string) | | TotalValue is the total value of denom coins supplied to the vault if the vault were to be liquidated. | @@ -3101,6 +3101,7 @@ MsgDeposit represents a message for depositing assedts into a vault | ----- | ---- | ----- | ----------- | | `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. | +| `strategy` | [StrategyType](#kava.earn.v1beta1.StrategyType) | | Strategy is the vault strategy to use. | @@ -3132,6 +3133,7 @@ MsgWithdraw represents a message for withdrawing liquidity from a vault | ----- | ---- | ----- | ----------- | | `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. | +| `strategy` | [StrategyType](#kava.earn.v1beta1.StrategyType) | | Strategy is the vault strategy to use. | diff --git a/proto/kava/earn/v1beta1/query.proto b/proto/kava/earn/v1beta1/query.proto index e13f0be1..abd22f72 100644 --- a/proto/kava/earn/v1beta1/query.proto +++ b/proto/kava/earn/v1beta1/query.proto @@ -58,7 +58,7 @@ message VaultResponse { string denom = 1; // VaultStrategy is the strategy used for this vault. - StrategyType vault_strategy = 2; + repeated StrategyType strategies = 2 [(gogoproto.castrepeated) = "StrategyTypes"]; // TotalShares is the total amount of shares issued to depositors. string total_shares = 3; diff --git a/proto/kava/earn/v1beta1/tx.proto b/proto/kava/earn/v1beta1/tx.proto index abafa094..fc4eee4c 100644 --- a/proto/kava/earn/v1beta1/tx.proto +++ b/proto/kava/earn/v1beta1/tx.proto @@ -4,6 +4,7 @@ package kava.earn.v1beta1; import "cosmos_proto/cosmos.proto"; import "cosmos/base/v1beta1/coin.proto"; import "gogoproto/gogo.proto"; +import "kava/earn/v1beta1/strategy.proto"; import "kava/earn/v1beta1/vault.proto"; option go_package = "github.com/kava-labs/kava/x/earn/types"; @@ -25,6 +26,9 @@ message MsgDeposit { // 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]; + + // Strategy is the vault strategy to use. + StrategyType strategy = 3; } // MsgDepositResponse defines the Msg/Deposit response type. @@ -42,6 +46,9 @@ message MsgWithdraw { // 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]; + + // Strategy is the vault strategy to use. + StrategyType strategy = 3; } // MsgWithdrawResponse defines the Msg/Withdraw response type. diff --git a/proto/kava/earn/v1beta1/vault.proto b/proto/kava/earn/v1beta1/vault.proto index 79eed639..7baf0276 100644 --- a/proto/kava/earn/v1beta1/vault.proto +++ b/proto/kava/earn/v1beta1/vault.proto @@ -4,7 +4,6 @@ package kava.earn.v1beta1; option go_package = "github.com/kava-labs/kava/x/earn/types"; import "cosmos_proto/cosmos.proto"; -import "cosmos/base/v1beta1/coin.proto"; import "gogoproto/gogo.proto"; import "kava/earn/v1beta1/strategy.proto"; @@ -15,7 +14,7 @@ message AllowedVault { string denom = 1; // VaultStrategy is the strategy used for this vault. - StrategyType vault_strategy = 2; + repeated StrategyType strategies = 2 [(gogoproto.castrepeated) = "StrategyTypes"]; } // VaultRecord is the state of a vault. diff --git a/third_party/proto/buf.yaml b/third_party/proto/buf.yaml index c3ce40db..9b96f3ed 100644 --- a/third_party/proto/buf.yaml +++ b/third_party/proto/buf.yaml @@ -4,6 +4,7 @@ lint: ignore: - cosmos - cosmos_proto + - ethermint - gogoproto - google - ibc diff --git a/x/earn/client/cli/tx.go b/x/earn/client/cli/tx.go index af42a25d..681f5053 100644 --- a/x/earn/client/cli/tx.go +++ b/x/earn/client/cli/tx.go @@ -40,13 +40,13 @@ func GetTxCmd() *cobra.Command { func getCmdDeposit() *cobra.Command { return &cobra.Command{ - Use: "deposit [amount]", + Use: "deposit [amount] [strategy]", Short: "deposit coins to an earn vault", Example: fmt.Sprintf( - `%s tx %s deposit 10000000ukava --from `, + `%s tx %s deposit 10000000ukava hard --from `, version.AppName, types.ModuleName, ), - Args: cobra.ExactArgs(1), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) if err != nil { @@ -58,8 +58,13 @@ func getCmdDeposit() *cobra.Command { return err } + strategy := types.NewStrategyTypeFromString(args[1]) + if !strategy.IsValid() { + return fmt.Errorf("invalid strategy type: %s", args[1]) + } + signer := clientCtx.GetFromAddress() - msg := types.NewMsgDeposit(signer.String(), amount) + msg := types.NewMsgDeposit(signer.String(), amount, strategy) if err := msg.ValidateBasic(); err != nil { return err } @@ -71,13 +76,13 @@ func getCmdDeposit() *cobra.Command { func getCmdWithdraw() *cobra.Command { return &cobra.Command{ - Use: "withdraw [amount]", + Use: "withdraw [amount] [strategy]", Short: "withdraw coins from an earn vault", Example: fmt.Sprintf( - `%s tx %s withdraw 10000000ukava --from `, + `%s tx %s withdraw 10000000ukava hard --from `, version.AppName, types.ModuleName, ), - Args: cobra.ExactArgs(1), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) if err != nil { @@ -89,8 +94,13 @@ func getCmdWithdraw() *cobra.Command { return err } + strategy := types.NewStrategyTypeFromString(args[1]) + if !strategy.IsValid() { + return fmt.Errorf("invalid strategy type: %s", args[1]) + } + fromAddr := clientCtx.GetFromAddress() - msg := types.NewMsgWithdraw(fromAddr.String(), amount) + msg := types.NewMsgWithdraw(fromAddr.String(), amount, strategy) if err := msg.ValidateBasic(); err != nil { return err } diff --git a/x/earn/keeper/deposit.go b/x/earn/keeper/deposit.go index 304febc4..b577608b 100644 --- a/x/earn/keeper/deposit.go +++ b/x/earn/keeper/deposit.go @@ -9,7 +9,12 @@ import ( // 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 { +func (k *Keeper) Deposit( + ctx sdk.Context, + depositor sdk.AccAddress, + amount sdk.Coin, + depositStrategy types.StrategyType, +) error { // Get AllowedVault, if not found (not a valid vault), return error allowedVault, found := k.GetAllowedVault(ctx, amount.Denom) if !found { @@ -20,6 +25,11 @@ func (k *Keeper) Deposit(ctx sdk.Context, depositor sdk.AccAddress, amount sdk.C return types.ErrInsufficientAmount } + // Check if deposit strategy is supported by vault + if !allowedVault.IsStrategyAllowed(depositStrategy) { + return types.ErrInvalidVaultStrategy + } + // Check if VaultRecord exists, create if not exist vaultRecord, found := k.GetVaultRecord(ctx, amount.Denom) if !found { @@ -28,7 +38,11 @@ func (k *Keeper) Deposit(ctx sdk.Context, depositor sdk.AccAddress, amount sdk.C } // Get the strategy for the vault - strategy, err := k.GetStrategy(allowedVault.VaultStrategy) + // NOTE: Currently always uses the first one, AllowedVaults are currently + // only valid with 1 and only 1 strategy so this is safe. + // If/When multiple strategies are supported and users can specify specific + // strategies, shares should be issued per-strategy instead of per-vault. + strategy, err := k.GetStrategy(allowedVault.Strategies[0]) if err != nil { return err } diff --git a/x/earn/keeper/deposit_test.go b/x/earn/keeper/deposit_test.go index 7beae143..7405b2be 100644 --- a/x/earn/keeper/deposit_test.go +++ b/x/earn/keeper/deposit_test.go @@ -42,7 +42,7 @@ func (suite *depositTestSuite) TestDeposit_Balances() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) suite.AccountBalanceEqual( @@ -65,7 +65,7 @@ func (suite *depositTestSuite) TestDeposit_Exceed() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().Error(err) suite.Require().ErrorIs(err, sdkerrors.ErrInsufficientFunds) @@ -90,7 +90,7 @@ func (suite *depositTestSuite) TestDeposit_Zero() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().Error(err) suite.Require().ErrorIs(err, types.ErrInsufficientAmount) @@ -115,7 +115,7 @@ func (suite *depositTestSuite) TestDeposit_InvalidVault() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().Error(err) suite.Require().ErrorIs(err, types.ErrInvalidVaultDenom) @@ -130,3 +130,17 @@ func (suite *depositTestSuite) TestDeposit_InvalidVault() { sdk.NewCoins(), ) } + +func (suite *depositTestSuite) TestDeposit_InvalidStrategy() { + vaultDenom := "usdx" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + depositAmount := sdk.NewInt64Coin(vaultDenom, 1001) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_HARD) + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrInvalidVaultStrategy) +} diff --git a/x/earn/keeper/grpc_query.go b/x/earn/keeper/grpc_query.go index 1c9c695d..38017e8f 100644 --- a/x/earn/keeper/grpc_query.go +++ b/x/earn/keeper/grpc_query.go @@ -81,10 +81,10 @@ func (s queryServer) Vaults( } vaults = append(vaults, types.VaultResponse{ - Denom: allowedVault.Denom, - VaultStrategy: allowedVault.VaultStrategy, - TotalShares: vaultTotalShares.Amount.String(), - TotalValue: totalValue.Amount, + Denom: allowedVault.Denom, + Strategies: allowedVault.Strategies, + TotalShares: vaultTotalShares.Amount.String(), + TotalValue: totalValue.Amount, }) } diff --git a/x/earn/keeper/grpc_query_test.go b/x/earn/keeper/grpc_query_test.go index 65b01a8f..86f98277 100644 --- a/x/earn/keeper/grpc_query_test.go +++ b/x/earn/keeper/grpc_query_test.go @@ -68,10 +68,10 @@ func (suite *grpcQueryTestSuite) TestVaults_ZeroSupply() { suite.Require().Len(res.Vaults, 1) suite.Require().Equal( types.VaultResponse{ - Denom: "usdx", - VaultStrategy: types.STRATEGY_TYPE_HARD, - TotalShares: sdk.NewDec(0).String(), - TotalValue: sdk.NewInt(0), + Denom: "usdx", + Strategies: []types.StrategyType{types.STRATEGY_TYPE_HARD}, + TotalShares: sdk.NewDec(0).String(), + TotalValue: sdk.NewInt(0), }, res.Vaults[0], ) @@ -84,16 +84,16 @@ func (suite *grpcQueryTestSuite) TestVaults_ZeroSupply() { suite.Require().ElementsMatch( []types.VaultResponse{ { - Denom: "usdx", - VaultStrategy: types.STRATEGY_TYPE_HARD, - TotalShares: sdk.NewDec(0).String(), - TotalValue: sdk.NewInt(0), + Denom: "usdx", + Strategies: []types.StrategyType{types.STRATEGY_TYPE_HARD}, + TotalShares: sdk.NewDec(0).String(), + TotalValue: sdk.NewInt(0), }, { - Denom: "busd", - VaultStrategy: types.STRATEGY_TYPE_HARD, - TotalShares: sdk.NewDec(0).String(), - TotalValue: sdk.NewInt(0), + Denom: "busd", + Strategies: []types.StrategyType{types.STRATEGY_TYPE_HARD}, + TotalShares: sdk.NewDec(0).String(), + TotalValue: sdk.NewInt(0), }, }, res.Vaults, @@ -111,7 +111,7 @@ func (suite *grpcQueryTestSuite) TestVaults_WithSupply() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) res, err := suite.queryClient.Vaults(context.Background(), types.NewQueryVaultsRequest("usdx")) @@ -119,10 +119,10 @@ func (suite *grpcQueryTestSuite) TestVaults_WithSupply() { suite.Require().Len(res.Vaults, 1) suite.Require().Equal( types.VaultResponse{ - Denom: "usdx", - VaultStrategy: types.STRATEGY_TYPE_HARD, - TotalShares: depositAmount.Amount.ToDec().String(), - TotalValue: depositAmount.Amount, + Denom: "usdx", + Strategies: []types.StrategyType{types.STRATEGY_TYPE_HARD}, + TotalShares: depositAmount.Amount.ToDec().String(), + TotalValue: depositAmount.Amount, }, res.Vaults[0], ) @@ -160,14 +160,14 @@ func (suite *grpcQueryTestSuite) TestDeposits() { // Deposit into each vault from each account - 4 total deposits // Acc 1: usdx + busd // Acc 2: usdx + usdc - err := suite.Keeper.Deposit(suite.Ctx, acc1, deposit1Amount) + err := suite.Keeper.Deposit(suite.Ctx, acc1, deposit1Amount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) - err = suite.Keeper.Deposit(suite.Ctx, acc1, deposit2Amount) + err = suite.Keeper.Deposit(suite.Ctx, acc1, deposit2Amount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) - err = suite.Keeper.Deposit(suite.Ctx, acc2, deposit1Amount) + err = suite.Keeper.Deposit(suite.Ctx, acc2, deposit1Amount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) - err = suite.Keeper.Deposit(suite.Ctx, acc2, deposit3Amount) + err = suite.Keeper.Deposit(suite.Ctx, acc2, deposit3Amount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) suite.Run("1) 1 vault for 1 account", func() { diff --git a/x/earn/keeper/msg_server.go b/x/earn/keeper/msg_server.go index ed8ffc55..755cea85 100644 --- a/x/earn/keeper/msg_server.go +++ b/x/earn/keeper/msg_server.go @@ -29,7 +29,7 @@ func (m msgServer) Deposit(goCtx context.Context, msg *types.MsgDeposit) (*types return nil, err } - if err := m.keeper.Deposit(ctx, depositor, msg.Amount); err != nil { + if err := m.keeper.Deposit(ctx, depositor, msg.Amount, msg.Strategy); err != nil { return nil, err } @@ -53,7 +53,7 @@ func (m msgServer) Withdraw(goCtx context.Context, msg *types.MsgWithdraw) (*typ return nil, err } - if err := m.keeper.Withdraw(ctx, from, msg.Amount); err != nil { + if err := m.keeper.Withdraw(ctx, from, msg.Amount, msg.Strategy); err != nil { return nil, err } diff --git a/x/earn/keeper/msg_server_test.go b/x/earn/keeper/msg_server_test.go index 0696aebf..88a5246b 100644 --- a/x/earn/keeper/msg_server_test.go +++ b/x/earn/keeper/msg_server_test.go @@ -41,7 +41,7 @@ func (suite *msgServerTestSuite) TestDeposit() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - msg := types.NewMsgDeposit(acc.GetAddress().String(), depositAmount) + msg := types.NewMsgDeposit(acc.GetAddress().String(), depositAmount, types.STRATEGY_TYPE_HARD) _, err := suite.msgServer.Deposit(sdk.WrapSDKContext(suite.Ctx), msg) suite.Require().NoError(err) @@ -94,12 +94,12 @@ func (suite *msgServerTestSuite) TestWithdraw() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - msgDeposit := types.NewMsgDeposit(acc.GetAddress().String(), depositAmount) + msgDeposit := types.NewMsgDeposit(acc.GetAddress().String(), depositAmount, types.STRATEGY_TYPE_HARD) _, err := suite.msgServer.Deposit(sdk.WrapSDKContext(suite.Ctx), msgDeposit) suite.Require().NoError(err) // Withdraw all - msgWithdraw := types.NewMsgWithdraw(acc.GetAddress().String(), depositAmount) + msgWithdraw := types.NewMsgWithdraw(acc.GetAddress().String(), depositAmount, types.STRATEGY_TYPE_HARD) _, err = suite.msgServer.Withdraw(sdk.WrapSDKContext(suite.Ctx), msgWithdraw) suite.Require().NoError(err) diff --git a/x/earn/keeper/strategy_hard_test.go b/x/earn/keeper/strategy_hard_test.go index 1dbd1139..dacc0e7d 100644 --- a/x/earn/keeper/strategy_hard_test.go +++ b/x/earn/keeper/strategy_hard_test.go @@ -40,7 +40,7 @@ func (suite *strategyHardTestSuite) TestDeposit_SingleAcc() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) suite.HardDepositAmountEqual(sdk.NewCoins(depositAmount)) @@ -65,11 +65,11 @@ func (suite *strategyHardTestSuite) TestDeposit_SingleAcc_MultipleDeposits() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // Second deposit - err = suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err = suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) expectedVaultBalance := depositAmount.Add(depositAmount) @@ -101,11 +101,11 @@ func (suite *strategyHardTestSuite) TestDeposit_MultipleAcc_MultipleDeposits() { // 2 deposits each account for i := 0; i < 2; i++ { // Deposit from acc1 - err := suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // Deposit from acc2 - err = suite.Keeper.Deposit(suite.Ctx, acc2.GetAddress(), depositAmount) + err = suite.Keeper.Deposit(suite.Ctx, acc2.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) } @@ -150,7 +150,7 @@ func (suite *strategyHardTestSuite) TestGetVaultTotalValue_NoDenomDeposit() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) // Deposit vault1 - err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // Query vault total, hard deposit exists for account, but amount in busd does not @@ -173,7 +173,7 @@ func (suite *strategyHardTestSuite) TestWithdraw() { suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_HARD) acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) suite.HardDepositAmountEqual(sdk.NewCoins(depositAmount)) @@ -184,7 +184,7 @@ func (suite *strategyHardTestSuite) TestWithdraw() { suite.Equal(depositAmount, totalValue) // Withdraw - err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), depositAmount) + err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) suite.HardDepositAmountEqual(sdk.NewCoins()) @@ -196,7 +196,7 @@ func (suite *strategyHardTestSuite) TestWithdraw() { suite.Equal(sdk.NewInt64Coin(vaultDenom, 0), totalValue) // Withdraw again - err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), depositAmount) + err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().Error(err) suite.Require().ErrorIs(err, types.ErrVaultRecordNotFound, "vault should be deleted when no more supply") } @@ -211,18 +211,18 @@ func (suite *strategyHardTestSuite) TestWithdraw_OnlyWithdrawOwnSupply() { // Deposits from 2 accounts acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0).GetAddress() acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress() - err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) - err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount) + err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // Withdraw - err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount) + err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // Withdraw again - err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount) + err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().Error(err) suite.Require().ErrorIs( err, @@ -242,11 +242,11 @@ func (suite *strategyHardTestSuite) TestWithdraw_WithAccumulatedHard() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0).GetAddress() acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress() - err := suite.Keeper.Deposit(suite.Ctx, acc, depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // Deposit from acc2 so the vault doesn't get deleted when withdrawing - err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount) + err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // Direct hard deposit from module account to increase vault value @@ -260,11 +260,11 @@ func (suite *strategyHardTestSuite) TestWithdraw_WithAccumulatedHard() { suite.Equal(depositAmount.AddAmount(sdk.NewInt(10)), accValue) // Withdraw 100, 10 remaining - err = suite.Keeper.Withdraw(suite.Ctx, acc, depositAmount) + err = suite.Keeper.Withdraw(suite.Ctx, acc, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // Withdraw 100 again -- too much - err = suite.Keeper.Withdraw(suite.Ctx, acc, depositAmount) + err = suite.Keeper.Withdraw(suite.Ctx, acc, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().Error(err) suite.Require().ErrorIs( err, @@ -273,11 +273,11 @@ func (suite *strategyHardTestSuite) TestWithdraw_WithAccumulatedHard() { ) // Half of remaining 10, 5 remaining - err = suite.Keeper.Withdraw(suite.Ctx, acc, sdk.NewCoin(vaultDenom, sdk.NewInt(5))) + err = suite.Keeper.Withdraw(suite.Ctx, acc, sdk.NewCoin(vaultDenom, sdk.NewInt(5)), types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // Withdraw all - err = suite.Keeper.Withdraw(suite.Ctx, acc, sdk.NewCoin(vaultDenom, sdk.NewInt(5))) + err = suite.Keeper.Withdraw(suite.Ctx, acc, sdk.NewCoin(vaultDenom, sdk.NewInt(5)), types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) accValue, err = suite.Keeper.GetVaultAccountValue(suite.Ctx, vaultDenom, acc) @@ -302,7 +302,7 @@ func (suite *strategyHardTestSuite) TestAccountShares() { acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress() // 1. acc1 deposit 100 - err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) acc1Shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1) @@ -318,7 +318,7 @@ func (suite *strategyHardTestSuite) TestAccountShares() { // 2. acc2 deposit 100 // share price is 10% more expensive now // hard 110 -> 210 - err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount) + err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // 100 * 100 / 210 = 47.619047619 shares @@ -347,7 +347,7 @@ func (suite *strategyHardTestSuite) TestAccountShares() { suite.HardKeeper.Deposit(suite.Ctx, macc.GetAddress(), sdk.NewCoins(sdk.NewInt64Coin(vaultDenom, 90))) // Deposit again from acc1 - err = suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount) + err = suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) acc1Shares, found = suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1) @@ -377,11 +377,11 @@ func (suite *strategyHardTestSuite) TestWithdraw_AccumulatedAmount() { acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress() // 1. acc1 deposit 100 - err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // acc2 deposit 100, just to make sure other deposits do not affect acc1 - err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount) + err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) acc1Shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1) @@ -395,7 +395,7 @@ func (suite *strategyHardTestSuite) TestWithdraw_AccumulatedAmount() { suite.Require().NoError(err) // 3. Withdraw all from acc1 - including accumulated amount - err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount.AddAmount(sdk.NewInt(10))) + err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount.AddAmount(sdk.NewInt(10)), types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) _, found = suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1) @@ -415,11 +415,11 @@ func (suite *strategyHardTestSuite) TestWithdraw_AccumulatedTruncated() { acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1).GetAddress() // 1. acc1 deposit 100 - err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // acc2 deposit 100, just to make sure other deposits do not affect acc1 - err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount) + err = suite.Keeper.Deposit(suite.Ctx, acc2, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) acc1Shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1) @@ -437,7 +437,7 @@ func (suite *strategyHardTestSuite) TestWithdraw_AccumulatedTruncated() { suite.Equal(depositAmount.AddAmount(sdk.NewInt(5)), accBal, "acc1 should have 105 usdx") // 3. Withdraw all from acc1 - including accumulated amount - err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount.AddAmount(sdk.NewInt(5))) + err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount.AddAmount(sdk.NewInt(5)), types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) acc1Shares, found = suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1) @@ -459,7 +459,7 @@ func (suite *strategyHardTestSuite) TestWithdraw_ExpensiveShares() { acc1 := suite.CreateAccount(sdk.NewCoins(startBalance), 0).GetAddress() // 1. acc1 deposit 100 - err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) acc1Shares, found := suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1) @@ -477,7 +477,7 @@ func (suite *strategyHardTestSuite) TestWithdraw_ExpensiveShares() { suite.Equal(sdk.NewInt(2000), accBal.Amount, "acc1 should have 2000 usdx") // 3. Withdraw all from acc1 - including accumulated amount - err = suite.Keeper.Withdraw(suite.Ctx, acc1, sdk.NewInt64Coin(vaultDenom, 2000)) + err = suite.Keeper.Withdraw(suite.Ctx, acc1, sdk.NewInt64Coin(vaultDenom, 2000), types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) acc1Shares, found = suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1) diff --git a/x/earn/keeper/vault.go b/x/earn/keeper/vault.go index 0e51bb16..fbb01f9f 100644 --- a/x/earn/keeper/vault.go +++ b/x/earn/keeper/vault.go @@ -38,7 +38,7 @@ func (k *Keeper) GetVaultTotalValue( return sdk.Coin{}, types.ErrVaultRecordNotFound } - strategy, err := k.GetStrategy(enabledVault.VaultStrategy) + strategy, err := k.GetStrategy(enabledVault.Strategies[0]) if err != nil { return sdk.Coin{}, types.ErrInvalidVaultStrategy } diff --git a/x/earn/keeper/vault_test.go b/x/earn/keeper/vault_test.go index f900024c..15a77028 100644 --- a/x/earn/keeper/vault_test.go +++ b/x/earn/keeper/vault_test.go @@ -32,7 +32,7 @@ func (suite *vaultTestSuite) TestGetVaultTotalShares() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) vaultTotalShares, found := suite.Keeper.GetVaultTotalShares(suite.Ctx, vaultDenom) @@ -66,13 +66,12 @@ func (suite *vaultTestSuite) TestGetVaultTotalValue_NotFound() { suite.Require().ErrorIs(err, types.ErrVaultRecordNotFound) } -func (suite *vaultTestSuite) TestGetVaultTotalValue_InvalidStrategy() { +func (suite *vaultTestSuite) TestInvalidVaultStrategy() { 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) + suite.PanicsWithValue("value from ParamSetPair is invalid: invalid strategy 99999", func() { + suite.CreateVault(vaultDenom, 99999) // not valid strategy type + }) } func (suite *vaultTestSuite) TestGetVaultAccountSupplied() { @@ -95,10 +94,10 @@ func (suite *vaultTestSuite) TestGetVaultAccountSupplied() { suite.Require().False(found) // Deposits from both accounts - err := suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), deposit1Amount) + err := suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), deposit1Amount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) - err = suite.Keeper.Deposit(suite.Ctx, acc2.GetAddress(), deposit2Amount) + err = suite.Keeper.Deposit(suite.Ctx, acc2.GetAddress(), deposit2Amount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // Check balances @@ -123,7 +122,7 @@ func (suite *vaultTestSuite) TestGetVaultAccountValue() { suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_HARD) - err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) accValue, err := suite.Keeper.GetVaultAccountValue(suite.Ctx, vaultDenom, acc.GetAddress()) @@ -151,7 +150,7 @@ func (suite *vaultTestSuite) TestGetVaultAccountValue_ShareNotFound() { suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_HARD) // Deposit from acc1 so that vault record exists - err := suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // Query from acc2 with no share record diff --git a/x/earn/keeper/withdraw.go b/x/earn/keeper/withdraw.go index 8f7df36a..f88d2688 100644 --- a/x/earn/keeper/withdraw.go +++ b/x/earn/keeper/withdraw.go @@ -11,7 +11,12 @@ import ( // 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, wantAmount sdk.Coin) error { +func (k *Keeper) Withdraw( + ctx sdk.Context, + from sdk.AccAddress, + wantAmount sdk.Coin, + withdrawStrategy types.StrategyType, +) error { // Get AllowedVault, if not found (not a valid vault), return error allowedVault, found := k.GetAllowedVault(ctx, wantAmount.Denom) if !found { @@ -22,6 +27,11 @@ func (k *Keeper) Withdraw(ctx sdk.Context, from sdk.AccAddress, wantAmount sdk.C return types.ErrInsufficientAmount } + // Check if withdraw strategy is supported by vault + if !allowedVault.IsStrategyAllowed(withdrawStrategy) { + return types.ErrInvalidVaultStrategy + } + // Check if VaultRecord exists vaultRecord, found := k.GetVaultRecord(ctx, wantAmount.Denom) if !found { @@ -74,7 +84,7 @@ func (k *Keeper) Withdraw(ctx sdk.Context, from sdk.AccAddress, wantAmount sdk.C } // Get the strategy for the vault - strategy, err := k.GetStrategy(allowedVault.VaultStrategy) + strategy, err := k.GetStrategy(allowedVault.Strategies[0]) if err != nil { return err } diff --git a/x/earn/keeper/withdraw_test.go b/x/earn/keeper/withdraw_test.go index d173d3b7..26450b68 100644 --- a/x/earn/keeper/withdraw_test.go +++ b/x/earn/keeper/withdraw_test.go @@ -33,7 +33,7 @@ func (suite *withdrawTestSuite) TestWithdraw_NoVaultRecord() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) // Withdraw without having any prior deposits - err := suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount) + err := suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount, types.STRATEGY_TYPE_HARD) suite.Require().Error(err) suite.Require().ErrorIs(err, types.ErrVaultRecordNotFound) @@ -59,13 +59,13 @@ func (suite *withdrawTestSuite) TestWithdraw_NoVaultShareRecord() { // 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) + err := suite.Keeper.Deposit(suite.Ctx, acc1.GetAddress(), acc1DepositAmount, types.STRATEGY_TYPE_HARD) 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) + err = suite.Keeper.Withdraw(suite.Ctx, acc2.GetAddress(), acc2WithdrawAmount, types.STRATEGY_TYPE_HARD) suite.Require().Error(err) suite.Require().ErrorIs(err, types.ErrVaultShareRecordNotFound) @@ -91,10 +91,10 @@ func (suite *withdrawTestSuite) TestWithdraw_ExceedBalance() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) - err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount) + err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount, types.STRATEGY_TYPE_HARD) suite.Require().Error(err) suite.Require().ErrorIs(err, types.ErrInsufficientValue) @@ -119,7 +119,7 @@ func (suite *withdrawTestSuite) TestWithdraw_Zero() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - err := suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount) + err := suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount, types.STRATEGY_TYPE_HARD) suite.Require().Error(err) suite.Require().ErrorIs(err, types.ErrInsufficientAmount) @@ -144,7 +144,7 @@ func (suite *withdrawTestSuite) TestWithdraw_InvalidVault() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - err := suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount) + err := suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount, types.STRATEGY_TYPE_HARD) suite.Require().Error(err) suite.Require().ErrorIs(err, types.ErrInvalidVaultDenom) @@ -160,6 +160,20 @@ func (suite *withdrawTestSuite) TestWithdraw_InvalidVault() { ) } +func (suite *withdrawTestSuite) TestWithdraw_InvalidStrategy() { + vaultDenom := "usdx" + startBalance := sdk.NewInt64Coin(vaultDenom, 1000) + withdrawAmount := sdk.NewInt64Coin(vaultDenom, 1001) + + suite.CreateVault(vaultDenom, types.STRATEGY_TYPE_HARD) + + acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) + + err := suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount, types.STRATEGY_TYPE_SAVINGS) + suite.Require().Error(err) + suite.Require().ErrorIs(err, types.ErrInvalidVaultStrategy) +} + func (suite *withdrawTestSuite) TestWithdraw_FullBalance() { vaultDenom := "usdx" startBalance := sdk.NewInt64Coin(vaultDenom, 1000) @@ -170,10 +184,10 @@ func (suite *withdrawTestSuite) TestWithdraw_FullBalance() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) - err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount) + err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // No net changes in balances @@ -197,10 +211,10 @@ func (suite *withdrawTestSuite) TestWithdraw_Partial() { acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0) - err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount) + err := suite.Keeper.Deposit(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) - err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), partialWithdrawAmount) + err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), partialWithdrawAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) suite.AccountBalanceEqual( @@ -209,11 +223,11 @@ func (suite *withdrawTestSuite) TestWithdraw_Partial() { ) // Second withdraw for remaining 50 - err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), partialWithdrawAmount) + err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), partialWithdrawAmount, types.STRATEGY_TYPE_HARD) suite.Require().NoError(err) // No more balance to withdraw - err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), partialWithdrawAmount) + err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), partialWithdrawAmount, types.STRATEGY_TYPE_HARD) suite.Require().Error(err) suite.Require().ErrorIs(err, types.ErrVaultRecordNotFound, "vault record should be deleted after no more supplied") diff --git a/x/earn/testutil/suite.go b/x/earn/testutil/suite.go index 2b883592..0a2ff495 100644 --- a/x/earn/testutil/suite.go +++ b/x/earn/testutil/suite.go @@ -216,13 +216,11 @@ func (suite *Suite) NewAccountFromAddr(addr sdk.AccAddress, balance sdk.Coins) a // 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) params := types.NewParams(allowedVaults) - suite.Require().NoError(params.Validate()) suite.Keeper.SetParams( suite.Ctx, diff --git a/x/earn/types/msg.go b/x/earn/types/msg.go index edd406b2..40fd23fb 100644 --- a/x/earn/types/msg.go +++ b/x/earn/types/msg.go @@ -20,10 +20,11 @@ const ( ) // NewMsgDeposit returns a new MsgDeposit. -func NewMsgDeposit(depositor string, amount sdk.Coin) *MsgDeposit { +func NewMsgDeposit(depositor string, amount sdk.Coin, strategy StrategyType) *MsgDeposit { return &MsgDeposit{ Depositor: depositor, Amount: amount, + Strategy: strategy, } } @@ -37,6 +38,10 @@ func (msg MsgDeposit) ValidateBasic() error { return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, err.Error()) } + if err := msg.Strategy.Validate(); err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error()) + } + return nil } @@ -67,10 +72,11 @@ func (msg MsgDeposit) Type() string { } // NewMsgWithdraw returns a new MsgWithdraw. -func NewMsgWithdraw(from string, amount sdk.Coin) *MsgWithdraw { +func NewMsgWithdraw(from string, amount sdk.Coin, strategy StrategyType) *MsgWithdraw { return &MsgWithdraw{ - From: from, - Amount: amount, + From: from, + Amount: amount, + Strategy: strategy, } } @@ -84,6 +90,10 @@ func (msg MsgWithdraw) ValidateBasic() error { return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, err.Error()) } + if err := msg.Strategy.Validate(); err != nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error()) + } + return nil } diff --git a/x/earn/types/query.pb.go b/x/earn/types/query.pb.go index 57dcf2c3..88ffc5ee 100644 --- a/x/earn/types/query.pb.go +++ b/x/earn/types/query.pb.go @@ -192,7 +192,7 @@ type VaultResponse struct { // denom represents the denom of the vault Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` // VaultStrategy is the strategy used for this vault. - VaultStrategy StrategyType `protobuf:"varint,2,opt,name=vault_strategy,json=vaultStrategy,proto3,enum=kava.earn.v1beta1.StrategyType" json:"vault_strategy,omitempty"` + Strategies StrategyTypes `protobuf:"varint,2,rep,packed,name=strategies,proto3,enum=kava.earn.v1beta1.StrategyType,castrepeated=StrategyTypes" json:"strategies,omitempty"` // TotalShares is the total amount of shares issued to depositors. TotalShares string `protobuf:"bytes,3,opt,name=total_shares,json=totalShares,proto3" json:"total_shares,omitempty"` // TotalValue is the total value of denom coins supplied to the vault if the @@ -376,55 +376,56 @@ func init() { func init() { proto.RegisterFile("kava/earn/v1beta1/query.proto", fileDescriptor_63f8dee2f3192a6b) } var fileDescriptor_63f8dee2f3192a6b = []byte{ - // 762 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x55, 0xcf, 0x4f, 0x13, 0x4f, - 0x14, 0xef, 0xb6, 0xb4, 0x81, 0xe9, 0x17, 0xbe, 0x71, 0xa8, 0x49, 0x5b, 0x64, 0x5b, 0x96, 0x08, - 0x95, 0xa4, 0xbb, 0x52, 0x13, 0xbd, 0x18, 0x13, 0x2b, 0xd1, 0xe0, 0xc1, 0xe8, 0xa2, 0x1c, 0x4c, - 0x4c, 0x33, 0xa5, 0x93, 0x65, 0x43, 0xbb, 0xb3, 0xec, 0x4c, 0xab, 0x68, 0xbc, 0x70, 0x37, 0x31, - 0xf1, 0x5f, 0x30, 0x1e, 0x3c, 0xf3, 0x47, 0x70, 0x24, 0x78, 0x31, 0x1e, 0x50, 0xc1, 0xbb, 0x57, - 0x8f, 0x66, 0x7e, 0x2c, 0x65, 0xdb, 0x6d, 0xea, 0xa9, 0x9d, 0xf7, 0xe3, 0xf3, 0xf9, 0xbc, 0x37, - 0x6f, 0xde, 0x82, 0xf9, 0x1d, 0xd4, 0x43, 0x16, 0x46, 0x81, 0x67, 0xf5, 0x56, 0x9b, 0x98, 0xa1, - 0x55, 0x6b, 0xb7, 0x8b, 0x83, 0x3d, 0xd3, 0x0f, 0x08, 0x23, 0xf0, 0x12, 0x77, 0x9b, 0xdc, 0x6d, - 0x2a, 0x77, 0xb1, 0xb0, 0x45, 0x68, 0x87, 0xd0, 0x86, 0x08, 0xb0, 0xe4, 0x41, 0x46, 0x17, 0x57, - 0xe4, 0xc9, 0x6a, 0x22, 0x8a, 0x25, 0xcc, 0x39, 0xa8, 0x8f, 0x1c, 0xd7, 0x43, 0xcc, 0x25, 0x9e, - 0x8a, 0xd5, 0x2f, 0xc6, 0x86, 0x51, 0x5b, 0xc4, 0x0d, 0xfd, 0x39, 0x87, 0x38, 0x44, 0x72, 0xf0, - 0x7f, 0xca, 0x7a, 0xc5, 0x21, 0xc4, 0x69, 0x63, 0x0b, 0xf9, 0xae, 0x85, 0x3c, 0x8f, 0x30, 0x01, - 0x19, 0xf2, 0xeb, 0xc3, 0xc5, 0xf8, 0x28, 0x40, 0x9d, 0xd0, 0x5f, 0x1e, 0xf6, 0x53, 0x16, 0x20, - 0x86, 0x1d, 0x55, 0x6f, 0x31, 0xa6, 0x1d, 0x3d, 0xd4, 0x6d, 0x33, 0xe9, 0x36, 0x72, 0x00, 0x3e, - 0xe1, 0x65, 0x3d, 0x16, 0xa8, 0x36, 0xde, 0xed, 0x62, 0xca, 0x8c, 0x47, 0x60, 0x36, 0x62, 0xa5, - 0x3e, 0xf1, 0x28, 0x86, 0xb7, 0x40, 0x46, 0xb2, 0xe7, 0xb5, 0xb2, 0x56, 0xc9, 0xd6, 0x0a, 0xe6, - 0x50, 0x33, 0x4d, 0x99, 0x52, 0x9f, 0x38, 0x3c, 0x29, 0x25, 0x6c, 0x15, 0x6e, 0xac, 0x28, 0x96, - 0x4d, 0xce, 0x1c, 0xb2, 0xc0, 0x1c, 0x48, 0xb7, 0xb0, 0x47, 0x3a, 0x02, 0x6d, 0xca, 0x96, 0x07, - 0xe3, 0x99, 0xe2, 0x0e, 0x63, 0x15, 0xf7, 0x1d, 0x90, 0x11, 0xba, 0x39, 0x77, 0xaa, 0x92, 0xad, - 0x95, 0x63, 0xb8, 0x45, 0x4a, 0x98, 0x11, 0x4a, 0x90, 0x59, 0xc6, 0x6f, 0x0d, 0x4c, 0x47, 0xfc, - 0xf1, 0xf4, 0xf0, 0x3e, 0x98, 0x11, 0x19, 0x8d, 0xb0, 0x8f, 0xf9, 0x64, 0x59, 0xab, 0xcc, 0xd4, - 0x4a, 0x31, 0x7c, 0x1b, 0x2a, 0xe4, 0xe9, 0x9e, 0x8f, 0xed, 0x69, 0x91, 0x16, 0x9a, 0xe0, 0x02, - 0xf8, 0x8f, 0x11, 0x86, 0xda, 0x0d, 0xba, 0x8d, 0x02, 0x4c, 0xf3, 0x29, 0x41, 0x92, 0x15, 0xb6, - 0x0d, 0x61, 0x82, 0x2f, 0x80, 0x3c, 0x36, 0x7a, 0xa8, 0xdd, 0xc5, 0xf9, 0x09, 0x1e, 0x51, 0xbf, - 0xcd, 0x55, 0x7f, 0x3b, 0x29, 0x2d, 0x39, 0x2e, 0xdb, 0xee, 0x36, 0xcd, 0x2d, 0xd2, 0x51, 0x23, - 0xa9, 0x7e, 0xaa, 0xb4, 0xb5, 0x63, 0xb1, 0x3d, 0x1f, 0x53, 0x73, 0xdd, 0x63, 0xc7, 0x07, 0x55, - 0xa0, 0x26, 0x76, 0xdd, 0x63, 0x36, 0x10, 0x80, 0x9b, 0x1c, 0xcf, 0xf8, 0xa8, 0x81, 0x9c, 0xe8, - 0xe4, 0x1a, 0xf6, 0x09, 0x75, 0xfb, 0x7d, 0x37, 0x41, 0x9a, 0xbc, 0xf4, 0x70, 0x20, 0x0b, 0xaf, - 0xe7, 0x8f, 0x0f, 0xaa, 0x39, 0x85, 0x71, 0xb7, 0xd5, 0x0a, 0x30, 0xa5, 0x1b, 0x2c, 0x70, 0x3d, - 0xc7, 0x96, 0x61, 0xfd, 0x46, 0x25, 0xa3, 0x8d, 0x02, 0xfd, 0x27, 0x20, 0xca, 0xcb, 0xd6, 0x96, - 0x4c, 0x85, 0xc3, 0xdf, 0x80, 0x29, 0x9f, 0x5d, 0x7f, 0x30, 0x1c, 0xac, 0x14, 0xd8, 0x17, 0x32, - 0x8d, 0x4f, 0x1a, 0xb8, 0x3c, 0x20, 0x53, 0x5d, 0xd0, 0x1a, 0x98, 0x6c, 0x29, 0x9b, 0xba, 0x74, - 0x23, 0xe6, 0x12, 0x54, 0xda, 0xc0, 0xb5, 0x9f, 0x67, 0xc2, 0x07, 0x11, 0x9d, 0x49, 0xa1, 0x73, - 0x79, 0xac, 0x4e, 0x09, 0x16, 0x11, 0xfa, 0x47, 0x03, 0xff, 0x0f, 0x90, 0xc1, 0x9b, 0x60, 0x4a, - 0x11, 0x91, 0xf1, 0xed, 0xec, 0x87, 0xc2, 0x87, 0x20, 0xa3, 0xe6, 0x22, 0x29, 0x0a, 0x9b, 0x1f, - 0x35, 0xcd, 0x62, 0x54, 0xea, 0xb3, 0xbc, 0xa6, 0xcf, 0xdf, 0x4b, 0xd9, 0xbe, 0x8d, 0xda, 0x0a, - 0x01, 0x22, 0x90, 0x96, 0x03, 0x94, 0x12, 0x50, 0x85, 0x48, 0x6d, 0x21, 0xd8, 0x3d, 0xe2, 0x7a, - 0xf5, 0xeb, 0x0a, 0xa6, 0xf2, 0x0f, 0xb3, 0xc5, 0x13, 0xa8, 0x2d, 0x91, 0x6b, 0xef, 0x52, 0x20, - 0x2d, 0xee, 0x08, 0xbe, 0x06, 0x19, 0xf9, 0xc2, 0xe1, 0xd5, 0x18, 0xc9, 0xc3, 0xab, 0xa4, 0xb8, - 0x34, 0x2e, 0x4c, 0x76, 0xd2, 0x58, 0xd8, 0xff, 0xf2, 0xeb, 0x43, 0x72, 0x0e, 0x16, 0xac, 0x51, - 0x2b, 0x0f, 0xee, 0x6b, 0x20, 0x23, 0xb7, 0xc2, 0x68, 0xf2, 0xc8, 0x86, 0x19, 0x4d, 0x1e, 0x5d, - 0x2e, 0xc6, 0x35, 0x41, 0xbe, 0x08, 0x17, 0xac, 0x11, 0xdb, 0x92, 0x5a, 0x6f, 0xc4, 0xd4, 0xbf, - 0xe5, 0x22, 0x26, 0xc3, 0x49, 0x85, 0xcb, 0xa3, 0xf0, 0x07, 0x9e, 0x5c, 0xb1, 0x32, 0x3e, 0x50, - 0x49, 0x59, 0x14, 0x52, 0xe6, 0xe1, 0x5c, 0x8c, 0x94, 0x70, 0xa6, 0xeb, 0x6b, 0x87, 0x3f, 0xf5, - 0xc4, 0xe1, 0xa9, 0xae, 0x1d, 0x9d, 0xea, 0xda, 0x8f, 0x53, 0x5d, 0x7b, 0x7f, 0xa6, 0x27, 0x8e, - 0xce, 0xf4, 0xc4, 0xd7, 0x33, 0x3d, 0xf1, 0xfc, 0xe2, 0xea, 0xe0, 0x20, 0xd5, 0x36, 0x6a, 0x52, - 0x09, 0xf7, 0x4a, 0x02, 0x8a, 0x2b, 0x6e, 0x66, 0xc4, 0x27, 0xe0, 0xc6, 0xdf, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x27, 0x75, 0x39, 0xf4, 0x32, 0x07, 0x00, 0x00, + // 771 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x55, 0x4f, 0x4f, 0x13, 0x4d, + 0x18, 0xef, 0xb6, 0xb4, 0x81, 0xe9, 0xcb, 0xfb, 0x86, 0xa1, 0x6f, 0xd2, 0x96, 0x97, 0x6d, 0x59, + 0xf2, 0x42, 0x25, 0xe9, 0xae, 0xd4, 0x44, 0x2f, 0xc6, 0xc4, 0x4a, 0x34, 0x78, 0x30, 0xba, 0x28, + 0x07, 0x13, 0x43, 0xa6, 0x74, 0xb2, 0x6c, 0x68, 0x77, 0x96, 0x9d, 0x69, 0x15, 0x8d, 0x17, 0xee, + 0x26, 0x26, 0x7e, 0x05, 0xe3, 0x81, 0x33, 0x1f, 0x82, 0x23, 0xc1, 0x8b, 0xf1, 0x00, 0x0a, 0x7e, + 0x08, 0x13, 0x2f, 0x66, 0xfe, 0x2c, 0xed, 0xb6, 0xdb, 0xd4, 0x53, 0x3b, 0xcf, 0x9f, 0xdf, 0xef, + 0x79, 0x9e, 0xf9, 0xcd, 0xb3, 0x60, 0x7e, 0x17, 0x75, 0x91, 0x85, 0x51, 0xe0, 0x59, 0xdd, 0xd5, + 0x06, 0x66, 0x68, 0xd5, 0xda, 0xeb, 0xe0, 0x60, 0xdf, 0xf4, 0x03, 0xc2, 0x08, 0x9c, 0xe1, 0x6e, + 0x93, 0xbb, 0x4d, 0xe5, 0x2e, 0x16, 0xb6, 0x09, 0x6d, 0x13, 0xba, 0x25, 0x02, 0x2c, 0x79, 0x90, + 0xd1, 0xc5, 0x15, 0x79, 0xb2, 0x1a, 0x88, 0x62, 0x09, 0x73, 0x05, 0xea, 0x23, 0xc7, 0xf5, 0x10, + 0x73, 0x89, 0xa7, 0x62, 0xf5, 0xfe, 0xd8, 0x30, 0x6a, 0x9b, 0xb8, 0xa1, 0x3f, 0xe7, 0x10, 0x87, + 0x48, 0x0e, 0xfe, 0x4f, 0x59, 0xff, 0x73, 0x08, 0x71, 0x5a, 0xd8, 0x42, 0xbe, 0x6b, 0x21, 0xcf, + 0x23, 0x4c, 0x40, 0x86, 0xfc, 0xfa, 0x70, 0x33, 0x3e, 0x0a, 0x50, 0x3b, 0xf4, 0x97, 0x87, 0xfd, + 0x94, 0x05, 0x88, 0x61, 0x47, 0xf5, 0x5b, 0x8c, 0x19, 0x47, 0x17, 0x75, 0x5a, 0x4c, 0xba, 0x8d, + 0x1c, 0x80, 0x4f, 0x78, 0x5b, 0x8f, 0x05, 0xaa, 0x8d, 0xf7, 0x3a, 0x98, 0x32, 0xe3, 0x11, 0x98, + 0x8d, 0x58, 0xa9, 0x4f, 0x3c, 0x8a, 0xe1, 0x2d, 0x90, 0x91, 0xec, 0x79, 0xad, 0xac, 0x55, 0xb2, + 0xb5, 0x82, 0x39, 0x34, 0x4c, 0x53, 0xa6, 0xd4, 0x27, 0x8e, 0xcf, 0x4a, 0x09, 0x5b, 0x85, 0x1b, + 0x2b, 0x8a, 0x65, 0x93, 0x33, 0x87, 0x2c, 0x30, 0x07, 0xd2, 0x4d, 0xec, 0x91, 0xb6, 0x40, 0x9b, + 0xb2, 0xe5, 0xc1, 0x78, 0xa6, 0xb8, 0xc3, 0x58, 0xc5, 0x7d, 0x07, 0x64, 0x44, 0xdd, 0x9c, 0x3b, + 0x55, 0xc9, 0xd6, 0xca, 0x31, 0xdc, 0x22, 0x25, 0xcc, 0x08, 0x4b, 0x90, 0x59, 0xc6, 0x2f, 0x0d, + 0x4c, 0x47, 0xfc, 0xf1, 0xf4, 0xd0, 0x06, 0x40, 0x4d, 0xd0, 0xc5, 0x34, 0x9f, 0x2c, 0xa7, 0x2a, + 0x7f, 0xd7, 0x4a, 0x31, 0x5c, 0x1b, 0x6a, 0xcc, 0x4f, 0xf7, 0x7d, 0x5c, 0x9f, 0x39, 0x3c, 0x2f, + 0x4d, 0xf7, 0x5b, 0xa8, 0xdd, 0x87, 0x02, 0x17, 0xc0, 0x5f, 0x8c, 0x30, 0xd4, 0xda, 0xa2, 0x3b, + 0x28, 0xc0, 0x34, 0x9f, 0x12, 0x84, 0x59, 0x61, 0xdb, 0x10, 0x26, 0xf8, 0x02, 0xc8, 0xe3, 0x56, + 0x17, 0xb5, 0x3a, 0x38, 0x3f, 0xc1, 0x23, 0xea, 0xb7, 0x79, 0x07, 0x5f, 0xcf, 0x4a, 0x4b, 0x8e, + 0xcb, 0x76, 0x3a, 0x0d, 0x73, 0x9b, 0xb4, 0x95, 0x3c, 0xd5, 0x4f, 0x95, 0x36, 0x77, 0x2d, 0xc6, + 0xf9, 0xcc, 0x75, 0x8f, 0x9d, 0x1e, 0x55, 0x81, 0x52, 0xef, 0xba, 0xc7, 0x6c, 0x20, 0x00, 0x37, + 0x39, 0x9e, 0xf1, 0x51, 0x03, 0x39, 0x31, 0xd5, 0x35, 0xec, 0x13, 0xea, 0xf6, 0xee, 0xc0, 0x04, + 0x69, 0xf2, 0xd2, 0xc3, 0x81, 0x1c, 0x42, 0x3d, 0x7f, 0x7a, 0x54, 0xcd, 0x29, 0x8c, 0xbb, 0xcd, + 0x66, 0x80, 0x29, 0xdd, 0x60, 0x81, 0xeb, 0x39, 0xb6, 0x0c, 0xeb, 0x0d, 0x2d, 0xd9, 0x3f, 0xb4, + 0xfb, 0x00, 0xf4, 0x9e, 0x83, 0x68, 0x2f, 0x5b, 0x5b, 0x32, 0x15, 0x0e, 0x7f, 0x0f, 0xa6, 0x7c, + 0x82, 0x3d, 0x91, 0x38, 0x58, 0x55, 0x60, 0xf7, 0x65, 0x1a, 0x9f, 0x34, 0xf0, 0xef, 0x40, 0x99, + 0xea, 0xb2, 0xd6, 0xc0, 0x64, 0x53, 0xd9, 0x94, 0x00, 0x8c, 0x98, 0x4b, 0x51, 0x69, 0x03, 0x12, + 0xb8, 0xca, 0x84, 0x0f, 0x22, 0x75, 0x26, 0x45, 0x9d, 0xcb, 0x63, 0xeb, 0x94, 0x60, 0x91, 0x42, + 0x7f, 0x6a, 0xe0, 0x9f, 0x01, 0x32, 0x78, 0x13, 0x4c, 0x29, 0x22, 0x32, 0x7e, 0x9c, 0xbd, 0x50, + 0xf8, 0x10, 0x64, 0x94, 0x2e, 0x92, 0xa2, 0xb1, 0xf9, 0x51, 0xca, 0x16, 0x52, 0xa9, 0xcf, 0xf2, + 0x9e, 0x0e, 0xcf, 0x4b, 0xd9, 0x9e, 0x8d, 0xda, 0x0a, 0x01, 0x22, 0x90, 0x96, 0x02, 0x4a, 0x09, + 0xa8, 0x42, 0xa4, 0xb7, 0x10, 0xec, 0x1e, 0x71, 0xbd, 0xfa, 0x75, 0x05, 0x53, 0xf9, 0x03, 0x6d, + 0xf1, 0x04, 0x6a, 0x4b, 0xe4, 0xda, 0xbb, 0x14, 0x48, 0x8b, 0x3b, 0x82, 0xaf, 0x41, 0x46, 0xbe, + 0x76, 0xf8, 0x7f, 0x4c, 0xc9, 0xc3, 0x6b, 0xa5, 0xb8, 0x34, 0x2e, 0x4c, 0x4e, 0xd2, 0x58, 0x38, + 0xf8, 0xfc, 0xe3, 0x43, 0x72, 0x0e, 0x16, 0xac, 0x51, 0xeb, 0x0f, 0x1e, 0x68, 0x20, 0x23, 0x37, + 0xc4, 0x68, 0xf2, 0xc8, 0xb6, 0x19, 0x4d, 0x1e, 0x5d, 0x34, 0xc6, 0x35, 0x41, 0xbe, 0x08, 0x17, + 0xac, 0x11, 0x9b, 0x93, 0x5a, 0x6f, 0x84, 0xea, 0xdf, 0xf2, 0x22, 0x26, 0x43, 0xa5, 0xc2, 0xe5, + 0x51, 0xf8, 0x03, 0x4f, 0xae, 0x58, 0x19, 0x1f, 0xa8, 0x4a, 0x59, 0x14, 0xa5, 0xcc, 0xc3, 0xb9, + 0x98, 0x52, 0x42, 0x4d, 0xd7, 0xd7, 0x8e, 0xbf, 0xeb, 0x89, 0xe3, 0x0b, 0x5d, 0x3b, 0xb9, 0xd0, + 0xb5, 0x6f, 0x17, 0xba, 0xf6, 0xfe, 0x52, 0x4f, 0x9c, 0x5c, 0xea, 0x89, 0x2f, 0x97, 0x7a, 0xe2, + 0x79, 0xff, 0xea, 0xe0, 0x20, 0xd5, 0x16, 0x6a, 0x50, 0x09, 0xf7, 0x4a, 0x02, 0x8a, 0x2b, 0x6e, + 0x64, 0xc4, 0xe7, 0xe0, 0xc6, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x53, 0xed, 0x53, 0xe2, 0x3e, + 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -745,10 +746,23 @@ func (m *VaultResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x1a } - if m.VaultStrategy != 0 { - i = encodeVarintQuery(dAtA, i, uint64(m.VaultStrategy)) + if len(m.Strategies) > 0 { + dAtA3 := make([]byte, len(m.Strategies)*10) + var j2 int + for _, num := range m.Strategies { + for num >= 1<<7 { + dAtA3[j2] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j2++ + } + dAtA3[j2] = uint8(num) + j2++ + } + i -= j2 + copy(dAtA[i:], dAtA3[:j2]) + i = encodeVarintQuery(dAtA, i, uint64(j2)) i-- - dAtA[i] = 0x10 + dAtA[i] = 0x12 } if len(m.Denom) > 0 { i -= len(m.Denom) @@ -985,8 +999,12 @@ func (m *VaultResponse) Size() (n int) { if l > 0 { n += 1 + l + sovQuery(uint64(l)) } - if m.VaultStrategy != 0 { - n += 1 + sovQuery(uint64(m.VaultStrategy)) + if len(m.Strategies) > 0 { + l = 0 + for _, e := range m.Strategies { + l += sovQuery(uint64(e)) + } + n += 1 + sovQuery(uint64(l)) + l } l = len(m.TotalShares) if l > 0 { @@ -1429,23 +1447,73 @@ func (m *VaultResponse) Unmarshal(dAtA []byte) error { 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 ErrIntOverflowQuery + if wireType == 0 { + var v StrategyType + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= StrategyType(b&0x7F) << shift + if b < 0x80 { + break + } } - if iNdEx >= l { + m.Strategies = append(m.Strategies, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - m.VaultStrategy |= StrategyType(b&0x7F) << shift - if b < 0x80 { - break + var elementCount int + if elementCount != 0 && len(m.Strategies) == 0 { + m.Strategies = make([]StrategyType, 0, elementCount) } + for iNdEx < postIndex { + var v StrategyType + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= StrategyType(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Strategies = append(m.Strategies, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field Strategies", wireType) } case 3: if wireType != 2 { diff --git a/x/earn/types/strategy.go b/x/earn/types/strategy.go new file mode 100644 index 00000000..5afe5d9d --- /dev/null +++ b/x/earn/types/strategy.go @@ -0,0 +1,62 @@ +package types + +import ( + "fmt" + "strings" +) + +// IsValid returns true if the StrategyType status is valid and false otherwise. +func (s StrategyType) IsValid() bool { + return s == STRATEGY_TYPE_HARD || s == STRATEGY_TYPE_SAVINGS +} + +// Validate returns an error if the StrategyType is invalid. +func (s StrategyType) Validate() error { + if !s.IsValid() { + return fmt.Errorf("invalid strategy %s", s) + } + + return nil +} + +// NewStrategyTypeFromString converts string to StrategyType type +func NewStrategyTypeFromString(str string) StrategyType { + switch strings.ToLower(str) { + case "hard": + return STRATEGY_TYPE_HARD + case "savings": + return STRATEGY_TYPE_SAVINGS + default: + return STRATEGY_TYPE_UNSPECIFIED + } +} + +// StrategyTypes defines a slice of StrategyType +type StrategyTypes []StrategyType + +// Validate returns an error if StrategyTypes are invalid. +func (strategies StrategyTypes) Validate() error { + if len(strategies) == 0 { + return fmt.Errorf("empty StrategyTypes") + } + + if len(strategies) != 1 { + return fmt.Errorf("must have exactly one strategy type, multiple strategies are not supported") + } + + uniqueStrategies := make(map[StrategyType]bool) + + for _, strategy := range strategies { + if err := strategy.Validate(); err != nil { + return err + } + + if _, found := uniqueStrategies[strategy]; found { + return fmt.Errorf("duplicate strategy %s", strategy) + } + + uniqueStrategies[strategy] = true + } + + return nil +} diff --git a/x/earn/types/strategy_test.go b/x/earn/types/strategy_test.go new file mode 100644 index 00000000..ed8fd1c5 --- /dev/null +++ b/x/earn/types/strategy_test.go @@ -0,0 +1,120 @@ +package types_test + +import ( + "testing" + + "github.com/kava-labs/kava/x/earn/types" + "github.com/stretchr/testify/require" +) + +func TestNewStrategyTypeFromString(t *testing.T) { + tests := []struct { + name string + strategy string + expected types.StrategyType + }{ + { + name: "hard", + strategy: "hard", + expected: types.STRATEGY_TYPE_HARD, + }, + { + name: "savings", + strategy: "savings", + expected: types.STRATEGY_TYPE_SAVINGS, + }, + { + name: "unspecified", + strategy: "not a valid strategy name", + expected: types.STRATEGY_TYPE_UNSPECIFIED, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := types.NewStrategyTypeFromString(tc.strategy) + if actual != tc.expected { + t.Errorf("expected %s, got %s", tc.expected, actual) + } + }) + } +} + +func TestValidateStrategyTypes(t *testing.T) { + type errArgs struct { + expectPass bool + contains string + } + + tests := []struct { + name string + strategies types.StrategyTypes + errArgs errArgs + }{ + { + name: "valid - hard", + strategies: types.StrategyTypes{types.STRATEGY_TYPE_HARD}, + errArgs: errArgs{ + expectPass: true, + }, + }, + { + name: "valid - savings", + strategies: types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, + errArgs: errArgs{ + expectPass: true, + }, + }, + { + name: "invalid - duplicate", + strategies: types.StrategyTypes{ + types.STRATEGY_TYPE_SAVINGS, + types.STRATEGY_TYPE_SAVINGS, + }, + errArgs: errArgs{ + expectPass: false, + // This will change to duplicate error if multiple strategies are supported + contains: "must have exactly one strategy type, multiple strategies are not supported", + }, + }, + { + name: "invalid - unspecified", + strategies: types.StrategyTypes{types.STRATEGY_TYPE_UNSPECIFIED}, + errArgs: errArgs{ + expectPass: false, + contains: "invalid strategy", + }, + }, + { + name: "invalid - zero", + strategies: types.StrategyTypes{}, + errArgs: errArgs{ + expectPass: false, + contains: "empty StrategyTypes", + }, + }, + { + name: "invalid - more than 1", + strategies: types.StrategyTypes{ + types.STRATEGY_TYPE_HARD, + types.STRATEGY_TYPE_SAVINGS, + }, + errArgs: errArgs{ + expectPass: false, + contains: "must have exactly one strategy type, multiple strategies are not supported", + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + err := tc.strategies.Validate() + if tc.errArgs.expectPass { + require.NoError(t, err) + } else { + require.Error(t, err) + require.Contains(t, err.Error(), tc.errArgs.contains) + } + }) + } +} diff --git a/x/earn/types/tx.pb.go b/x/earn/types/tx.pb.go index 911f0e38..66920018 100644 --- a/x/earn/types/tx.pb.go +++ b/x/earn/types/tx.pb.go @@ -37,6 +37,8 @@ type MsgDeposit struct { // 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"` + // Strategy is the vault strategy to use. + Strategy StrategyType `protobuf:"varint,3,opt,name=strategy,proto3,enum=kava.earn.v1beta1.StrategyType" json:"strategy,omitempty"` } func (m *MsgDeposit) Reset() { *m = MsgDeposit{} } @@ -124,6 +126,8 @@ type MsgWithdraw struct { // 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"` + // Strategy is the vault strategy to use. + Strategy StrategyType `protobuf:"varint,3,opt,name=strategy,proto3,enum=kava.earn.v1beta1.StrategyType" json:"strategy,omitempty"` } func (m *MsgWithdraw) Reset() { *m = MsgWithdraw{} } @@ -214,33 +218,35 @@ func init() { func init() { proto.RegisterFile("kava/earn/v1beta1/tx.proto", fileDescriptor_2e9dcf48a3fa0009) } var fileDescriptor_2e9dcf48a3fa0009 = []byte{ - // 404 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, - 0x52, 0x92, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xf1, 0x60, 0x05, 0xfa, 0x10, 0x0e, 0x44, 0xb5, - 0x94, 0x1c, 0x84, 0xa7, 0x9f, 0x94, 0x58, 0x9c, 0x0a, 0x37, 0x2b, 0x39, 0x3f, 0x33, 0x0f, 0x2a, - 0x2f, 0x92, 0x9e, 0x9f, 0x9e, 0x0f, 0xd1, 0x07, 0x62, 0x41, 0x45, 0x65, 0x31, 0xed, 0x2f, 0x4b, - 0x2c, 0xcd, 0x29, 0x81, 0x48, 0x2b, 0x35, 0x33, 0x72, 0x71, 0xf9, 0x16, 0xa7, 0xbb, 0xa4, 0x16, - 0xe4, 0x17, 0x67, 0x96, 0x08, 0x99, 0x71, 0x71, 0xa6, 0x40, 0x98, 0xf9, 0x45, 0x12, 0x8c, 0x0a, - 0x8c, 0x1a, 0x9c, 0x4e, 0x12, 0x97, 0xb6, 0xe8, 0x8a, 0x40, 0x1d, 0xe2, 0x98, 0x92, 0x52, 0x94, - 0x5a, 0x5c, 0x1c, 0x5c, 0x52, 0x94, 0x99, 0x97, 0x1e, 0x84, 0x50, 0x2a, 0x64, 0xce, 0xc5, 0x96, - 0x98, 0x9b, 0x5f, 0x9a, 0x57, 0x22, 0xc1, 0xa4, 0xc0, 0xa8, 0xc1, 0x6d, 0x24, 0xa9, 0x07, 0xd5, - 0x01, 0x72, 0x2c, 0xcc, 0x73, 0x7a, 0xce, 0xf9, 0x99, 0x79, 0x4e, 0x2c, 0x27, 0xee, 0xc9, 0x33, - 0x04, 0x41, 0x95, 0x5b, 0xb1, 0x74, 0x2c, 0x90, 0x67, 0x50, 0x0a, 0xe4, 0x12, 0x42, 0x38, 0x22, - 0x28, 0xb5, 0xb8, 0x20, 0x3f, 0xaf, 0x38, 0x55, 0xc8, 0x9a, 0x8b, 0xad, 0x38, 0x23, 0xb1, 0x28, - 0xb5, 0x18, 0xec, 0x12, 0x6e, 0x23, 0x59, 0x3d, 0x8c, 0xf0, 0xd2, 0x0b, 0x03, 0xf9, 0x25, 0x18, - 0xa4, 0x0a, 0x66, 0x30, 0x44, 0x8b, 0x52, 0x15, 0x17, 0xb7, 0x6f, 0x71, 0x7a, 0x78, 0x66, 0x49, - 0x46, 0x4a, 0x51, 0x62, 0xb9, 0x90, 0x0e, 0x17, 0x4b, 0x5a, 0x51, 0x7e, 0x2e, 0x41, 0x3f, 0x81, - 0x55, 0x51, 0xea, 0x9d, 0x20, 0x2e, 0x61, 0x24, 0xbb, 0xa9, 0xe2, 0x1f, 0xa3, 0x55, 0x8c, 0x5c, - 0xcc, 0xbe, 0xc5, 0xe9, 0x42, 0xfe, 0x5c, 0xec, 0xb0, 0xc8, 0xc2, 0xa6, 0x1f, 0x11, 0x8c, 0x52, - 0xaa, 0x78, 0xa5, 0xe1, 0xae, 0x0a, 0xe2, 0xe2, 0x80, 0x87, 0x92, 0x1c, 0x76, 0x2d, 0x30, 0x79, - 0x29, 0x35, 0xfc, 0xf2, 0x30, 0x33, 0x9d, 0x1c, 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, - 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, - 0x8e, 0x21, 0x4a, 0x2d, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0x1f, 0x64, - 0x96, 0x6e, 0x4e, 0x62, 0x52, 0x31, 0x98, 0xa5, 0x5f, 0x01, 0x49, 0xa5, 0x25, 0x95, 0x05, 0xa9, - 0xc5, 0x49, 0x6c, 0xe0, 0xe4, 0x69, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xb4, 0xb0, 0x19, 0x18, - 0x3f, 0x03, 0x00, 0x00, + // 443 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x93, 0x41, 0x8b, 0xd3, 0x40, + 0x14, 0xc7, 0x33, 0x6e, 0xa9, 0xbb, 0x53, 0x10, 0x1c, 0xf7, 0xd0, 0x0d, 0xec, 0xb4, 0x14, 0x5c, + 0x7a, 0x70, 0x27, 0x6c, 0x05, 0x05, 0xf7, 0xa2, 0xd5, 0x6b, 0x11, 0x53, 0x51, 0xf0, 0x22, 0x93, + 0x66, 0x9c, 0x06, 0x37, 0x99, 0x30, 0x6f, 0x5a, 0xb7, 0xdf, 0xc0, 0xa3, 0x1f, 0xc1, 0xb3, 0x67, + 0xc1, 0xab, 0xc7, 0x3d, 0x2e, 0x9e, 0x3c, 0x89, 0xb4, 0x5f, 0x44, 0x92, 0x99, 0xa4, 0x42, 0xcb, + 0x7a, 0x11, 0xf6, 0xf6, 0x26, 0xff, 0xdf, 0xff, 0xe5, 0xbd, 0x7f, 0x32, 0xd8, 0x7f, 0xcf, 0xe7, + 0x3c, 0x10, 0x5c, 0x67, 0xc1, 0xfc, 0x24, 0x12, 0x86, 0x9f, 0x04, 0xe6, 0x9c, 0xe5, 0x5a, 0x19, + 0x45, 0x6e, 0x17, 0x1a, 0x2b, 0x34, 0xe6, 0x34, 0xff, 0x60, 0xa2, 0x20, 0x55, 0xf0, 0xb6, 0x04, + 0x02, 0x7b, 0xb0, 0xb4, 0x4f, 0xed, 0x29, 0x88, 0x38, 0x88, 0xba, 0xd7, 0x44, 0x25, 0x99, 0xd3, + 0xf7, 0xa5, 0x92, 0xca, 0xfa, 0x8a, 0xca, 0x3d, 0xed, 0x6e, 0xbe, 0x1f, 0x8c, 0xe6, 0x46, 0xc8, + 0x85, 0x23, 0x0e, 0x37, 0x89, 0x39, 0x9f, 0x9d, 0x19, 0x2b, 0xf7, 0xbe, 0x23, 0x8c, 0x47, 0x20, + 0x9f, 0x89, 0x5c, 0x41, 0x62, 0xc8, 0x03, 0xbc, 0x17, 0xdb, 0x52, 0xe9, 0x36, 0xea, 0xa2, 0xfe, + 0xde, 0xb0, 0xfd, 0xe3, 0xeb, 0xf1, 0xbe, 0x1b, 0xf5, 0x49, 0x1c, 0x6b, 0x01, 0x30, 0x36, 0x3a, + 0xc9, 0x64, 0xb8, 0x46, 0xc9, 0x43, 0xdc, 0xe4, 0xa9, 0x9a, 0x65, 0xa6, 0x7d, 0xa3, 0x8b, 0xfa, + 0xad, 0xc1, 0x01, 0x73, 0x8e, 0x62, 0x9d, 0x6a, 0x7d, 0xf6, 0x54, 0x25, 0xd9, 0xb0, 0x71, 0xf1, + 0xab, 0xe3, 0x85, 0x0e, 0x27, 0xa7, 0x78, 0xb7, 0x1a, 0xb8, 0xbd, 0xd3, 0x45, 0xfd, 0x5b, 0x83, + 0x0e, 0xdb, 0xc8, 0x8d, 0x8d, 0x1d, 0xf2, 0x72, 0x91, 0x8b, 0xb0, 0x36, 0x3c, 0x6a, 0x7c, 0xfc, + 0xdc, 0xf1, 0x7a, 0x2f, 0x30, 0x59, 0x6f, 0x10, 0x0a, 0xc8, 0x55, 0x06, 0x82, 0x9c, 0xe2, 0x26, + 0x4c, 0xb9, 0x16, 0x50, 0xae, 0xd1, 0x1a, 0x1c, 0x6e, 0x69, 0xfb, 0xaa, 0x08, 0x62, 0x5c, 0x50, + 0xd5, 0x54, 0xd6, 0xd2, 0xfb, 0x86, 0x70, 0x6b, 0x04, 0xf2, 0x75, 0x62, 0xa6, 0xb1, 0xe6, 0x1f, + 0xc8, 0x3d, 0xdc, 0x78, 0xa7, 0x55, 0xfa, 0xcf, 0x44, 0x4a, 0xea, 0x5a, 0xc3, 0x08, 0xf1, 0x9d, + 0xbf, 0x06, 0xff, 0x2f, 0x69, 0x0c, 0xbe, 0x20, 0xbc, 0x33, 0x02, 0x49, 0x9e, 0xe3, 0x9b, 0xd5, + 0x7f, 0xb2, 0xcd, 0xbf, 0xfe, 0x08, 0xfe, 0xdd, 0x2b, 0xe5, 0x7a, 0xaa, 0x10, 0xef, 0xd6, 0x11, + 0xd3, 0xed, 0x96, 0x4a, 0xf7, 0x8f, 0xae, 0xd6, 0xab, 0x9e, 0xc3, 0xc7, 0x17, 0x4b, 0x8a, 0x2e, + 0x97, 0x14, 0xfd, 0x5e, 0x52, 0xf4, 0x69, 0x45, 0xbd, 0xcb, 0x15, 0xf5, 0x7e, 0xae, 0xa8, 0xf7, + 0xe6, 0x48, 0x26, 0x66, 0x3a, 0x8b, 0xd8, 0x44, 0xa5, 0x41, 0xd1, 0xeb, 0xf8, 0x8c, 0x47, 0x50, + 0x56, 0xc1, 0xb9, 0xbd, 0x20, 0x66, 0x91, 0x0b, 0x88, 0x9a, 0xe5, 0xcd, 0xb8, 0xff, 0x27, 0x00, + 0x00, 0xff, 0xff, 0x23, 0xf1, 0x3e, 0x54, 0xdc, 0x03, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -383,6 +389,11 @@ func (m *MsgDeposit) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Strategy != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Strategy)) + i-- + dAtA[i] = 0x18 + } { size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -456,6 +467,11 @@ func (m *MsgWithdraw) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Strategy != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Strategy)) + i-- + dAtA[i] = 0x18 + } { size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -532,6 +548,9 @@ func (m *MsgDeposit) Size() (n int) { } l = m.Amount.Size() n += 1 + l + sovTx(uint64(l)) + if m.Strategy != 0 { + n += 1 + sovTx(uint64(m.Strategy)) + } return n } @@ -558,6 +577,9 @@ func (m *MsgWithdraw) Size() (n int) { } l = m.Amount.Size() n += 1 + l + sovTx(uint64(l)) + if m.Strategy != 0 { + n += 1 + sovTx(uint64(m.Strategy)) + } return n } @@ -672,6 +694,25 @@ func (m *MsgDeposit) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Strategy", wireType) + } + m.Strategy = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Strategy |= StrategyType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -870,6 +911,25 @@ func (m *MsgWithdraw) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Strategy", wireType) + } + m.Strategy = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Strategy |= StrategyType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/x/earn/types/vault.go b/x/earn/types/vault.go index b3bde787..2117c1fc 100644 --- a/x/earn/types/vault.go +++ b/x/earn/types/vault.go @@ -86,15 +86,17 @@ func (vsrs VaultShareRecords) Validate() error { } // NewAllowedVaults returns a new AllowedVaults with the given denom and strategy type. -func NewAllowedVault(denom string, strategyType StrategyType) AllowedVault { +func NewAllowedVault(denom string, strategyTypes ...StrategyType) AllowedVault { return AllowedVault{ - Denom: denom, - VaultStrategy: strategyType, + Denom: denom, + Strategies: strategyTypes, } } +// AllowedVaults is a slice of AllowedVault. type AllowedVaults []AllowedVault +// Validate returns an error if the AllowedVaults is invalid. func (a AllowedVaults) Validate() error { denoms := make(map[string]bool) @@ -109,17 +111,27 @@ func (a AllowedVaults) Validate() error { denoms[v.Denom] = true } + return nil } +// Validate returns an error if the AllowedVault is invalid func (a *AllowedVault) Validate() error { if err := sdk.ValidateDenom(a.Denom); err != nil { return sdkerrors.Wrap(ErrInvalidVaultDenom, err.Error()) } - if a.VaultStrategy == STRATEGY_TYPE_UNSPECIFIED { - return ErrInvalidVaultStrategy + return a.Strategies.Validate() +} + +// IsStrategyAllowed returns true if the given strategy type is allowed for the +// vault. +func (a *AllowedVault) IsStrategyAllowed(strategy StrategyType) bool { + for _, s := range a.Strategies { + if s == strategy { + return true + } } - return nil + return false } diff --git a/x/earn/types/vault.pb.go b/x/earn/types/vault.pb.go index b1f21324..0cc9b5cf 100644 --- a/x/earn/types/vault.pb.go +++ b/x/earn/types/vault.pb.go @@ -32,7 +32,7 @@ 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 strategy used for this vault. - VaultStrategy StrategyType `protobuf:"varint,2,opt,name=vault_strategy,json=vaultStrategy,proto3,enum=kava.earn.v1beta1.StrategyType" json:"vault_strategy,omitempty"` + Strategies StrategyTypes `protobuf:"varint,2,rep,packed,name=strategies,proto3,enum=kava.earn.v1beta1.StrategyType,castrepeated=StrategyTypes" json:"strategies,omitempty"` } func (m *AllowedVault) Reset() { *m = AllowedVault{} } @@ -75,11 +75,11 @@ func (m *AllowedVault) GetDenom() string { return "" } -func (m *AllowedVault) GetVaultStrategy() StrategyType { +func (m *AllowedVault) GetStrategies() StrategyTypes { if m != nil { - return m.VaultStrategy + return m.Strategies } - return STRATEGY_TYPE_UNSPECIFIED + return nil } // VaultRecord is the state of a vault. @@ -238,35 +238,36 @@ func init() { func init() { proto.RegisterFile("kava/earn/v1beta1/vault.proto", fileDescriptor_884eb89509fbdc04) } var fileDescriptor_884eb89509fbdc04 = []byte{ - // 445 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x31, 0x8f, 0xd3, 0x30, - 0x18, 0x4d, 0x8e, 0xa3, 0x52, 0x9d, 0x72, 0x82, 0xdc, 0x0d, 0xc7, 0x49, 0x4d, 0xa2, 0x0c, 0xa8, - 0x4b, 0x12, 0xb5, 0x6c, 0x88, 0x81, 0x46, 0x55, 0x85, 0x18, 0xd3, 0xc2, 0xc0, 0x52, 0x39, 0x8e, - 0x49, 0xab, 0x26, 0x71, 0x14, 0xbb, 0x85, 0x2c, 0xfc, 0x06, 0x46, 0x46, 0x66, 0xe6, 0xfe, 0x06, - 0xd4, 0xb1, 0xea, 0x84, 0x18, 0x0a, 0x6a, 0xff, 0x05, 0x13, 0xb2, 0xe3, 0x12, 0xa4, 0x82, 0xb8, - 0x29, 0xf6, 0xfb, 0xde, 0x7b, 0xdf, 0xfb, 0xf2, 0x19, 0xb4, 0xe7, 0x70, 0x09, 0x3d, 0x0c, 0x8b, - 0xcc, 0x5b, 0x76, 0x43, 0xcc, 0x60, 0xd7, 0x5b, 0xc2, 0x45, 0xc2, 0xdc, 0xbc, 0x20, 0x8c, 0xe8, - 0x0f, 0x78, 0xd9, 0xe5, 0x65, 0x57, 0x96, 0x6f, 0x1e, 0x22, 0x42, 0x53, 0x42, 0x27, 0x82, 0xe0, - 0x55, 0x97, 0x8a, 0x7d, 0x63, 0x54, 0x37, 0x2f, 0x84, 0x14, 0xff, 0xb6, 0x43, 0x64, 0x96, 0xc9, - 0xfa, 0x55, 0x4c, 0x62, 0x52, 0xe9, 0xf8, 0x49, 0xa2, 0xd6, 0x69, 0x04, 0xca, 0x0a, 0xc8, 0x70, - 0x5c, 0x56, 0x0c, 0x3b, 0x01, 0xad, 0x7e, 0x92, 0x90, 0xb7, 0x38, 0x7a, 0xc5, 0xb3, 0xe9, 0x57, - 0xe0, 0x6e, 0x84, 0x33, 0x92, 0x5e, 0xab, 0x96, 0xda, 0x69, 0x06, 0xd5, 0x45, 0x1f, 0x82, 0x0b, - 0x11, 0x7d, 0x72, 0x54, 0x5f, 0x9f, 0x59, 0x6a, 0xe7, 0xa2, 0x67, 0xba, 0x27, 0x43, 0xb8, 0x23, - 0x49, 0x19, 0x97, 0x39, 0x0e, 0xee, 0x09, 0xd9, 0x11, 0xb2, 0x5f, 0x02, 0x4d, 0xb4, 0x09, 0x30, - 0x22, 0x45, 0xa4, 0x0f, 0x41, 0x8b, 0x11, 0x06, 0x93, 0x09, 0x9d, 0xc2, 0x02, 0x53, 0xd1, 0x53, - 0xeb, 0xb5, 0xff, 0x62, 0x2a, 0x54, 0x23, 0xce, 0xf2, 0xcf, 0xd7, 0x3b, 0x53, 0x09, 0x34, 0x21, - 0x14, 0x08, 0xb5, 0xbf, 0xa8, 0xe0, 0x7e, 0xcd, 0x90, 0xe6, 0x6f, 0x40, 0x33, 0xc2, 0x39, 0xa1, - 0x33, 0x46, 0x0a, 0xe1, 0xdc, 0xf2, 0x9f, 0xff, 0xdc, 0x99, 0x4e, 0x3c, 0x63, 0xd3, 0x45, 0xe8, - 0x22, 0x92, 0xca, 0x3f, 0x2c, 0x3f, 0x0e, 0x8d, 0xe6, 0x1e, 0x2b, 0x73, 0x4c, 0xdd, 0x3e, 0x42, - 0xfd, 0x28, 0x2a, 0x30, 0xa5, 0xdb, 0x95, 0x73, 0x29, 0xf7, 0x20, 0x11, 0xbf, 0x64, 0x98, 0x06, - 0xb5, 0xb5, 0xfe, 0x02, 0x34, 0x64, 0xfc, 0x33, 0xeb, 0xce, 0xff, 0xe3, 0x5f, 0xf2, 0xf8, 0x9f, - 0xbf, 0x9b, 0x5a, 0x8d, 0xd1, 0x40, 0x3a, 0xd8, 0xef, 0x01, 0xa8, 0xe1, 0x7f, 0xec, 0x62, 0x0c, - 0x1a, 0x30, 0x25, 0x8b, 0x8c, 0x89, 0x1d, 0x34, 0xfd, 0xa7, 0xdc, 0xf0, 0xdb, 0xce, 0x7c, 0x74, - 0x8b, 0xc1, 0x06, 0x18, 0x6d, 0x57, 0x0e, 0x90, 0x13, 0x0d, 0x30, 0x0a, 0xa4, 0xd7, 0x93, 0xf3, - 0x8f, 0x9f, 0x4c, 0xc5, 0x7f, 0xb6, 0xde, 0x1b, 0xea, 0x66, 0x6f, 0xa8, 0x3f, 0xf6, 0x86, 0xfa, - 0xe1, 0x60, 0x28, 0x9b, 0x83, 0xa1, 0x7c, 0x3d, 0x18, 0xca, 0xeb, 0x3f, 0xdd, 0xf9, 0x7c, 0x4e, - 0x02, 0x43, 0x2a, 0x4e, 0xde, 0xbb, 0xea, 0x81, 0x89, 0x0e, 0x61, 0x43, 0x3c, 0xab, 0xc7, 0xbf, - 0x02, 0x00, 0x00, 0xff, 0xff, 0x19, 0x75, 0x6f, 0x0e, 0xfd, 0x02, 0x00, 0x00, + // 450 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x31, 0x6f, 0xd3, 0x40, + 0x14, 0xc7, 0xed, 0x52, 0x22, 0xf5, 0x1c, 0x10, 0x75, 0x3b, 0x84, 0x4a, 0xb5, 0x23, 0x0f, 0xa8, + 0x8b, 0x6d, 0xb5, 0x6c, 0x88, 0x81, 0x58, 0x15, 0x42, 0x8c, 0xd7, 0xc2, 0xc0, 0x52, 0x9d, 0xcf, + 0x87, 0x6b, 0xd5, 0xf6, 0x45, 0x7e, 0x97, 0x90, 0x2c, 0x7c, 0x06, 0x46, 0x46, 0xe6, 0xcc, 0xf9, + 0x0c, 0x28, 0x63, 0x94, 0x09, 0x31, 0x24, 0x28, 0xf9, 0x16, 0x4c, 0xe8, 0xce, 0x27, 0x1c, 0x29, + 0x20, 0x98, 0xec, 0xf7, 0x7f, 0xef, 0xfd, 0xde, 0xff, 0xdd, 0x1d, 0x3a, 0xbd, 0x23, 0x43, 0x12, + 0x32, 0x52, 0x95, 0xe1, 0xf0, 0x3c, 0x66, 0x82, 0x9c, 0x87, 0x43, 0x32, 0xc8, 0x45, 0xd0, 0xaf, + 0xb8, 0xe0, 0xf6, 0xa1, 0x4c, 0x07, 0x32, 0x1d, 0xe8, 0xf4, 0xc9, 0x63, 0xca, 0xa1, 0xe0, 0x70, + 0xa3, 0x0a, 0xc2, 0x3a, 0xa8, 0xab, 0x4f, 0x9c, 0x3a, 0x0a, 0x63, 0x02, 0xec, 0x37, 0x8e, 0xf2, + 0xac, 0xd4, 0xf9, 0xe3, 0x94, 0xa7, 0xbc, 0xee, 0x93, 0x7f, 0x5a, 0xed, 0xee, 0x5a, 0x00, 0x51, + 0x11, 0xc1, 0xd2, 0x71, 0x5d, 0xe1, 0x8d, 0x50, 0xbb, 0x97, 0xe7, 0xfc, 0x03, 0x4b, 0xde, 0x4a, + 0x6f, 0xf6, 0x31, 0xba, 0x9f, 0xb0, 0x92, 0x17, 0x1d, 0xb3, 0x6b, 0x9e, 0x1d, 0xe0, 0x3a, 0xb0, + 0x31, 0x42, 0xba, 0x2f, 0x63, 0xd0, 0xd9, 0xeb, 0xde, 0x3b, 0x7b, 0x78, 0xe1, 0x06, 0x3b, 0x0b, + 0x04, 0x57, 0x1a, 0x7e, 0x3d, 0xee, 0xb3, 0xe8, 0x70, 0xb2, 0x72, 0x1f, 0x6c, 0x2b, 0x80, 0xb7, + 0x28, 0xde, 0x1b, 0x64, 0xa9, 0x91, 0x98, 0x51, 0x5e, 0x25, 0xf6, 0x4b, 0xd4, 0x16, 0x5c, 0x90, + 0xfc, 0x06, 0x6e, 0x49, 0xc5, 0x40, 0xcd, 0xb7, 0x2e, 0x4e, 0xff, 0x30, 0x44, 0x75, 0x5d, 0xc9, + 0xaa, 0x68, 0x7f, 0xb6, 0x74, 0x0d, 0x6c, 0xa9, 0x46, 0xa5, 0x80, 0xf7, 0xd5, 0x44, 0x8f, 0x9a, + 0x0a, 0x0d, 0x7f, 0x8f, 0x0e, 0x12, 0xd6, 0xe7, 0x90, 0x09, 0x5e, 0x29, 0x72, 0x3b, 0x7a, 0xf5, + 0x73, 0xe9, 0xfa, 0x69, 0x26, 0x6e, 0x07, 0x71, 0x40, 0x79, 0xa1, 0x4f, 0x5b, 0x7f, 0x7c, 0x48, + 0xee, 0x42, 0x21, 0x2d, 0x07, 0x3d, 0x4a, 0x7b, 0x49, 0x52, 0x31, 0x80, 0xc5, 0xd4, 0x3f, 0xd2, + 0x77, 0xa2, 0x95, 0x68, 0x2c, 0x18, 0xe0, 0x06, 0x6d, 0xbf, 0x46, 0x2d, 0x6d, 0x5f, 0x9e, 0xd1, + 0x3f, 0xed, 0x1f, 0x49, 0xfb, 0x93, 0x95, 0x6b, 0x35, 0x1a, 0x60, 0x4d, 0xf0, 0x3e, 0x22, 0xd4, + 0xc8, 0x7f, 0xb9, 0x97, 0x6b, 0xd4, 0x22, 0x05, 0x1f, 0x94, 0xa2, 0xb3, 0x27, 0xe5, 0xe8, 0xb9, + 0x04, 0x7e, 0x5f, 0xba, 0x4f, 0xfe, 0x63, 0xb1, 0x4b, 0x46, 0x17, 0x53, 0x1f, 0xe9, 0x8d, 0x2e, + 0x19, 0xc5, 0x9a, 0xf5, 0x6c, 0xff, 0xf3, 0x17, 0xd7, 0x88, 0x5e, 0xcc, 0xd6, 0x8e, 0x39, 0x5f, + 0x3b, 0xe6, 0x8f, 0xb5, 0x63, 0x7e, 0xda, 0x38, 0xc6, 0x7c, 0xe3, 0x18, 0xdf, 0x36, 0x8e, 0xf1, + 0x6e, 0x9b, 0x2e, 0xf7, 0xf3, 0x73, 0x12, 0x83, 0xfa, 0x0b, 0x47, 0xf5, 0x63, 0x53, 0x13, 0xe2, + 0x96, 0x7a, 0x62, 0x4f, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0xae, 0x23, 0x43, 0xb6, 0x09, 0x03, + 0x00, 0x00, } func (m *AllowedVault) Marshal() (dAtA []byte, err error) { @@ -289,10 +290,23 @@ func (m *AllowedVault) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.VaultStrategy != 0 { - i = encodeVarintVault(dAtA, i, uint64(m.VaultStrategy)) + if len(m.Strategies) > 0 { + dAtA2 := make([]byte, len(m.Strategies)*10) + var j1 int + for _, num := range m.Strategies { + for num >= 1<<7 { + dAtA2[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA2[j1] = uint8(num) + j1++ + } + i -= j1 + copy(dAtA[i:], dAtA2[:j1]) + i = encodeVarintVault(dAtA, i, uint64(j1)) i-- - dAtA[i] = 0x10 + dAtA[i] = 0x12 } if len(m.Denom) > 0 { i -= len(m.Denom) @@ -442,8 +456,12 @@ func (m *AllowedVault) Size() (n int) { if l > 0 { n += 1 + l + sovVault(uint64(l)) } - if m.VaultStrategy != 0 { - n += 1 + sovVault(uint64(m.VaultStrategy)) + if len(m.Strategies) > 0 { + l = 0 + for _, e := range m.Strategies { + l += sovVault(uint64(e)) + } + n += 1 + sovVault(uint64(l)) + l } return n } @@ -561,23 +579,73 @@ func (m *AllowedVault) Unmarshal(dAtA []byte) error { 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 wireType == 0 { + var v StrategyType + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVault + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= StrategyType(b&0x7F) << shift + if b < 0x80 { + break + } } - if iNdEx >= l { + m.Strategies = append(m.Strategies, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVault + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthVault + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthVault + } + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - m.VaultStrategy |= StrategyType(b&0x7F) << shift - if b < 0x80 { - break + var elementCount int + if elementCount != 0 && len(m.Strategies) == 0 { + m.Strategies = make([]StrategyType, 0, elementCount) } + for iNdEx < postIndex { + var v StrategyType + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVault + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= StrategyType(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Strategies = append(m.Strategies, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field Strategies", wireType) } default: iNdEx = preIndex diff --git a/x/earn/types/vault_test.go b/x/earn/types/vault_test.go index 3eec396a..cdeaeb55 100644 --- a/x/earn/types/vault_test.go +++ b/x/earn/types/vault_test.go @@ -208,12 +208,12 @@ func TestAllowedVaultsValidate(t *testing.T) { name: "valid vault share records", vaultRecords: types.AllowedVaults{ { - Denom: "usdx", - VaultStrategy: types.STRATEGY_TYPE_HARD, + Denom: "usdx", + Strategies: []types.StrategyType{types.STRATEGY_TYPE_HARD}, }, { - Denom: "busd", - VaultStrategy: types.STRATEGY_TYPE_HARD, + Denom: "busd", + Strategies: []types.StrategyType{types.STRATEGY_TYPE_HARD}, }, }, errArgs: errArgs{ @@ -224,12 +224,12 @@ func TestAllowedVaultsValidate(t *testing.T) { name: "invalid - duplicate denom", vaultRecords: types.AllowedVaults{ { - Denom: "usdx", - VaultStrategy: types.STRATEGY_TYPE_HARD, + Denom: "usdx", + Strategies: []types.StrategyType{types.STRATEGY_TYPE_HARD}, }, { - Denom: "usdx", - VaultStrategy: types.STRATEGY_TYPE_HARD, + Denom: "usdx", + Strategies: []types.StrategyType{types.STRATEGY_TYPE_HARD}, }, }, errArgs: errArgs{ @@ -241,8 +241,8 @@ func TestAllowedVaultsValidate(t *testing.T) { name: "invalid - invalid denom", vaultRecords: types.AllowedVaults{ { - Denom: "", - VaultStrategy: types.STRATEGY_TYPE_HARD, + Denom: "", + Strategies: []types.StrategyType{types.STRATEGY_TYPE_HARD}, }, }, errArgs: errArgs{ @@ -254,13 +254,13 @@ func TestAllowedVaultsValidate(t *testing.T) { name: "invalid - invalid strategy", vaultRecords: types.AllowedVaults{ { - Denom: "usdx", - VaultStrategy: types.STRATEGY_TYPE_UNSPECIFIED, + Denom: "usdx", + Strategies: []types.StrategyType{types.STRATEGY_TYPE_UNSPECIFIED}, }, }, errArgs: errArgs{ expectPass: false, - contains: "invalid vault strategy", + contains: "invalid strategy STRATEGY_TYPE_UNSPECIFIED", }, }, }