diff --git a/app/app.go b/app/app.go
index 3b07e7da..152b5f8e 100644
--- a/app/app.go
+++ b/app/app.go
@@ -107,6 +107,7 @@ import (
committeekeeper "github.com/kava-labs/kava/x/committee/keeper"
committeetypes "github.com/kava-labs/kava/x/committee/types"
earn "github.com/kava-labs/kava/x/earn"
+ earnclient "github.com/kava-labs/kava/x/earn/client"
earnkeeper "github.com/kava-labs/kava/x/earn/keeper"
earntypes "github.com/kava-labs/kava/x/earn/types"
evmutil "github.com/kava-labs/kava/x/evmutil"
@@ -171,6 +172,8 @@ var (
ibcclientclient.UpgradeProposalHandler,
kavadistclient.ProposalHandler,
committeeclient.ProposalHandler,
+ earnclient.DepositProposalHandler,
+ earnclient.WithdrawProposalHandler,
),
params.AppModuleBasic{},
crisis.AppModuleBasic{},
@@ -225,6 +228,7 @@ var (
savingstypes.ModuleAccountName: nil,
liquidtypes.ModuleAccountName: {authtypes.Minter, authtypes.Burner},
earntypes.ModuleAccountName: nil,
+ kavadisttypes.FundModuleAccount: nil,
}
)
@@ -613,6 +617,7 @@ func NewApp(
&app.liquidKeeper,
&hardKeeper,
&savingsKeeper,
+ app.distrKeeper,
)
app.incentiveKeeper = incentivekeeper.NewKeeper(
@@ -652,26 +657,6 @@ func NewApp(
app.accountKeeper,
app.bankKeeper,
)
- // create gov keeper with router
- // NOTE this must be done after any keepers referenced in the gov router (ie committee) are defined
- govRouter := govtypes.NewRouter()
- govRouter.
- AddRoute(govtypes.RouterKey, govtypes.ProposalHandler).
- AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.paramsKeeper)).
- AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.upgradeKeeper)).
- AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.ibcKeeper.ClientKeeper)).
- AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.distrKeeper)).
- AddRoute(kavadisttypes.RouterKey, kavadist.NewCommunityPoolMultiSpendProposalHandler(app.kavadistKeeper)).
- AddRoute(committeetypes.RouterKey, committee.NewProposalHandler(app.committeeKeeper))
- app.govKeeper = govkeeper.NewKeeper(
- appCodec,
- keys[govtypes.StoreKey],
- govSubspace,
- app.accountKeeper,
- app.bankKeeper,
- &app.stakingKeeper,
- govRouter,
- )
// register the staking hooks
// NOTE: These keepers are passed by reference above, so they will contain these hooks.
@@ -684,6 +669,28 @@ func NewApp(
app.savingsKeeper = *savingsKeeper.SetHooks(savingstypes.NewMultiSavingsHooks(app.incentiveKeeper.Hooks()))
app.earnKeeper = *earnKeeper.SetHooks(app.incentiveKeeper.Hooks())
+ // create gov keeper with router
+ // NOTE this must be done after any keepers referenced in the gov router (ie committee) are defined
+ govRouter := govtypes.NewRouter()
+ govRouter.
+ AddRoute(govtypes.RouterKey, govtypes.ProposalHandler).
+ AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.paramsKeeper)).
+ AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.upgradeKeeper)).
+ AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.ibcKeeper.ClientKeeper)).
+ AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.distrKeeper)).
+ AddRoute(kavadisttypes.RouterKey, kavadist.NewCommunityPoolMultiSpendProposalHandler(app.kavadistKeeper)).
+ AddRoute(earntypes.RouterKey, earn.NewCommunityPoolProposalHandler(app.earnKeeper)).
+ AddRoute(committeetypes.RouterKey, committee.NewProposalHandler(app.committeeKeeper))
+ app.govKeeper = govkeeper.NewKeeper(
+ appCodec,
+ keys[govtypes.StoreKey],
+ govSubspace,
+ app.accountKeeper,
+ app.bankKeeper,
+ &app.stakingKeeper,
+ govRouter,
+ )
+
// override x/gov tally handler with custom implementation
tallyHandler := NewTallyHandler(
app.govKeeper, app.stakingKeeper, app.savingsKeeper, app.earnKeeper,
@@ -1023,10 +1030,11 @@ func (app *App) loadBlockedMaccAddrs() map[string]bool {
kavadistMaccAddr := app.accountKeeper.GetModuleAddress(kavadisttypes.ModuleName)
earnMaccAddr := app.accountKeeper.GetModuleAddress(earntypes.ModuleName)
liquidMaccAddr := app.accountKeeper.GetModuleAddress(liquidtypes.ModuleName)
+ kavadistFundMaccAddr := app.accountKeeper.GetModuleAddress(kavadisttypes.FundModuleAccount)
for addr := range modAccAddrs {
// Set the kavadist and earn module account address as unblocked
- if addr == kavadistMaccAddr.String() || addr == earnMaccAddr.String() || addr == liquidMaccAddr.String() {
+ if addr == kavadistMaccAddr.String() || addr == earnMaccAddr.String() || addr == liquidMaccAddr.String() || addr == kavadistFundMaccAddr.String() {
modAccAddrs[addr] = false
}
}
diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md
index b0dff491..5df5ca12 100644
--- a/docs/core/proto-docs.md
+++ b/docs/core/proto-docs.md
@@ -193,6 +193,12 @@
- [kava/earn/v1beta1/genesis.proto](#kava/earn/v1beta1/genesis.proto)
- [GenesisState](#kava.earn.v1beta1.GenesisState)
+- [kava/earn/v1beta1/proposal.proto](#kava/earn/v1beta1/proposal.proto)
+ - [CommunityPoolDepositProposal](#kava.earn.v1beta1.CommunityPoolDepositProposal)
+ - [CommunityPoolDepositProposalJSON](#kava.earn.v1beta1.CommunityPoolDepositProposalJSON)
+ - [CommunityPoolWithdrawProposal](#kava.earn.v1beta1.CommunityPoolWithdrawProposal)
+ - [CommunityPoolWithdrawProposalJSON](#kava.earn.v1beta1.CommunityPoolWithdrawProposalJSON)
+
- [kava/earn/v1beta1/query.proto](#kava/earn/v1beta1/query.proto)
- [DepositResponse](#kava.earn.v1beta1.DepositResponse)
- [QueryDepositsRequest](#kava.earn.v1beta1.QueryDepositsRequest)
@@ -2950,6 +2956,92 @@ GenesisState defines the earn module's genesis state.
+
+
+
+
+
+
+
+
+
+
+
+
Top
+
+## kava/earn/v1beta1/proposal.proto
+
+
+
+
+
+### CommunityPoolDepositProposal
+CommunityPoolDepositProposal deposits from the community pool into an earn vault
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `title` | [string](#string) | | |
+| `description` | [string](#string) | | |
+| `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | |
+
+
+
+
+
+
+
+
+### CommunityPoolDepositProposalJSON
+CommunityPoolDepositProposalJSON defines a CommunityPoolDepositProposal with a deposit
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `title` | [string](#string) | | |
+| `description` | [string](#string) | | |
+| `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | |
+| `deposit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | |
+
+
+
+
+
+
+
+
+### CommunityPoolWithdrawProposal
+CommunityPoolWithdrawProposal withdraws from an earn vault back to community pool
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `title` | [string](#string) | | |
+| `description` | [string](#string) | | |
+| `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | |
+
+
+
+
+
+
+
+
+### CommunityPoolWithdrawProposalJSON
+CommunityPoolWithdrawProposalJSON defines a CommunityPoolWithdrawProposal with a deposit
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `title` | [string](#string) | | |
+| `description` | [string](#string) | | |
+| `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | |
+| `deposit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | |
+
+
+
+
+
diff --git a/proto/kava/earn/v1beta1/proposal.proto b/proto/kava/earn/v1beta1/proposal.proto
new file mode 100644
index 00000000..a3c66ecf
--- /dev/null
+++ b/proto/kava/earn/v1beta1/proposal.proto
@@ -0,0 +1,51 @@
+syntax = "proto3";
+package kava.earn.v1beta1;
+
+import "gogoproto/gogo.proto";
+import "cosmos/base/v1beta1/coin.proto";
+
+option go_package = "github.com/kava-labs/kava/x/earn/types";
+
+// CommunityPoolDepositProposal deposits from the community pool into an earn vault
+message CommunityPoolDepositProposal {
+ option (gogoproto.goproto_stringer) = false;
+ option (gogoproto.goproto_getters) = false;
+
+ string title = 1;
+ string description = 2;
+ cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false];
+}
+
+// CommunityPoolDepositProposalJSON defines a CommunityPoolDepositProposal with a deposit
+message CommunityPoolDepositProposalJSON {
+ option (gogoproto.goproto_stringer) = true;
+ option (gogoproto.goproto_getters) = false;
+
+ string title = 1;
+ string description = 2;
+ cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false];
+ repeated cosmos.base.v1beta1.Coin deposit = 4
+ [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
+}
+
+// CommunityPoolWithdrawProposal withdraws from an earn vault back to community pool
+message CommunityPoolWithdrawProposal {
+ option (gogoproto.goproto_stringer) = false;
+ option (gogoproto.goproto_getters) = false;
+
+ string title = 1;
+ string description = 2;
+ cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false];
+}
+
+// CommunityPoolWithdrawProposalJSON defines a CommunityPoolWithdrawProposal with a deposit
+message CommunityPoolWithdrawProposalJSON {
+ option (gogoproto.goproto_stringer) = true;
+ option (gogoproto.goproto_getters) = false;
+
+ string title = 1;
+ string description = 2;
+ cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false];
+ repeated cosmos.base.v1beta1.Coin deposit = 4
+ [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
+}
\ No newline at end of file
diff --git a/x/earn/client/cli/tx.go b/x/earn/client/cli/tx.go
index 681f5053..9d667303 100644
--- a/x/earn/client/cli/tx.go
+++ b/x/earn/client/cli/tx.go
@@ -2,6 +2,7 @@ package cli
import (
"fmt"
+ "strings"
"github.com/spf13/cobra"
@@ -10,6 +11,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
+ govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/kava-labs/kava/x/earn/types"
)
@@ -109,3 +111,119 @@ func getCmdWithdraw() *cobra.Command {
},
}
}
+
+// GetCmdSubmitCommunityPoolDepositProposal implements the command to submit a community-pool deposit proposal
+func GetCmdSubmitCommunityPoolDepositProposal() *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "community-pool-deposit [proposal-file]",
+ Args: cobra.ExactArgs(1),
+ Short: "Submit a community pool deposit proposal",
+ Long: strings.TrimSpace(
+ fmt.Sprintf(`Submit a community pool deposit proposal along with an initial deposit.
+The proposal details must be supplied via a JSON file.
+Example:
+$ %s tx gov submit-proposal community-pool-deposit --from=
+Where proposal.json contains:
+{
+ "title": "Community Pool Deposit",
+ "description": "Deposit some KAVA from community pool!",
+ "amount":
+ {
+ "denom": "ukava",
+ "amount": "100000000000"
+ },
+ "deposit": [
+ {
+ "denom": "ukava",
+ "amount": "1000000000"
+ }
+ ]
+}
+`,
+ version.AppName,
+ ),
+ ),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ clientCtx, err := client.GetClientTxContext(cmd)
+ if err != nil {
+ return err
+ }
+ proposal, err := ParseCommunityPoolDepositProposalJSON(clientCtx.Codec, args[0])
+ if err != nil {
+ return err
+ }
+
+ from := clientCtx.GetFromAddress()
+ content := types.NewCommunityPoolDepositProposal(proposal.Title, proposal.Description, proposal.Amount)
+ msg, err := govtypes.NewMsgSubmitProposal(content, proposal.Deposit, from)
+ if err != nil {
+ return err
+ }
+ if err := msg.ValidateBasic(); err != nil {
+ return err
+ }
+
+ return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
+ },
+ }
+
+ return cmd
+}
+
+// GetCmdSubmitCommunityPoolWithdrawProposal implements the command to submit a community-pool withdraw proposal
+func GetCmdSubmitCommunityPoolWithdrawProposal() *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "community-pool-withdraw [proposal-file]",
+ Args: cobra.ExactArgs(1),
+ Short: "Submit a community pool withdraw proposal",
+ Long: strings.TrimSpace(
+ fmt.Sprintf(`Submit a community pool withdraw proposal along with an initial deposit.
+The proposal details must be supplied via a JSON file.
+Example:
+$ %s tx gov submit-proposal community-pool-withdraw --from=
+Where proposal.json contains:
+{
+ "title": "Community Pool Withdraw",
+ "description": "Withdraw some KAVA from community pool!",
+ "amount":
+ {
+ "denom": "ukava",
+ "amount": "100000000000"
+ },
+ "deposit": [
+ {
+ "denom": "ukava",
+ "amount": "1000000000"
+ }
+ ]
+}
+`,
+ version.AppName,
+ ),
+ ),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ clientCtx, err := client.GetClientTxContext(cmd)
+ if err != nil {
+ return err
+ }
+ proposal, err := ParseCommunityPoolWithdrawProposalJSON(clientCtx.Codec, args[0])
+ if err != nil {
+ return err
+ }
+
+ from := clientCtx.GetFromAddress()
+ content := types.NewCommunityPoolWithdrawProposal(proposal.Title, proposal.Description, proposal.Amount)
+ msg, err := govtypes.NewMsgSubmitProposal(content, proposal.Deposit, from)
+ if err != nil {
+ return err
+ }
+ if err := msg.ValidateBasic(); err != nil {
+ return err
+ }
+
+ return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
+ },
+ }
+
+ return cmd
+}
diff --git a/x/earn/client/cli/utils.go b/x/earn/client/cli/utils.go
new file mode 100644
index 00000000..c8693ec4
--- /dev/null
+++ b/x/earn/client/cli/utils.go
@@ -0,0 +1,39 @@
+package cli
+
+import (
+ "os"
+
+ "github.com/cosmos/cosmos-sdk/codec"
+
+ "github.com/kava-labs/kava/x/earn/types"
+)
+
+// ParseCommunityPoolDepositProposalJSON reads and parses a CommunityPoolDepositProposalJSON from a file.
+func ParseCommunityPoolDepositProposalJSON(cdc codec.JSONCodec, proposalFile string) (types.CommunityPoolDepositProposalJSON, error) {
+ proposal := types.CommunityPoolDepositProposalJSON{}
+ contents, err := os.ReadFile(proposalFile)
+ if err != nil {
+ return proposal, err
+ }
+
+ if err := cdc.UnmarshalJSON(contents, &proposal); err != nil {
+ return proposal, err
+ }
+
+ return proposal, nil
+}
+
+// ParseCommunityPoolWithdrawProposalJSON reads and parses a CommunityPoolWithdrawProposalJSON from a file.
+func ParseCommunityPoolWithdrawProposalJSON(cdc codec.JSONCodec, proposalFile string) (types.CommunityPoolWithdrawProposalJSON, error) {
+ proposal := types.CommunityPoolWithdrawProposalJSON{}
+ contents, err := os.ReadFile(proposalFile)
+ if err != nil {
+ return proposal, err
+ }
+
+ if err := cdc.UnmarshalJSON(contents, &proposal); err != nil {
+ return proposal, err
+ }
+
+ return proposal, nil
+}
diff --git a/x/earn/client/proposal_handler.go b/x/earn/client/proposal_handler.go
new file mode 100644
index 00000000..9d76d960
--- /dev/null
+++ b/x/earn/client/proposal_handler.go
@@ -0,0 +1,14 @@
+package client
+
+import (
+ govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
+
+ "github.com/kava-labs/kava/x/earn/client/cli"
+ "github.com/kava-labs/kava/x/earn/client/rest"
+)
+
+// community-pool deposit/withdraw proposal handlers
+var (
+ DepositProposalHandler = govclient.NewProposalHandler(cli.GetCmdSubmitCommunityPoolDepositProposal, rest.DepositProposalRESTHandler)
+ WithdrawProposalHandler = govclient.NewProposalHandler(cli.GetCmdSubmitCommunityPoolWithdrawProposal, rest.WithdrawProposalRESTHandler)
+)
diff --git a/x/earn/client/rest/rest.go b/x/earn/client/rest/rest.go
new file mode 100644
index 00000000..bff5052f
--- /dev/null
+++ b/x/earn/client/rest/rest.go
@@ -0,0 +1,97 @@
+package rest
+
+import (
+ "net/http"
+
+ "github.com/cosmos/cosmos-sdk/client"
+ "github.com/cosmos/cosmos-sdk/client/tx"
+ sdk "github.com/cosmos/cosmos-sdk/types"
+ "github.com/cosmos/cosmos-sdk/types/rest"
+ govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
+ govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
+
+ "github.com/kava-labs/kava/x/earn/types"
+)
+
+type (
+ // CommunityPoolDepositProposalReq defines a community pool deposit proposal request body.
+ CommunityPoolDepositProposalReq struct {
+ BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
+
+ Title string `json:"title" yaml:"title"`
+ Description string `json:"description" yaml:"description"`
+ Amount sdk.Coin `json:"amount" yaml:"amount"`
+ Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
+ Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"`
+ }
+ // CommunityPoolWithdrawProposalReq defines a community pool deposit proposal request body.
+ CommunityPoolWithdrawProposalReq struct {
+ BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
+
+ Title string `json:"title" yaml:"title"`
+ Description string `json:"description" yaml:"description"`
+ Amount sdk.Coin `json:"amount" yaml:"amount"`
+ Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
+ Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"`
+ }
+)
+
+// DepositProposalRESTHandler returns a ProposalRESTHandler that exposes the community pool deposit REST handler with a given sub-route.
+func DepositProposalRESTHandler(cliCtx client.Context) govrest.ProposalRESTHandler {
+ return govrest.ProposalRESTHandler{
+ SubRoute: types.ProposalTypeCommunityPoolDeposit,
+ Handler: postDepositProposalHandlerFn(cliCtx),
+ }
+}
+
+func postDepositProposalHandlerFn(cliCtx client.Context) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ var req CommunityPoolDepositProposalReq
+ if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
+ return
+ }
+ req.BaseReq = req.BaseReq.Sanitize()
+ if !req.BaseReq.ValidateBasic(w) {
+ return
+ }
+ content := types.NewCommunityPoolDepositProposal(req.Title, req.Description, req.Amount)
+ msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, req.Proposer)
+ if rest.CheckBadRequestError(w, err) {
+ return
+ }
+ if rest.CheckBadRequestError(w, msg.ValidateBasic()) {
+ return
+ }
+ tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg)
+ }
+}
+
+// WithdrawProposalRESTHandler returns a ProposalRESTHandler that exposes the community pool deposit REST handler with a given sub-route.
+func WithdrawProposalRESTHandler(cliCtx client.Context) govrest.ProposalRESTHandler {
+ return govrest.ProposalRESTHandler{
+ SubRoute: types.ProposalTypeCommunityPoolWithdraw,
+ Handler: postWithdrawProposalHandlerFn(cliCtx),
+ }
+}
+
+func postWithdrawProposalHandlerFn(cliCtx client.Context) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ var req CommunityPoolWithdrawProposalReq
+ if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
+ return
+ }
+ req.BaseReq = req.BaseReq.Sanitize()
+ if !req.BaseReq.ValidateBasic(w) {
+ return
+ }
+ content := types.NewCommunityPoolWithdrawProposal(req.Title, req.Description, req.Amount)
+ msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, req.Proposer)
+ if rest.CheckBadRequestError(w, err) {
+ return
+ }
+ if rest.CheckBadRequestError(w, msg.ValidateBasic()) {
+ return
+ }
+ tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg)
+ }
+}
diff --git a/x/earn/handler.go b/x/earn/handler.go
new file mode 100644
index 00000000..b6eac9a5
--- /dev/null
+++ b/x/earn/handler.go
@@ -0,0 +1,24 @@
+package earn
+
+import (
+ sdk "github.com/cosmos/cosmos-sdk/types"
+ sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
+ govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
+
+ "github.com/kava-labs/kava/x/earn/keeper"
+ "github.com/kava-labs/kava/x/earn/types"
+)
+
+// NewCommunityPoolProposalHandler
+func NewCommunityPoolProposalHandler(k keeper.Keeper) govtypes.Handler {
+ return func(ctx sdk.Context, content govtypes.Content) error {
+ switch c := content.(type) {
+ case *types.CommunityPoolDepositProposal:
+ return keeper.HandleCommunityPoolDepositProposal(ctx, k, c)
+ case *types.CommunityPoolWithdrawProposal:
+ return keeper.HandleCommunityPoolWithdrawProposal(ctx, k, c)
+ default:
+ return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized earn proposal content type: %T", c)
+ }
+ }
+}
diff --git a/x/earn/keeper/deposit.go b/x/earn/keeper/deposit.go
index 894e829f..143f2224 100644
--- a/x/earn/keeper/deposit.go
+++ b/x/earn/keeper/deposit.go
@@ -4,6 +4,7 @@ import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
+
"github.com/kava-labs/kava/x/earn/types"
)
@@ -112,3 +113,15 @@ func (k *Keeper) Deposit(
return nil
}
+
+// DepositFromModuleAccount adds the provided amount from a depositor module
+// account to a vault. The vault is specified by the denom in the amount.
+func (k *Keeper) DepositFromModuleAccount(
+ ctx sdk.Context,
+ from string,
+ wantAmount sdk.Coin,
+ withdrawStrategy types.StrategyType,
+) error {
+ addr := k.accountKeeper.GetModuleAddress(from)
+ return k.Deposit(ctx, addr, wantAmount, withdrawStrategy)
+}
diff --git a/x/earn/keeper/hooks_test.go b/x/earn/keeper/hooks_test.go
index 1bfb2252..63ef4aa4 100644
--- a/x/earn/keeper/hooks_test.go
+++ b/x/earn/keeper/hooks_test.go
@@ -172,7 +172,7 @@ func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
acc.GetAddress(),
shareRecord.AmountOf(deposit1Amount.Denom),
).Once()
- err = suite.Keeper.Withdraw(
+ _, err = suite.Keeper.Withdraw(
suite.Ctx,
acc.GetAddress(),
// 3 deposits, multiply original deposit amount by 3
@@ -196,7 +196,7 @@ func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
acc.GetAddress(),
shareRecord.AmountOf(deposit2Amount.Denom),
).Once()
- err = suite.Keeper.Withdraw(
+ _, err = suite.Keeper.Withdraw(
suite.Ctx,
acc.GetAddress(),
deposit2Amount,
@@ -219,7 +219,7 @@ func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
acc.GetAddress(),
shareRecord.AmountOf(deposit2Amount.Denom),
).Once()
- err = suite.Keeper.Withdraw(
+ _, err = suite.Keeper.Withdraw(
suite.Ctx,
acc.GetAddress(),
deposit2Amount,
@@ -242,7 +242,7 @@ func (suite *hookTestSuite) TestHooks_DepositAndWithdraw() {
acc.GetAddress(),
shareRecord.AmountOf(deposit2Amount.Denom),
).Once()
- err = suite.Keeper.Withdraw(
+ _, err = suite.Keeper.Withdraw(
suite.Ctx,
acc.GetAddress(),
deposit2Amount,
@@ -274,7 +274,7 @@ func (suite *hookTestSuite) TestHooks_NoPanicsOnNilHooks() {
suite.Require().NoError(err)
// BeforeVaultDepositModified should not panic if no hooks are registered
- err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount, types.STRATEGY_TYPE_HARD)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount, types.STRATEGY_TYPE_HARD)
suite.Require().NoError(err)
}
@@ -317,6 +317,6 @@ func (suite *hookTestSuite) TestHooks_HookOrdering() {
suite.Require().True(found, "expected after hook to be called after shares are updated")
suite.Require().Equal(depositAmount.Amount.MulRaw(2).ToDec(), shares.AmountOf(depositAmount.Denom))
})
- err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD)
suite.Require().NoError(err)
}
diff --git a/x/earn/keeper/keeper.go b/x/earn/keeper/keeper.go
index 22f55e1c..b9ffa3f0 100644
--- a/x/earn/keeper/keeper.go
+++ b/x/earn/keeper/keeper.go
@@ -21,6 +21,9 @@ type Keeper struct {
// Keepers used for strategies
hardKeeper types.HardKeeper
savingsKeeper types.SavingsKeeper
+
+ // Keeper for community pool transfers
+ distKeeper types.DistributionKeeper
}
// NewKeeper creates a new keeper
@@ -33,6 +36,7 @@ func NewKeeper(
liquidKeeper types.LiquidKeeper,
hardKeeper types.HardKeeper,
savingsKeeper types.SavingsKeeper,
+ distKeeper types.DistributionKeeper,
) Keeper {
if !paramstore.HasKeyTable() {
paramstore = paramstore.WithKeyTable(types.ParamKeyTable())
@@ -47,6 +51,7 @@ func NewKeeper(
liquidKeeper: liquidKeeper,
hardKeeper: hardKeeper,
savingsKeeper: savingsKeeper,
+ distKeeper: distKeeper,
}
}
diff --git a/x/earn/keeper/msg_server.go b/x/earn/keeper/msg_server.go
index 755cea85..1e719b99 100644
--- a/x/earn/keeper/msg_server.go
+++ b/x/earn/keeper/msg_server.go
@@ -53,7 +53,8 @@ func (m msgServer) Withdraw(goCtx context.Context, msg *types.MsgWithdraw) (*typ
return nil, err
}
- if err := m.keeper.Withdraw(ctx, from, msg.Amount, msg.Strategy); err != nil {
+ _, err = m.keeper.Withdraw(ctx, from, msg.Amount, msg.Strategy)
+ if err != nil {
return nil, err
}
diff --git a/x/earn/keeper/proposal_handler.go b/x/earn/keeper/proposal_handler.go
new file mode 100644
index 00000000..03b08c7c
--- /dev/null
+++ b/x/earn/keeper/proposal_handler.go
@@ -0,0 +1,49 @@
+package keeper
+
+import (
+ sdk "github.com/cosmos/cosmos-sdk/types"
+
+ "github.com/kava-labs/kava/x/earn/types"
+ kavadisttypes "github.com/kava-labs/kava/x/kavadist/types"
+)
+
+// HandleCommunityPoolDepositProposal is a handler for executing a passed community pool deposit proposal
+func HandleCommunityPoolDepositProposal(ctx sdk.Context, k Keeper, p *types.CommunityPoolDepositProposal) error {
+ fundAcc := k.accountKeeper.GetModuleAccount(ctx, kavadisttypes.FundModuleAccount)
+ if err := k.distKeeper.DistributeFromFeePool(ctx, sdk.NewCoins(p.Amount), fundAcc.GetAddress()); err != nil {
+ return err
+ }
+
+ err := k.DepositFromModuleAccount(ctx, kavadisttypes.FundModuleAccount, p.Amount, types.STRATEGY_TYPE_SAVINGS)
+ if err != nil {
+ return err
+ }
+
+ return nil
+
+}
+
+// HandleCommunityPoolWithdrawProposal is a handler for executing a passed community pool withdraw proposal.
+func HandleCommunityPoolWithdrawProposal(ctx sdk.Context, k Keeper, p *types.CommunityPoolWithdrawProposal) error {
+ // Withdraw to fund module account
+ withdrawAmount, err := k.WithdrawFromModuleAccount(ctx, kavadisttypes.FundModuleAccount, p.Amount, types.STRATEGY_TYPE_SAVINGS)
+ if err != nil {
+ return err
+ }
+
+ // Move funds to the community pool manually
+ err = k.bankKeeper.SendCoinsFromModuleToModule(
+ ctx,
+ kavadisttypes.FundModuleAccount,
+ k.distKeeper.GetDistributionAccount(ctx).GetName(),
+ sdk.NewCoins(withdrawAmount),
+ )
+ if err != nil {
+ return err
+ }
+ feePool := k.distKeeper.GetFeePool(ctx)
+ newCommunityPool := feePool.CommunityPool.Add(sdk.NewDecCoinFromCoin(withdrawAmount))
+ feePool.CommunityPool = newCommunityPool
+ k.distKeeper.SetFeePool(ctx, feePool)
+ return nil
+}
diff --git a/x/earn/keeper/proposal_handler_test.go b/x/earn/keeper/proposal_handler_test.go
new file mode 100644
index 00000000..23856736
--- /dev/null
+++ b/x/earn/keeper/proposal_handler_test.go
@@ -0,0 +1,80 @@
+package keeper_test
+
+import (
+ "testing"
+
+ sdk "github.com/cosmos/cosmos-sdk/types"
+ "github.com/kava-labs/kava/x/earn/keeper"
+ "github.com/kava-labs/kava/x/earn/testutil"
+ "github.com/kava-labs/kava/x/earn/types"
+ "github.com/stretchr/testify/suite"
+)
+
+type proposalTestSuite struct {
+ testutil.Suite
+}
+
+func (suite *proposalTestSuite) SetupTest() {
+ suite.Suite.SetupTest()
+ suite.Keeper.SetParams(suite.Ctx, types.DefaultParams())
+}
+
+func TestProposalTestSuite(t *testing.T) {
+ suite.Run(t, new(proposalTestSuite))
+}
+
+func (suite *proposalTestSuite) TestCommunityDepositProposal() {
+ distKeeper := suite.App.GetDistrKeeper()
+ ctx := suite.Ctx
+ macc := distKeeper.GetDistributionAccount(ctx)
+ fundAmount := sdk.NewCoins(sdk.NewInt64Coin("ukava", 100000000))
+ depositAmount := sdk.NewCoin("ukava", sdk.NewInt(10000000))
+ suite.Require().NoError(suite.App.FundModuleAccount(ctx, macc.GetName(), fundAmount))
+ feePool := distKeeper.GetFeePool(ctx)
+ feePool.CommunityPool = sdk.NewDecCoinsFromCoins(fundAmount...)
+ distKeeper.SetFeePool(ctx, feePool)
+ suite.CreateVault("ukava", types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
+ prop := types.NewCommunityPoolDepositProposal("test title",
+ "desc", depositAmount)
+ err := keeper.HandleCommunityPoolDepositProposal(ctx, suite.Keeper, prop)
+ suite.Require().NoError(err)
+
+ balance := suite.BankKeeper.GetAllBalances(ctx, macc.GetAddress())
+ suite.Require().Equal(fundAmount.Sub(sdk.NewCoins(depositAmount)), balance)
+ feePool = distKeeper.GetFeePool(ctx)
+ communityPoolBalance, change := feePool.CommunityPool.TruncateDecimal()
+ suite.Require().Equal(fundAmount.Sub(sdk.NewCoins(depositAmount)), communityPoolBalance)
+ suite.Require().True(change.Empty())
+}
+
+func (suite *proposalTestSuite) TestCommunityWithdrawProposal() {
+ distKeeper := suite.App.GetDistrKeeper()
+ ctx := suite.Ctx
+ macc := distKeeper.GetDistributionAccount(ctx)
+ fundAmount := sdk.NewCoins(sdk.NewInt64Coin("ukava", 100000000))
+ depositAmount := sdk.NewCoin("ukava", sdk.NewInt(10000000))
+ suite.Require().NoError(suite.App.FundModuleAccount(ctx, macc.GetName(), fundAmount))
+ feePool := distKeeper.GetFeePool(ctx)
+ feePool.CommunityPool = sdk.NewDecCoinsFromCoins(fundAmount...)
+ distKeeper.SetFeePool(ctx, feePool)
+ // TODO update to STRATEGY_TYPE_SAVINGS once implemented
+ suite.CreateVault("ukava", types.StrategyTypes{types.STRATEGY_TYPE_SAVINGS}, false, nil)
+ deposit := types.NewCommunityPoolDepositProposal("test title",
+ "desc", depositAmount)
+ err := keeper.HandleCommunityPoolDepositProposal(ctx, suite.Keeper, deposit)
+ suite.Require().NoError(err)
+
+ balance := suite.BankKeeper.GetAllBalances(ctx, macc.GetAddress())
+ suite.Require().Equal(fundAmount.Sub(sdk.NewCoins(depositAmount)), balance)
+
+ withdraw := types.NewCommunityPoolWithdrawProposal("test title",
+ "desc", depositAmount)
+ err = keeper.HandleCommunityPoolWithdrawProposal(ctx, suite.Keeper, withdraw)
+ suite.Require().NoError(err)
+ balance = suite.BankKeeper.GetAllBalances(ctx, macc.GetAddress())
+ suite.Require().Equal(fundAmount, balance)
+ feePool = distKeeper.GetFeePool(ctx)
+ communityPoolBalance, change := feePool.CommunityPool.TruncateDecimal()
+ suite.Require().Equal(fundAmount, communityPoolBalance)
+ suite.Require().True(change.Empty())
+}
diff --git a/x/earn/keeper/strategy_hard_test.go b/x/earn/keeper/strategy_hard_test.go
index bbf6a6ba..871a9394 100644
--- a/x/earn/keeper/strategy_hard_test.go
+++ b/x/earn/keeper/strategy_hard_test.go
@@ -184,7 +184,7 @@ func (suite *strategyHardTestSuite) TestWithdraw() {
suite.Equal(depositAmount, totalValue)
// Withdraw
- err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_HARD)
+ _, 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, types.STRATEGY_TYPE_HARD)
+ _, 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")
}
@@ -218,11 +218,11 @@ func (suite *strategyHardTestSuite) TestWithdraw_OnlyWithdrawOwnSupply() {
suite.Require().NoError(err)
// Withdraw
- err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD)
+ _, 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, types.STRATEGY_TYPE_HARD)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_HARD)
suite.Require().Error(err)
suite.Require().ErrorIs(
err,
@@ -263,11 +263,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, types.STRATEGY_TYPE_HARD)
+ _, 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, types.STRATEGY_TYPE_HARD)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc, depositAmount, types.STRATEGY_TYPE_HARD)
suite.Require().Error(err)
suite.Require().ErrorIs(
err,
@@ -276,11 +276,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)), types.STRATEGY_TYPE_HARD)
+ _, 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)), types.STRATEGY_TYPE_HARD)
+ _, 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)
@@ -401,7 +401,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)), types.STRATEGY_TYPE_HARD)
+ _, 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)
@@ -444,7 +444,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)), types.STRATEGY_TYPE_HARD)
+ _, 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)
@@ -485,7 +485,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), types.STRATEGY_TYPE_HARD)
+ _, 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/strategy_savings_test.go b/x/earn/keeper/strategy_savings_test.go
index 992f5308..19c13e55 100644
--- a/x/earn/keeper/strategy_savings_test.go
+++ b/x/earn/keeper/strategy_savings_test.go
@@ -180,7 +180,7 @@ func (suite *strategySavingsTestSuite) TestWithdraw() {
suite.Equal(depositAmount, totalValue)
// Withdraw
- err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
suite.Require().NoError(err)
suite.SavingsDepositAmountEqual(sdk.NewCoins())
@@ -192,7 +192,7 @@ func (suite *strategySavingsTestSuite) TestWithdraw() {
suite.Equal(sdk.NewInt64Coin(savingsVaultDenom, 0), totalValue)
// Withdraw again
- err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
suite.Require().Error(err)
suite.Require().ErrorIs(err, types.ErrVaultRecordNotFound, "vault should be deleted when no more supply")
}
@@ -213,11 +213,11 @@ func (suite *strategySavingsTestSuite) TestWithdraw_OnlyWithdrawOwnSupply() {
suite.Require().NoError(err)
// Withdraw
- err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_SAVINGS)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_SAVINGS)
suite.Require().NoError(err)
// Withdraw again
- err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_SAVINGS)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount, types.STRATEGY_TYPE_SAVINGS)
suite.Require().Error(err)
suite.Require().ErrorIs(
err,
@@ -257,11 +257,11 @@ func (suite *strategySavingsTestSuite) TestWithdraw_WithAccumulatedSavings() {
suite.Equal(depositAmount.AddAmount(sdk.NewInt(10)), accValue)
// Withdraw 100, 10 remaining
- err = suite.Keeper.Withdraw(suite.Ctx, acc, depositAmount, types.STRATEGY_TYPE_SAVINGS)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc, depositAmount, types.STRATEGY_TYPE_SAVINGS)
suite.Require().NoError(err)
// Withdraw 100 again -- too much
- err = suite.Keeper.Withdraw(suite.Ctx, acc, depositAmount, types.STRATEGY_TYPE_SAVINGS)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc, depositAmount, types.STRATEGY_TYPE_SAVINGS)
suite.Require().Error(err)
suite.Require().ErrorIs(
err,
@@ -270,11 +270,11 @@ func (suite *strategySavingsTestSuite) TestWithdraw_WithAccumulatedSavings() {
)
// Half of remaining 10, 5 remaining
- err = suite.Keeper.Withdraw(suite.Ctx, acc, sdk.NewCoin(savingsVaultDenom, sdk.NewInt(5)), types.STRATEGY_TYPE_SAVINGS)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc, sdk.NewCoin(savingsVaultDenom, sdk.NewInt(5)), types.STRATEGY_TYPE_SAVINGS)
suite.Require().NoError(err)
// Withdraw all
- err = suite.Keeper.Withdraw(suite.Ctx, acc, sdk.NewCoin(savingsVaultDenom, sdk.NewInt(5)), types.STRATEGY_TYPE_SAVINGS)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc, sdk.NewCoin(savingsVaultDenom, sdk.NewInt(5)), types.STRATEGY_TYPE_SAVINGS)
suite.Require().NoError(err)
accValue, err = suite.Keeper.GetVaultAccountValue(suite.Ctx, savingsVaultDenom, acc)
@@ -393,7 +393,7 @@ func (suite *strategySavingsTestSuite) 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)), types.STRATEGY_TYPE_SAVINGS)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount.AddAmount(sdk.NewInt(10)), types.STRATEGY_TYPE_SAVINGS)
suite.Require().NoError(err)
_, found = suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
@@ -435,7 +435,7 @@ func (suite *strategySavingsTestSuite) 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)), types.STRATEGY_TYPE_SAVINGS)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc1, depositAmount.AddAmount(sdk.NewInt(5)), types.STRATEGY_TYPE_SAVINGS)
suite.Require().NoError(err)
acc1Shares, found = suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
@@ -475,7 +475,7 @@ func (suite *strategySavingsTestSuite) 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(savingsVaultDenom, 2000), types.STRATEGY_TYPE_SAVINGS)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc1, sdk.NewInt64Coin(savingsVaultDenom, 2000), types.STRATEGY_TYPE_SAVINGS)
suite.Require().NoError(err)
acc1Shares, found = suite.Keeper.GetVaultAccountShares(suite.Ctx, acc1)
diff --git a/x/earn/keeper/withdraw.go b/x/earn/keeper/withdraw.go
index d149aa24..122e570b 100644
--- a/x/earn/keeper/withdraw.go
+++ b/x/earn/keeper/withdraw.go
@@ -16,43 +16,43 @@ func (k *Keeper) Withdraw(
from sdk.AccAddress,
wantAmount sdk.Coin,
withdrawStrategy types.StrategyType,
-) error {
+) (sdk.Coin, error) {
// Get AllowedVault, if not found (not a valid vault), return error
allowedVault, found := k.GetAllowedVault(ctx, wantAmount.Denom)
if !found {
- return types.ErrInvalidVaultDenom
+ return sdk.Coin{}, types.ErrInvalidVaultDenom
}
if wantAmount.IsZero() {
- return types.ErrInsufficientAmount
+ return sdk.Coin{}, types.ErrInsufficientAmount
}
// Check if withdraw strategy is supported by vault
if !allowedVault.IsStrategyAllowed(withdrawStrategy) {
- return types.ErrInvalidVaultStrategy
+ return sdk.Coin{}, types.ErrInvalidVaultStrategy
}
// Check if VaultRecord exists
vaultRecord, found := k.GetVaultRecord(ctx, wantAmount.Denom)
if !found {
- return types.ErrVaultRecordNotFound
+ return sdk.Coin{}, types.ErrVaultRecordNotFound
}
// Get account share record for the vault
vaultShareRecord, found := k.GetVaultShareRecord(ctx, from)
if !found {
- return types.ErrVaultShareRecordNotFound
+ return sdk.Coin{}, types.ErrVaultShareRecordNotFound
}
withdrawShares, err := k.ConvertToShares(ctx, wantAmount)
if err != nil {
- return fmt.Errorf("failed to convert assets to shares: %w", err)
+ return sdk.Coin{}, fmt.Errorf("failed to convert assets to shares: %w", err)
}
accCurrentShares := vaultShareRecord.Shares.AmountOf(wantAmount.Denom)
// Check if account is not withdrawing more shares than they have
if accCurrentShares.LT(withdrawShares.Amount) {
- return sdkerrors.Wrapf(
+ return sdk.Coin{}, sdkerrors.Wrapf(
types.ErrInsufficientValue,
"account has less %s vault shares than withdraw shares, %s < %s",
wantAmount.Denom,
@@ -64,17 +64,17 @@ func (k *Keeper) Withdraw(
// Convert shares to amount to get truncated true share value
withdrawAmount, err := k.ConvertToAssets(ctx, withdrawShares)
if err != nil {
- return fmt.Errorf("failed to convert shares to assets: %w", err)
+ return sdk.Coin{}, fmt.Errorf("failed to convert shares to assets: %w", err)
}
accountValue, err := k.GetVaultAccountValue(ctx, wantAmount.Denom, from)
if err != nil {
- return fmt.Errorf("failed to get account value: %w", err)
+ return sdk.Coin{}, fmt.Errorf("failed to get account value: %w", err)
}
// Check if withdrawAmount > account value
if withdrawAmount.Amount.GT(accountValue.Amount) {
- return sdkerrors.Wrapf(
+ return sdk.Coin{}, sdkerrors.Wrapf(
types.ErrInsufficientValue,
"account has less %s vault value than withdraw amount, %s < %s",
withdrawAmount.Denom,
@@ -86,7 +86,7 @@ func (k *Keeper) Withdraw(
// Get the strategy for the vault
strategy, err := k.GetStrategy(allowedVault.Strategies[0])
if err != nil {
- return err
+ return sdk.Coin{}, err
}
// Not necessary to check if amount denom is allowed for the strategy, as
@@ -94,7 +94,7 @@ func (k *Keeper) Withdraw(
// Withdraw the withdrawAmount from the strategy
if err := strategy.Withdraw(ctx, withdrawAmount); err != nil {
- return fmt.Errorf("failed to withdraw from strategy: %w", err)
+ return sdk.Coin{}, fmt.Errorf("failed to withdraw from strategy: %w", err)
}
// Send coins back to account, must withdraw from strategy first or the
@@ -105,7 +105,7 @@ func (k *Keeper) Withdraw(
from,
sdk.NewCoins(withdrawAmount),
); err != nil {
- return err
+ return sdk.Coin{}, err
}
// Check if new account balance of shares results in account share value
@@ -116,7 +116,7 @@ func (k *Keeper) Withdraw(
vaultShareRecord.Shares.GetShare(withdrawAmount.Denom).Sub(withdrawShares),
)
if err != nil {
- return err
+ return sdk.Coin{}, err
}
if isDust {
@@ -148,5 +148,21 @@ func (k *Keeper) Withdraw(
),
)
- return nil
+ return withdrawAmount, nil
+}
+
+// WithdrawFromModuleAccount removes the amount of supplied tokens from a vault and transfers it
+// back to the module account. The module account must be unblocked from receiving transfers.
+func (k *Keeper) WithdrawFromModuleAccount(
+ ctx sdk.Context,
+ from string,
+ wantAmount sdk.Coin,
+ withdrawStrategy types.StrategyType,
+) (sdk.Coin, error) {
+ // Ensure the module account exists to prevent SendCoins from creating a new non-module account.
+ acc := k.accountKeeper.GetModuleAccount(ctx, from)
+ if acc == nil {
+ return sdk.Coin{}, fmt.Errorf("module account not found: %s", from)
+ }
+ return k.Withdraw(ctx, acc.GetAddress(), wantAmount, withdrawStrategy)
}
diff --git a/x/earn/keeper/withdraw_test.go b/x/earn/keeper/withdraw_test.go
index e4db67f1..0bb14a91 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, types.STRATEGY_TYPE_HARD)
+ _, err := suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount, types.STRATEGY_TYPE_HARD)
suite.Require().Error(err)
suite.Require().ErrorIs(err, types.ErrVaultRecordNotFound)
@@ -65,7 +65,7 @@ func (suite *withdrawTestSuite) TestWithdraw_NoVaultShareRecord() {
acc2 := suite.CreateAccount(sdk.NewCoins(startBalance), 1)
// Withdraw from acc2 without having any prior deposits
- err = suite.Keeper.Withdraw(suite.Ctx, acc2.GetAddress(), acc2WithdrawAmount, types.STRATEGY_TYPE_HARD)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc2.GetAddress(), acc2WithdrawAmount, types.STRATEGY_TYPE_HARD)
suite.Require().Error(err)
suite.Require().ErrorIs(err, types.ErrVaultShareRecordNotFound)
@@ -94,7 +94,7 @@ func (suite *withdrawTestSuite) TestWithdraw_ExceedBalance() {
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, types.STRATEGY_TYPE_HARD)
+ _, 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, types.STRATEGY_TYPE_HARD)
+ _, 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, types.STRATEGY_TYPE_HARD)
+ _, err := suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount, types.STRATEGY_TYPE_HARD)
suite.Require().Error(err)
suite.Require().ErrorIs(err, types.ErrInvalidVaultDenom)
@@ -169,7 +169,7 @@ func (suite *withdrawTestSuite) TestWithdraw_InvalidStrategy() {
acc := suite.CreateAccount(sdk.NewCoins(startBalance), 0)
- err := suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount, types.STRATEGY_TYPE_SAVINGS)
+ _, err := suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount, types.STRATEGY_TYPE_SAVINGS)
suite.Require().Error(err)
suite.Require().ErrorIs(err, types.ErrInvalidVaultStrategy)
}
@@ -187,7 +187,7 @@ func (suite *withdrawTestSuite) TestWithdraw_FullBalance() {
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, types.STRATEGY_TYPE_HARD)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), withdrawAmount, types.STRATEGY_TYPE_HARD)
suite.Require().NoError(err)
// No net changes in balances
@@ -214,7 +214,7 @@ func (suite *withdrawTestSuite) TestWithdraw_Partial() {
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, types.STRATEGY_TYPE_HARD)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), partialWithdrawAmount, types.STRATEGY_TYPE_HARD)
suite.Require().NoError(err)
suite.AccountBalanceEqual(
@@ -223,11 +223,11 @@ func (suite *withdrawTestSuite) TestWithdraw_Partial() {
)
// Second withdraw for remaining 50
- err = suite.Keeper.Withdraw(suite.Ctx, acc.GetAddress(), partialWithdrawAmount, types.STRATEGY_TYPE_HARD)
+ _, 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, types.STRATEGY_TYPE_HARD)
+ _, 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")
@@ -265,7 +265,7 @@ func (suite *withdrawTestSuite) TestWithdraw_bKava() {
"should be able to deposit bkava derivative denom in bkava vault",
)
- err = suite.Keeper.Withdraw(suite.Ctx, acc1.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
+ _, err = suite.Keeper.Withdraw(suite.Ctx, acc1.GetAddress(), depositAmount, types.STRATEGY_TYPE_SAVINGS)
suite.Require().NoError(
err,
"should be able to withdraw bkava derivative denom from bkava vault",
diff --git a/x/earn/types/codec.go b/x/earn/types/codec.go
index 38e6eeb3..c4bcabcc 100644
--- a/x/earn/types/codec.go
+++ b/x/earn/types/codec.go
@@ -7,6 +7,7 @@ import (
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
+ govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
)
// RegisterLegacyAminoCodec registers all the necessary types and interfaces for the
@@ -14,6 +15,8 @@ import (
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
cdc.RegisterConcrete(&MsgDeposit{}, "earn/MsgDeposit", nil)
cdc.RegisterConcrete(&MsgWithdraw{}, "earn/MsgWithdraw", nil)
+ cdc.RegisterConcrete(&CommunityPoolDepositProposal{}, "kava/CommunityPoolDepositProposal", nil)
+ cdc.RegisterConcrete(&CommunityPoolWithdrawProposal{}, "kava/CommunityPoolWithdrawProposal", nil)
}
// RegisterInterfaces registers proto messages under their interfaces for unmarshalling,
@@ -23,6 +26,10 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
&MsgDeposit{},
&MsgWithdraw{},
)
+ registry.RegisterImplementations((*govtypes.Content)(nil),
+ &CommunityPoolDepositProposal{},
+ &CommunityPoolWithdrawProposal{},
+ )
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
}
diff --git a/x/earn/types/expected_keepers.go b/x/earn/types/expected_keepers.go
index 99dd28da..e2533c88 100644
--- a/x/earn/types/expected_keepers.go
+++ b/x/earn/types/expected_keepers.go
@@ -3,6 +3,7 @@ package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/types"
+ disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
hardtypes "github.com/kava-labs/kava/x/hard/types"
savingstypes "github.com/kava-labs/kava/x/savings/types"
@@ -25,6 +26,14 @@ type BankKeeper interface {
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
}
+// DistributionKeeper defines the expected interface needed for community-pool deposits to earn vaults
+type DistributionKeeper interface {
+ GetFeePool(ctx sdk.Context) (feePool disttypes.FeePool)
+ SetFeePool(ctx sdk.Context, feePool disttypes.FeePool)
+ GetDistributionAccount(ctx sdk.Context) types.ModuleAccountI
+ DistributeFromFeePool(ctx sdk.Context, amount sdk.Coins, receiveAddr sdk.AccAddress) error
+}
+
// LiquidKeeper defines the expected interface needed for derivative to staked token conversions.
type LiquidKeeper interface {
GetStakedTokensForDerivatives(ctx sdk.Context, derivatives sdk.Coins) (sdk.Coin, error)
diff --git a/x/earn/types/proposal.go b/x/earn/types/proposal.go
new file mode 100644
index 00000000..95800245
--- /dev/null
+++ b/x/earn/types/proposal.go
@@ -0,0 +1,117 @@
+package types
+
+import (
+ fmt "fmt"
+ "strings"
+
+ sdk "github.com/cosmos/cosmos-sdk/types"
+ govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
+)
+
+const (
+ // ProposalTypeCommunityPoolDeposit defines the type for a CommunityPoolDepositProposal
+ ProposalTypeCommunityPoolDeposit = "CommunityPoolDeposit"
+ // ProposalTypeCommunityPoolWithdraw defines the type for a CommunityPoolDepositProposal
+ ProposalTypeCommunityPoolWithdraw = "CommunityPoolWithdraw"
+)
+
+// Assert CommunityPoolDepositProposal implements govtypes.Content at compile-time
+var (
+ _ govtypes.Content = &CommunityPoolDepositProposal{}
+ _ govtypes.Content = &CommunityPoolWithdrawProposal{}
+)
+
+func init() {
+ govtypes.RegisterProposalType(ProposalTypeCommunityPoolDeposit)
+ govtypes.RegisterProposalTypeCodec(&CommunityPoolDepositProposal{}, "kava/CommunityPoolDepositProposal")
+ govtypes.RegisterProposalType(ProposalTypeCommunityPoolWithdraw)
+ govtypes.RegisterProposalTypeCodec(&CommunityPoolWithdrawProposal{}, "kava/CommunityPoolWithdrawProposal")
+}
+
+// NewCommunityPoolDepositProposal creates a new community pool deposit proposal.
+func NewCommunityPoolDepositProposal(title, description string, amount sdk.Coin) *CommunityPoolDepositProposal {
+ return &CommunityPoolDepositProposal{
+ Title: title,
+ Description: description,
+ Amount: amount,
+ }
+}
+
+// GetTitle returns the title of a community pool deposit proposal.
+func (cdp *CommunityPoolDepositProposal) GetTitle() string { return cdp.Title }
+
+// GetDescription returns the description of a community pool deposit proposal.
+func (cdp *CommunityPoolDepositProposal) GetDescription() string { return cdp.Description }
+
+// GetDescription returns the routing key of a community pool deposit proposal.
+func (cdp *CommunityPoolDepositProposal) ProposalRoute() string { return RouterKey }
+
+// ProposalType returns the type of a community pool deposit proposal.
+func (cdp *CommunityPoolDepositProposal) ProposalType() string {
+ return ProposalTypeCommunityPoolDeposit
+}
+
+// String implements fmt.Stringer
+func (cdp *CommunityPoolDepositProposal) String() string {
+
+ var b strings.Builder
+ b.WriteString(fmt.Sprintf(`Community Pool Deposit Proposal:
+ Title: %s
+ Description: %s
+ Amount: %s
+`, cdp.Title, cdp.Description, cdp.Amount))
+ return b.String()
+}
+
+// ValidateBasic stateless validation of a community pool multi-spend proposal.
+func (cdp *CommunityPoolDepositProposal) ValidateBasic() error {
+ err := govtypes.ValidateAbstract(cdp)
+ if err != nil {
+ return err
+ }
+ return cdp.Amount.Validate()
+}
+
+// NewCommunityPoolWithdrawProposal creates a new community pool deposit proposal.
+func NewCommunityPoolWithdrawProposal(title, description string, amount sdk.Coin) *CommunityPoolWithdrawProposal {
+ return &CommunityPoolWithdrawProposal{
+ Title: title,
+ Description: description,
+ Amount: amount,
+ }
+}
+
+// GetTitle returns the title of a community pool withdraw proposal.
+func (cdp *CommunityPoolWithdrawProposal) GetTitle() string { return cdp.Title }
+
+// GetDescription returns the description of a community pool withdraw proposal.
+func (cdp *CommunityPoolWithdrawProposal) GetDescription() string { return cdp.Description }
+
+// GetDescription returns the routing key of a community pool withdraw proposal.
+func (cdp *CommunityPoolWithdrawProposal) ProposalRoute() string { return RouterKey }
+
+// ProposalType returns the type of a community pool withdraw proposal.
+func (cdp *CommunityPoolWithdrawProposal) ProposalType() string {
+ return ProposalTypeCommunityPoolWithdraw
+}
+
+// String implements fmt.Stringer
+func (cdp *CommunityPoolWithdrawProposal) String() string {
+
+ var b strings.Builder
+ b.WriteString(fmt.Sprintf(`Community Pool Withdraw Proposal:
+ Title: %s
+ Description: %s
+ Amount: %s
+`, cdp.Title, cdp.Description, cdp.Amount))
+ return b.String()
+}
+
+// ValidateBasic stateless validation of a community pool multi-spend proposal.
+func (cdp *CommunityPoolWithdrawProposal) ValidateBasic() error {
+ err := govtypes.ValidateAbstract(cdp)
+ if err != nil {
+ return err
+ }
+ return cdp.Amount.Validate()
+}
diff --git a/x/earn/types/proposal.pb.go b/x/earn/types/proposal.pb.go
new file mode 100644
index 00000000..ed39c173
--- /dev/null
+++ b/x/earn/types/proposal.pb.go
@@ -0,0 +1,1285 @@
+// Code generated by protoc-gen-gogo. DO NOT EDIT.
+// source: kava/earn/v1beta1/proposal.proto
+
+package types
+
+import (
+ fmt "fmt"
+ github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types"
+ types "github.com/cosmos/cosmos-sdk/types"
+ _ "github.com/gogo/protobuf/gogoproto"
+ proto "github.com/gogo/protobuf/proto"
+ io "io"
+ math "math"
+ math_bits "math/bits"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
+
+// CommunityPoolDepositProposal deposits from the community pool into an earn vault
+type CommunityPoolDepositProposal struct {
+ Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+ Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"`
+}
+
+func (m *CommunityPoolDepositProposal) Reset() { *m = CommunityPoolDepositProposal{} }
+func (*CommunityPoolDepositProposal) ProtoMessage() {}
+func (*CommunityPoolDepositProposal) Descriptor() ([]byte, []int) {
+ return fileDescriptor_c374f1a8c57e13e2, []int{0}
+}
+func (m *CommunityPoolDepositProposal) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *CommunityPoolDepositProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_CommunityPoolDepositProposal.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalToSizedBuffer(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (m *CommunityPoolDepositProposal) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommunityPoolDepositProposal.Merge(m, src)
+}
+func (m *CommunityPoolDepositProposal) XXX_Size() int {
+ return m.Size()
+}
+func (m *CommunityPoolDepositProposal) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommunityPoolDepositProposal.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommunityPoolDepositProposal proto.InternalMessageInfo
+
+// CommunityPoolDepositProposalJSON defines a CommunityPoolDepositProposal with a deposit
+type CommunityPoolDepositProposalJSON struct {
+ Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+ Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"`
+ Deposit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,4,rep,name=deposit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"deposit"`
+}
+
+func (m *CommunityPoolDepositProposalJSON) Reset() { *m = CommunityPoolDepositProposalJSON{} }
+func (m *CommunityPoolDepositProposalJSON) String() string { return proto.CompactTextString(m) }
+func (*CommunityPoolDepositProposalJSON) ProtoMessage() {}
+func (*CommunityPoolDepositProposalJSON) Descriptor() ([]byte, []int) {
+ return fileDescriptor_c374f1a8c57e13e2, []int{1}
+}
+func (m *CommunityPoolDepositProposalJSON) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *CommunityPoolDepositProposalJSON) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_CommunityPoolDepositProposalJSON.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalToSizedBuffer(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (m *CommunityPoolDepositProposalJSON) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommunityPoolDepositProposalJSON.Merge(m, src)
+}
+func (m *CommunityPoolDepositProposalJSON) XXX_Size() int {
+ return m.Size()
+}
+func (m *CommunityPoolDepositProposalJSON) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommunityPoolDepositProposalJSON.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommunityPoolDepositProposalJSON proto.InternalMessageInfo
+
+// CommunityPoolWithdrawProposal withdraws from an earn vault back to community pool
+type CommunityPoolWithdrawProposal struct {
+ Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+ Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"`
+}
+
+func (m *CommunityPoolWithdrawProposal) Reset() { *m = CommunityPoolWithdrawProposal{} }
+func (*CommunityPoolWithdrawProposal) ProtoMessage() {}
+func (*CommunityPoolWithdrawProposal) Descriptor() ([]byte, []int) {
+ return fileDescriptor_c374f1a8c57e13e2, []int{2}
+}
+func (m *CommunityPoolWithdrawProposal) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *CommunityPoolWithdrawProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_CommunityPoolWithdrawProposal.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalToSizedBuffer(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (m *CommunityPoolWithdrawProposal) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommunityPoolWithdrawProposal.Merge(m, src)
+}
+func (m *CommunityPoolWithdrawProposal) XXX_Size() int {
+ return m.Size()
+}
+func (m *CommunityPoolWithdrawProposal) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommunityPoolWithdrawProposal.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommunityPoolWithdrawProposal proto.InternalMessageInfo
+
+// CommunityPoolWithdrawProposalJSON defines a CommunityPoolWithdrawProposal with a deposit
+type CommunityPoolWithdrawProposalJSON struct {
+ Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+ Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"`
+ Deposit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,4,rep,name=deposit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"deposit"`
+}
+
+func (m *CommunityPoolWithdrawProposalJSON) Reset() { *m = CommunityPoolWithdrawProposalJSON{} }
+func (m *CommunityPoolWithdrawProposalJSON) String() string { return proto.CompactTextString(m) }
+func (*CommunityPoolWithdrawProposalJSON) ProtoMessage() {}
+func (*CommunityPoolWithdrawProposalJSON) Descriptor() ([]byte, []int) {
+ return fileDescriptor_c374f1a8c57e13e2, []int{3}
+}
+func (m *CommunityPoolWithdrawProposalJSON) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *CommunityPoolWithdrawProposalJSON) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_CommunityPoolWithdrawProposalJSON.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalToSizedBuffer(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (m *CommunityPoolWithdrawProposalJSON) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CommunityPoolWithdrawProposalJSON.Merge(m, src)
+}
+func (m *CommunityPoolWithdrawProposalJSON) XXX_Size() int {
+ return m.Size()
+}
+func (m *CommunityPoolWithdrawProposalJSON) XXX_DiscardUnknown() {
+ xxx_messageInfo_CommunityPoolWithdrawProposalJSON.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CommunityPoolWithdrawProposalJSON proto.InternalMessageInfo
+
+func init() {
+ proto.RegisterType((*CommunityPoolDepositProposal)(nil), "kava.earn.v1beta1.CommunityPoolDepositProposal")
+ proto.RegisterType((*CommunityPoolDepositProposalJSON)(nil), "kava.earn.v1beta1.CommunityPoolDepositProposalJSON")
+ proto.RegisterType((*CommunityPoolWithdrawProposal)(nil), "kava.earn.v1beta1.CommunityPoolWithdrawProposal")
+ proto.RegisterType((*CommunityPoolWithdrawProposalJSON)(nil), "kava.earn.v1beta1.CommunityPoolWithdrawProposalJSON")
+}
+
+func init() { proto.RegisterFile("kava/earn/v1beta1/proposal.proto", fileDescriptor_c374f1a8c57e13e2) }
+
+var fileDescriptor_c374f1a8c57e13e2 = []byte{
+ // 371 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xc8, 0x4e, 0x2c, 0x4b,
+ 0xd4, 0x4f, 0x4d, 0x2c, 0xca, 0xd3, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x2f, 0x28,
+ 0xca, 0x2f, 0xc8, 0x2f, 0x4e, 0xcc, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x04, 0xa9,
+ 0xd0, 0x03, 0xa9, 0xd0, 0x83, 0xaa, 0x90, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xcb, 0xea, 0x83,
+ 0x58, 0x10, 0x85, 0x52, 0x72, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xfa, 0x49, 0x89, 0xc5, 0xa9,
+ 0x70, 0xc3, 0x92, 0xf3, 0x33, 0xf3, 0x20, 0xf2, 0x4a, 0x33, 0x19, 0xb9, 0x64, 0x9c, 0xf3, 0x73,
+ 0x73, 0x4b, 0xf3, 0x32, 0x4b, 0x2a, 0x03, 0xf2, 0xf3, 0x73, 0x5c, 0x52, 0x0b, 0xf2, 0x8b, 0x33,
+ 0x4b, 0x02, 0xa0, 0xf6, 0x09, 0x89, 0x70, 0xb1, 0x96, 0x64, 0x96, 0xe4, 0xa4, 0x4a, 0x30, 0x2a,
+ 0x30, 0x6a, 0x70, 0x06, 0x41, 0x38, 0x42, 0x0a, 0x5c, 0xdc, 0x29, 0xa9, 0xc5, 0xc9, 0x45, 0x99,
+ 0x05, 0x25, 0x99, 0xf9, 0x79, 0x12, 0x4c, 0x60, 0x39, 0x64, 0x21, 0x21, 0x73, 0x2e, 0xb6, 0xc4,
+ 0xdc, 0xfc, 0xd2, 0xbc, 0x12, 0x09, 0x66, 0x05, 0x46, 0x0d, 0x6e, 0x23, 0x49, 0x3d, 0x88, 0x4b,
+ 0xf4, 0x40, 0x2e, 0x81, 0x39, 0x5a, 0xcf, 0x39, 0x3f, 0x33, 0xcf, 0x89, 0xe5, 0xc4, 0x3d, 0x79,
+ 0x86, 0x20, 0xa8, 0x72, 0x2b, 0x8e, 0x8e, 0x05, 0xf2, 0x0c, 0x33, 0x16, 0xc8, 0x33, 0x28, 0xb5,
+ 0x30, 0x71, 0x29, 0xe0, 0x73, 0x9b, 0x57, 0xb0, 0xbf, 0x1f, 0xdd, 0xdd, 0x27, 0x94, 0xca, 0xc5,
+ 0x9e, 0x02, 0x71, 0x87, 0x04, 0x8b, 0x02, 0x33, 0x7e, 0x9d, 0x06, 0x20, 0x9d, 0xab, 0xee, 0xcb,
+ 0x6b, 0xa4, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x43, 0x23, 0x04, 0x42,
+ 0xe9, 0x16, 0xa7, 0x64, 0xeb, 0x97, 0x54, 0x16, 0xa4, 0x16, 0x83, 0x35, 0x14, 0x07, 0xc1, 0xcc,
+ 0x86, 0x07, 0x03, 0xa3, 0xd2, 0x2c, 0x46, 0x2e, 0x59, 0x94, 0x60, 0x08, 0xcf, 0x2c, 0xc9, 0x48,
+ 0x29, 0x4a, 0x2c, 0x1f, 0x0c, 0x71, 0xd4, 0xca, 0xc4, 0xa5, 0x88, 0xd7, 0x71, 0x23, 0x23, 0x92,
+ 0x9c, 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, 0x0d, 0xc9, 0x58,
+ 0x50, 0xae, 0xd5, 0xcd, 0x49, 0x4c, 0x2a, 0x06, 0xb3, 0xf4, 0x2b, 0x20, 0x79, 0x1c, 0x6c, 0x74,
+ 0x12, 0x1b, 0x38, 0x43, 0x1a, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd3, 0xb6, 0x0b, 0x2a, 0xfd,
+ 0x03, 0x00, 0x00,
+}
+
+func (m *CommunityPoolDepositProposal) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalToSizedBuffer(dAtA[:size])
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *CommunityPoolDepositProposal) MarshalTo(dAtA []byte) (int, error) {
+ size := m.Size()
+ return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *CommunityPoolDepositProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+ i := len(dAtA)
+ _ = i
+ var l int
+ _ = l
+ {
+ size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i])
+ if err != nil {
+ return 0, err
+ }
+ i -= size
+ i = encodeVarintProposal(dAtA, i, uint64(size))
+ }
+ i--
+ dAtA[i] = 0x1a
+ if len(m.Description) > 0 {
+ i -= len(m.Description)
+ copy(dAtA[i:], m.Description)
+ i = encodeVarintProposal(dAtA, i, uint64(len(m.Description)))
+ i--
+ dAtA[i] = 0x12
+ }
+ if len(m.Title) > 0 {
+ i -= len(m.Title)
+ copy(dAtA[i:], m.Title)
+ i = encodeVarintProposal(dAtA, i, uint64(len(m.Title)))
+ i--
+ dAtA[i] = 0xa
+ }
+ return len(dAtA) - i, nil
+}
+
+func (m *CommunityPoolDepositProposalJSON) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalToSizedBuffer(dAtA[:size])
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *CommunityPoolDepositProposalJSON) MarshalTo(dAtA []byte) (int, error) {
+ size := m.Size()
+ return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *CommunityPoolDepositProposalJSON) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+ i := len(dAtA)
+ _ = i
+ var l int
+ _ = l
+ if len(m.Deposit) > 0 {
+ for iNdEx := len(m.Deposit) - 1; iNdEx >= 0; iNdEx-- {
+ {
+ size, err := m.Deposit[iNdEx].MarshalToSizedBuffer(dAtA[:i])
+ if err != nil {
+ return 0, err
+ }
+ i -= size
+ i = encodeVarintProposal(dAtA, i, uint64(size))
+ }
+ i--
+ dAtA[i] = 0x22
+ }
+ }
+ {
+ size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i])
+ if err != nil {
+ return 0, err
+ }
+ i -= size
+ i = encodeVarintProposal(dAtA, i, uint64(size))
+ }
+ i--
+ dAtA[i] = 0x1a
+ if len(m.Description) > 0 {
+ i -= len(m.Description)
+ copy(dAtA[i:], m.Description)
+ i = encodeVarintProposal(dAtA, i, uint64(len(m.Description)))
+ i--
+ dAtA[i] = 0x12
+ }
+ if len(m.Title) > 0 {
+ i -= len(m.Title)
+ copy(dAtA[i:], m.Title)
+ i = encodeVarintProposal(dAtA, i, uint64(len(m.Title)))
+ i--
+ dAtA[i] = 0xa
+ }
+ return len(dAtA) - i, nil
+}
+
+func (m *CommunityPoolWithdrawProposal) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalToSizedBuffer(dAtA[:size])
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *CommunityPoolWithdrawProposal) MarshalTo(dAtA []byte) (int, error) {
+ size := m.Size()
+ return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *CommunityPoolWithdrawProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+ i := len(dAtA)
+ _ = i
+ var l int
+ _ = l
+ {
+ size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i])
+ if err != nil {
+ return 0, err
+ }
+ i -= size
+ i = encodeVarintProposal(dAtA, i, uint64(size))
+ }
+ i--
+ dAtA[i] = 0x1a
+ if len(m.Description) > 0 {
+ i -= len(m.Description)
+ copy(dAtA[i:], m.Description)
+ i = encodeVarintProposal(dAtA, i, uint64(len(m.Description)))
+ i--
+ dAtA[i] = 0x12
+ }
+ if len(m.Title) > 0 {
+ i -= len(m.Title)
+ copy(dAtA[i:], m.Title)
+ i = encodeVarintProposal(dAtA, i, uint64(len(m.Title)))
+ i--
+ dAtA[i] = 0xa
+ }
+ return len(dAtA) - i, nil
+}
+
+func (m *CommunityPoolWithdrawProposalJSON) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalToSizedBuffer(dAtA[:size])
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *CommunityPoolWithdrawProposalJSON) MarshalTo(dAtA []byte) (int, error) {
+ size := m.Size()
+ return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *CommunityPoolWithdrawProposalJSON) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+ i := len(dAtA)
+ _ = i
+ var l int
+ _ = l
+ if len(m.Deposit) > 0 {
+ for iNdEx := len(m.Deposit) - 1; iNdEx >= 0; iNdEx-- {
+ {
+ size, err := m.Deposit[iNdEx].MarshalToSizedBuffer(dAtA[:i])
+ if err != nil {
+ return 0, err
+ }
+ i -= size
+ i = encodeVarintProposal(dAtA, i, uint64(size))
+ }
+ i--
+ dAtA[i] = 0x22
+ }
+ }
+ {
+ size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i])
+ if err != nil {
+ return 0, err
+ }
+ i -= size
+ i = encodeVarintProposal(dAtA, i, uint64(size))
+ }
+ i--
+ dAtA[i] = 0x1a
+ if len(m.Description) > 0 {
+ i -= len(m.Description)
+ copy(dAtA[i:], m.Description)
+ i = encodeVarintProposal(dAtA, i, uint64(len(m.Description)))
+ i--
+ dAtA[i] = 0x12
+ }
+ if len(m.Title) > 0 {
+ i -= len(m.Title)
+ copy(dAtA[i:], m.Title)
+ i = encodeVarintProposal(dAtA, i, uint64(len(m.Title)))
+ i--
+ dAtA[i] = 0xa
+ }
+ return len(dAtA) - i, nil
+}
+
+func encodeVarintProposal(dAtA []byte, offset int, v uint64) int {
+ offset -= sovProposal(v)
+ base := offset
+ for v >= 1<<7 {
+ dAtA[offset] = uint8(v&0x7f | 0x80)
+ v >>= 7
+ offset++
+ }
+ dAtA[offset] = uint8(v)
+ return base
+}
+func (m *CommunityPoolDepositProposal) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = len(m.Title)
+ if l > 0 {
+ n += 1 + l + sovProposal(uint64(l))
+ }
+ l = len(m.Description)
+ if l > 0 {
+ n += 1 + l + sovProposal(uint64(l))
+ }
+ l = m.Amount.Size()
+ n += 1 + l + sovProposal(uint64(l))
+ return n
+}
+
+func (m *CommunityPoolDepositProposalJSON) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = len(m.Title)
+ if l > 0 {
+ n += 1 + l + sovProposal(uint64(l))
+ }
+ l = len(m.Description)
+ if l > 0 {
+ n += 1 + l + sovProposal(uint64(l))
+ }
+ l = m.Amount.Size()
+ n += 1 + l + sovProposal(uint64(l))
+ if len(m.Deposit) > 0 {
+ for _, e := range m.Deposit {
+ l = e.Size()
+ n += 1 + l + sovProposal(uint64(l))
+ }
+ }
+ return n
+}
+
+func (m *CommunityPoolWithdrawProposal) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = len(m.Title)
+ if l > 0 {
+ n += 1 + l + sovProposal(uint64(l))
+ }
+ l = len(m.Description)
+ if l > 0 {
+ n += 1 + l + sovProposal(uint64(l))
+ }
+ l = m.Amount.Size()
+ n += 1 + l + sovProposal(uint64(l))
+ return n
+}
+
+func (m *CommunityPoolWithdrawProposalJSON) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = len(m.Title)
+ if l > 0 {
+ n += 1 + l + sovProposal(uint64(l))
+ }
+ l = len(m.Description)
+ if l > 0 {
+ n += 1 + l + sovProposal(uint64(l))
+ }
+ l = m.Amount.Size()
+ n += 1 + l + sovProposal(uint64(l))
+ if len(m.Deposit) > 0 {
+ for _, e := range m.Deposit {
+ l = e.Size()
+ n += 1 + l + sovProposal(uint64(l))
+ }
+ }
+ return n
+}
+
+func sovProposal(x uint64) (n int) {
+ return (math_bits.Len64(x|1) + 6) / 7
+}
+func sozProposal(x uint64) (n int) {
+ return sovProposal(uint64((x << 1) ^ uint64((int64(x) >> 63))))
+}
+func (m *CommunityPoolDepositProposal) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: CommunityPoolDepositProposal: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: CommunityPoolDepositProposal: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthProposal
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Title = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthProposal
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Description = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 3:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthProposal
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipProposal(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if (skippy < 0) || (iNdEx+skippy) < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func (m *CommunityPoolDepositProposalJSON) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: CommunityPoolDepositProposalJSON: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: CommunityPoolDepositProposalJSON: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthProposal
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Title = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthProposal
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Description = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 3:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthProposal
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 4:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Deposit", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthProposal
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Deposit = append(m.Deposit, types.Coin{})
+ if err := m.Deposit[len(m.Deposit)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipProposal(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if (skippy < 0) || (iNdEx+skippy) < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func (m *CommunityPoolWithdrawProposal) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: CommunityPoolWithdrawProposal: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: CommunityPoolWithdrawProposal: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthProposal
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Title = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthProposal
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Description = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 3:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthProposal
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipProposal(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if (skippy < 0) || (iNdEx+skippy) < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func (m *CommunityPoolWithdrawProposalJSON) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: CommunityPoolWithdrawProposalJSON: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: CommunityPoolWithdrawProposalJSON: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthProposal
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Title = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthProposal
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Description = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 3:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthProposal
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 4:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Deposit", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthProposal
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Deposit = append(m.Deposit, types.Coin{})
+ if err := m.Deposit[len(m.Deposit)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipProposal(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if (skippy < 0) || (iNdEx+skippy) < 0 {
+ return ErrInvalidLengthProposal
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func skipProposal(dAtA []byte) (n int, err error) {
+ l := len(dAtA)
+ iNdEx := 0
+ depth := 0
+ for iNdEx < l {
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return 0, ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return 0, io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= (uint64(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ wireType := int(wire & 0x7)
+ switch wireType {
+ case 0:
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return 0, ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return 0, io.ErrUnexpectedEOF
+ }
+ iNdEx++
+ if dAtA[iNdEx-1] < 0x80 {
+ break
+ }
+ }
+ case 1:
+ iNdEx += 8
+ case 2:
+ var length int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return 0, ErrIntOverflowProposal
+ }
+ if iNdEx >= l {
+ return 0, io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ length |= (int(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if length < 0 {
+ return 0, ErrInvalidLengthProposal
+ }
+ iNdEx += length
+ case 3:
+ depth++
+ case 4:
+ if depth == 0 {
+ return 0, ErrUnexpectedEndOfGroupProposal
+ }
+ depth--
+ case 5:
+ iNdEx += 4
+ default:
+ return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
+ }
+ if iNdEx < 0 {
+ return 0, ErrInvalidLengthProposal
+ }
+ if depth == 0 {
+ return iNdEx, nil
+ }
+ }
+ return 0, io.ErrUnexpectedEOF
+}
+
+var (
+ ErrInvalidLengthProposal = fmt.Errorf("proto: negative length found during unmarshaling")
+ ErrIntOverflowProposal = fmt.Errorf("proto: integer overflow")
+ ErrUnexpectedEndOfGroupProposal = fmt.Errorf("proto: unexpected end of group")
+)
diff --git a/x/hard/keeper/interest_test.go b/x/hard/keeper/interest_test.go
index fdc20c8c..1c55e267 100644
--- a/x/hard/keeper/interest_test.go
+++ b/x/hard/keeper/interest_test.go
@@ -445,6 +445,22 @@ func (suite *InterestTestSuite) TestAPYToSPY() {
},
false,
},
+ {
+ "5% apy",
+ args{
+ apy: sdk.MustNewDecFromStr("1.05"),
+ expectedValue: sdk.MustNewDecFromStr("1.000000001547125958"),
+ },
+ false,
+ },
+ {
+ "25% apy",
+ args{
+ apy: sdk.MustNewDecFromStr("1.25"),
+ expectedValue: sdk.MustNewDecFromStr("1.000000007075835620"),
+ },
+ false,
+ },
{
"medium-high apy",
args{
diff --git a/x/kavadist/types/keys.go b/x/kavadist/types/keys.go
index 82ed8361..bb246cd3 100644
--- a/x/kavadist/types/keys.go
+++ b/x/kavadist/types/keys.go
@@ -18,6 +18,9 @@ const (
// KavaDistMacc module account for kavadist
KavaDistMacc = ModuleName
+
+ // Treasury
+ FundModuleAccount = "kava-fund"
)
var (
diff --git a/x/router/keeper/msg_server.go b/x/router/keeper/msg_server.go
index 72015426..76032968 100644
--- a/x/router/keeper/msg_server.go
+++ b/x/router/keeper/msg_server.go
@@ -129,12 +129,12 @@ func (m msgServer) WithdrawBurn(goCtx context.Context, msg *types.MsgWithdrawBur
return nil, err
}
- err = m.keeper.earnKeeper.Withdraw(ctx, depositor, tokenAmount, earntypes.STRATEGY_TYPE_SAVINGS)
+ withdrawnAmount, err := m.keeper.earnKeeper.Withdraw(ctx, depositor, tokenAmount, earntypes.STRATEGY_TYPE_SAVINGS)
if err != nil {
return nil, err
}
- _, err = m.keeper.liquidKeeper.BurnDerivative(ctx, depositor, val, tokenAmount)
+ _, err = m.keeper.liquidKeeper.BurnDerivative(ctx, depositor, val, withdrawnAmount)
if err != nil {
return nil, err
}
@@ -169,12 +169,12 @@ func (m msgServer) WithdrawBurnUndelegate(goCtx context.Context, msg *types.MsgW
return nil, err
}
- err = m.keeper.earnKeeper.Withdraw(ctx, depositor, tokenAmount, earntypes.STRATEGY_TYPE_SAVINGS)
+ withdrawnAmount, err := m.keeper.earnKeeper.Withdraw(ctx, depositor, tokenAmount, earntypes.STRATEGY_TYPE_SAVINGS)
if err != nil {
return nil, err
}
- sharesReturned, err := m.keeper.liquidKeeper.BurnDerivative(ctx, depositor, val, tokenAmount)
+ sharesReturned, err := m.keeper.liquidKeeper.BurnDerivative(ctx, depositor, val, withdrawnAmount)
if err != nil {
return nil, err
}
diff --git a/x/router/types/expected_keepers.go b/x/router/types/expected_keepers.go
index 4a3dd382..8cc01636 100644
--- a/x/router/types/expected_keepers.go
+++ b/x/router/types/expected_keepers.go
@@ -30,5 +30,5 @@ type LiquidKeeper interface {
type EarnKeeper interface {
Deposit(ctx sdk.Context, depositor sdk.AccAddress, amount sdk.Coin, depositStrategy earntypes.StrategyType) error
- Withdraw(ctx sdk.Context, from sdk.AccAddress, wantAmount sdk.Coin, withdrawStrategy earntypes.StrategyType) error
+ Withdraw(ctx sdk.Context, from sdk.AccAddress, wantAmount sdk.Coin, withdrawStrategy earntypes.StrategyType) (sdk.Coin, error)
}