From 2fdddd664d8cb9635876fab8c3b4dbb643f51b9f Mon Sep 17 00:00:00 2001 From: Hanjun Kim Date: Tue, 19 Apr 2022 15:56:52 +0900 Subject: [PATCH] fix: check if the orderer has sufficient balance to make an order Note that there already exists such check. This commit fixes the problem when the orderer has less balances than the offer coin, but has enough balances to make the order. Since this fix, orders cannot make an order with too much offer coin. --- x/liquidity/keeper/swap.go | 14 +++++++++++++ x/liquidity/keeper/swap_test.go | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/x/liquidity/keeper/swap.go b/x/liquidity/keeper/swap.go index 7c87c0718..937309edf 100644 --- a/x/liquidity/keeper/swap.go +++ b/x/liquidity/keeper/swap.go @@ -16,6 +16,13 @@ import ( // ValidateMsgLimitOrder validates types.MsgLimitOrder with state and returns // calculated offer coin and price that is fit into ticks. func (k Keeper) ValidateMsgLimitOrder(ctx sdk.Context, msg *types.MsgLimitOrder) (offerCoin sdk.Coin, price sdk.Dec, err error) { + spendable := k.bankKeeper.SpendableCoins(ctx, msg.GetOrderer()) + if spendableAmt := spendable.AmountOf(msg.OfferCoin.Denom); spendableAmt.LT(msg.OfferCoin.Amount) { + return sdk.Coin{}, sdk.Dec{}, sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, "%s is smaller than %s", + sdk.NewCoin(msg.OfferCoin.Denom, spendableAmt), msg.OfferCoin) + } + params := k.GetParams(ctx) if msg.OrderLifespan > params.MaxOrderLifespan { @@ -122,6 +129,13 @@ func (k Keeper) LimitOrder(ctx sdk.Context, msg *types.MsgLimitOrder) (types.Ord // ValidateMsgMarketOrder validates types.MsgMarketOrder with state and returns // calculated offer coin and price. func (k Keeper) ValidateMsgMarketOrder(ctx sdk.Context, msg *types.MsgMarketOrder) (offerCoin sdk.Coin, price sdk.Dec, err error) { + spendable := k.bankKeeper.SpendableCoins(ctx, msg.GetOrderer()) + if spendableAmt := spendable.AmountOf(msg.OfferCoin.Denom); spendableAmt.LT(msg.OfferCoin.Amount) { + return sdk.Coin{}, sdk.Dec{}, sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, "%s is smaller than %s", + sdk.NewCoin(msg.OfferCoin.Denom, spendableAmt), msg.OfferCoin) + } + params := k.GetParams(ctx) if msg.OrderLifespan > params.MaxOrderLifespan { diff --git a/x/liquidity/keeper/swap_test.go b/x/liquidity/keeper/swap_test.go index 6fdb665ba..4e0a7f8c6 100644 --- a/x/liquidity/keeper/swap_test.go +++ b/x/liquidity/keeper/swap_test.go @@ -4,6 +4,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" utils "github.com/cosmosquad-labs/squad/types" "github.com/cosmosquad-labs/squad/x/liquidity" @@ -113,6 +114,23 @@ func (s *KeeperTestSuite) TestLimitOrder() { } } +func (s *KeeperTestSuite) TestLimitOrderInsufficientOfferCoin() { + pair := s.createPair(s.addr(0), "denom1", "denom2", true) + + orderer := s.addr(1) + s.fundAddr(orderer, utils.ParseCoins("1000000denom2")) + _, err := s.keeper.LimitOrder(s.ctx, types.NewMsgLimitOrder( + orderer, pair.Id, types.OrderDirectionBuy, utils.ParseCoin("1000001denom2"), "denom1", + utils.ParseDec("1.0"), sdk.NewInt(1000000), 0)) + s.Require().ErrorIs(err, sdkerrors.ErrInsufficientFunds) + + s.fundAddr(orderer, utils.ParseCoins("1000000denom1")) + _, err = s.keeper.LimitOrder(s.ctx, types.NewMsgLimitOrder( + orderer, pair.Id, types.OrderDirectionSell, utils.ParseCoin("1000001denom1"), "denom2", + utils.ParseDec("1.0"), sdk.NewInt(1000000), 0)) + s.Require().ErrorIs(err, sdkerrors.ErrInsufficientFunds) +} + func (s *KeeperTestSuite) TestLimitOrderRefund() { pair := s.createPair(s.addr(0), "denom1", "denom2", true) orderer := s.addr(1) @@ -196,6 +214,23 @@ func (s *KeeperTestSuite) TestMarketOrder() { s.Require().True(coinsEq(utils.ParseCoins("10800denom2"), s.getBalances(s.addr(4)))) } +func (s *KeeperTestSuite) TestMarketOrderInsufficientOfferCoin() { + pair := s.createPair(s.addr(0), "denom1", "denom2", true) + + orderer := s.addr(1) + s.fundAddr(orderer, utils.ParseCoins("1000000denom2")) + _, err := s.keeper.MarketOrder(s.ctx, types.NewMsgMarketOrder( + orderer, pair.Id, types.OrderDirectionBuy, utils.ParseCoin("1000001denom2"), "denom1", + sdk.NewInt(1000000), 0)) + s.Require().ErrorIs(err, sdkerrors.ErrInsufficientFunds) + + s.fundAddr(orderer, utils.ParseCoins("1000000denom1")) + _, err = s.keeper.MarketOrder(s.ctx, types.NewMsgMarketOrder( + orderer, pair.Id, types.OrderDirectionSell, utils.ParseCoin("1000001denom1"), "denom2", + sdk.NewInt(1000000), 0)) + s.Require().ErrorIs(err, sdkerrors.ErrInsufficientFunds) +} + func (s *KeeperTestSuite) TestMarketOrderRefund() { pair := s.createPair(s.addr(0), "denom1", "denom2", true) p := utils.ParseDec("1.0")