diff --git a/x/bundles/keeper/keeper_suite_funding_bundles_test.go b/x/bundles/keeper/keeper_suite_funding_bundles_test.go index 25bf36e7..7f5adafa 100644 --- a/x/bundles/keeper/keeper_suite_funding_bundles_test.go +++ b/x/bundles/keeper/keeper_suite_funding_bundles_test.go @@ -33,6 +33,10 @@ var _ = Describe("funding bundles", Ordered, func() { // init new clean chain s = i.NewCleanChain() + params := s.App().FundersKeeper.GetParams(s.Ctx()) + params.MinFundingMultiple = 0 + s.App().FundersKeeper.SetParams(s.Ctx(), params) + // create clean pool for every test case gov := s.App().GovKeeper.GetGovernanceAccount(s.Ctx()).GetAddress().String() msg := &pooltypes.MsgCreatePool{ diff --git a/x/bundles/keeper/keeper_suite_inflation_splitting_test.go b/x/bundles/keeper/keeper_suite_inflation_splitting_test.go index 95b44312..65f650fc 100644 --- a/x/bundles/keeper/keeper_suite_inflation_splitting_test.go +++ b/x/bundles/keeper/keeper_suite_inflation_splitting_test.go @@ -63,6 +63,7 @@ var _ = Describe("inflation splitting", Ordered, func() { params := s.App().FundersKeeper.GetParams(s.Ctx()) params.MinFundingAmountPerBundle = 1_000 params.MinFundingAmount = 100 + params.MinFundingMultiple = 0 s.App().FundersKeeper.SetParams(s.Ctx(), params) // create funders diff --git a/x/funders/keeper/logic_funders.go b/x/funders/keeper/logic_funders.go index 7e850d84..36582723 100644 --- a/x/funders/keeper/logic_funders.go +++ b/x/funders/keeper/logic_funders.go @@ -103,7 +103,6 @@ func (k Keeper) GetLowestFunding(fundings []types.Funding) (lowestFunding *types // // and minimum funding amount func (k Keeper) ensureParamsCompatibility(ctx sdk.Context, funding types.Funding) error { - params := k.GetParams(ctx) if funding.AmountPerBundle < params.MinFundingAmountPerBundle { return errors.Wrapf(errorsTypes.ErrInvalidRequest, types.ErrAmountPerBundleTooLow.Error(), params.MinFundingAmountPerBundle) @@ -111,6 +110,9 @@ func (k Keeper) ensureParamsCompatibility(ctx sdk.Context, funding types.Funding if funding.Amount < params.MinFundingAmount { return errors.Wrapf(errorsTypes.ErrInvalidRequest, types.ErrMinFundingAmount.Error(), params.MinFundingAmount) } + if funding.AmountPerBundle*params.MinFundingMultiple > funding.Amount { + return errors.Wrapf(errorsTypes.ErrInvalidRequest, types.ErrMinFundingMultiple.Error(), funding.AmountPerBundle, params.MinFundingAmount, funding.Amount) + } return nil } @@ -124,7 +126,6 @@ func (k Keeper) ensureParamsCompatibility(ctx sdk.Context, funding types.Funding // new funding can be added. // CONTRACT: no KV Writing on newFunding and fundingState func (k Keeper) ensureFreeSlot(ctx sdk.Context, newFunding *types.Funding, fundingState *types.FundingState) error { - activeFundings := k.GetActiveFundings(ctx, *fundingState) // check if slots are still available if len(activeFundings) < types.MaxFunders { diff --git a/x/funders/keeper/logic_funders_test.go b/x/funders/keeper/logic_funders_test.go index b2bf876c..d49dfff2 100644 --- a/x/funders/keeper/logic_funders_test.go +++ b/x/funders/keeper/logic_funders_test.go @@ -49,6 +49,10 @@ var _ = Describe("logic_funders.go", Ordered, func() { } s.RunTxPoolSuccess(msg) + params := s.App().FundersKeeper.GetParams(s.Ctx()) + params.MinFundingMultiple = 5 + s.App().FundersKeeper.SetParams(s.Ctx(), params) + // create funder s.RunTxFundersSuccess(&funderstypes.MsgCreateFunder{ Creator: i.ALICE, diff --git a/x/funders/keeper/msg_server_fund_pool.go b/x/funders/keeper/msg_server_fund_pool.go index 82a7736f..8fd3cbcb 100644 --- a/x/funders/keeper/msg_server_fund_pool.go +++ b/x/funders/keeper/msg_server_fund_pool.go @@ -15,7 +15,6 @@ import ( // If the funders list is full, it checks if the funder wants to fund // more than the current lowest funder. If so, the current lowest funder // will get their tokens back and removed form the active funders list. -// TODO: what if amount_per_bundle is higher than the amount? A funder that knows that he is the next uploader could just fund a huge amount which gets payed to only himself. func (k msgServer) FundPool(goCtx context.Context, msg *types.MsgFundPool) (*types.MsgFundPoolResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) diff --git a/x/funders/keeper/msg_server_fund_pool_test.go b/x/funders/keeper/msg_server_fund_pool_test.go index 50a44e19..ab1d5ddc 100644 --- a/x/funders/keeper/msg_server_fund_pool_test.go +++ b/x/funders/keeper/msg_server_fund_pool_test.go @@ -1,6 +1,8 @@ package keeper_test import ( + "fmt" + i "github.com/KYVENetwork/chain/testutil/integration" funderstypes "github.com/KYVENetwork/chain/x/funders/types" pooltypes "github.com/KYVENetwork/chain/x/pool/types" @@ -417,4 +419,17 @@ var _ = Describe("msg_server_fund_pool.go", Ordered, func() { AmountPerBundle: 1, }) }) + + It("Try to fund without fulfilling min_funding_multiple", func() { + // ASSERT + res, err := s.RunTx(&funderstypes.MsgFundPool{ + Creator: i.ALICE, + PoolId: 0, + Amount: 2 * i.KYVE, + AmountPerBundle: 1 * i.KYVE, + }) + fmt.Println(res) + fmt.Println(err.Error()) + Expect(err.Error()).To(Equal("per_bundle_amount (1000000000kyve) times min_funding_multiple (1000000000) is smaller than funded_amount (2000000000kyve): invalid request")) + }) }) diff --git a/x/funders/types/errors.go b/x/funders/types/errors.go index 34decf78..d37bfe95 100644 --- a/x/funders/types/errors.go +++ b/x/funders/types/errors.go @@ -6,13 +6,13 @@ import ( // x/funders module sentinel errors var ( - ErrFunderAlreadyExists = errors.Register(ModuleName, 1100, "funder with address %v already exists") - ErrFunderDoesNotExist = errors.Register(ModuleName, 1101, "funder with address %v does not exist") - ErrFundsTooLow = errors.Register(ModuleName, 1102, "minimum funding amount of %vkyve not reached") - ErrAmountPerBundleTooLow = errors.Register(ModuleName, 1103, "minimum amount per bundle of %vkyve not reached") - ErrMinFundingAmount = errors.Register(ModuleName, 1104, "minimum funding amount of %vkyve not reached") - ErrFundingDoesNotExist = errors.Register(ModuleName, 1105, "funding for pool %v and funder %v does not exist") - ErrFundingIsUsedUp = errors.Register(ModuleName, 1106, "funding for pool %v and funder %v is used up") - + ErrFunderAlreadyExists = errors.Register(ModuleName, 1100, "funder with address %v already exists") + ErrFunderDoesNotExist = errors.Register(ModuleName, 1101, "funder with address %v does not exist") + ErrFundsTooLow = errors.Register(ModuleName, 1102, "minimum funding amount of %vkyve not reached") + ErrAmountPerBundleTooLow = errors.Register(ModuleName, 1103, "minimum amount per bundle of %vkyve not reached") + ErrMinFundingAmount = errors.Register(ModuleName, 1104, "minimum funding amount of %vkyve not reached") + ErrFundingDoesNotExist = errors.Register(ModuleName, 1105, "funding for pool %v and funder %v does not exist") + ErrFundingIsUsedUp = errors.Register(ModuleName, 1106, "funding for pool %v and funder %v is used up") ErrFundingStateDoesNotExist = errors.Register(ModuleName, 1107, "funding state for pool %v does not exist") + ErrMinFundingMultiple = errors.Register(ModuleName, 1108, "per_bundle_amount (%dkyve) times min_funding_multiple (%d) is smaller than funded_amount (%vkyve)") ) diff --git a/x/funders/types/msgs.go b/x/funders/types/msgs.go index 77d512f0..e568d11e 100644 --- a/x/funders/types/msgs.go +++ b/x/funders/types/msgs.go @@ -1,8 +1,10 @@ package types import ( - "cosmossdk.io/errors" "encoding/json" + + "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" )