diff --git a/app/testutil/amm.go b/app/testutil/amm.go index 1c197e01..651273d5 100644 --- a/app/testutil/amm.go +++ b/app/testutil/amm.go @@ -29,6 +29,20 @@ func (s *TestSuite) AddLiquidity(ownerAddr sdk.AccAddress, poolId uint64, lowerP return } +func (s *TestSuite) AddLiquidityByLiquidity(ownerAddr sdk.AccAddress, poolId uint64, lowerPrice, upperPrice sdk.Dec, desiredLiquidity sdk.Int) (position ammtypes.Position, liquidity sdk.Int, amt sdk.Coins) { + s.T().Helper() + pool := s.App.AMMKeeper.MustGetPool(s.Ctx, poolId) + poolState := s.App.AMMKeeper.MustGetPoolState(s.Ctx, poolId) + amt0, amt1 := ammtypes.AmountsForLiquidity( + utils.DecApproxSqrt(poolState.CurrentPrice), + utils.DecApproxSqrt(lowerPrice), + utils.DecApproxSqrt(upperPrice), + desiredLiquidity) + return s.AddLiquidity( + ownerAddr, pool.Id, lowerPrice, upperPrice, + sdk.NewCoins(sdk.NewCoin(pool.Denom0, amt0), sdk.NewCoin(pool.Denom1, amt1))) +} + func (s *TestSuite) RemoveLiquidity(ownerAddr sdk.AccAddress, positionId uint64, liquidity sdk.Int) (position ammtypes.Position, amt sdk.Coins) { s.T().Helper() var err error diff --git a/x/amm/keeper/grpc_query_test.go b/x/amm/keeper/grpc_query_test.go index c7850bde..38419848 100644 --- a/x/amm/keeper/grpc_query_test.go +++ b/x/amm/keeper/grpc_query_test.go @@ -906,14 +906,9 @@ func (s *KeeperTestSuite) TestQueryOrderBookEdgecase() { market, pool := s.CreateMarketAndPool("ucre", "uusd", utils.ParseDec("0.000000000002410188")) lpAddr := s.FundedAccount(1, enoughCoins) - amt0, amt1 := types.AmountsForLiquidity( - utils.DecApproxSqrt(utils.ParseDec("0.000000000002410188")), - utils.DecApproxSqrt(types.MinPrice), - utils.DecApproxSqrt(types.MaxPrice), - sdk.NewInt(160843141868)) - s.AddLiquidity( + s.AddLiquidityByLiquidity( lpAddr, pool.Id, types.MinPrice, types.MaxPrice, - sdk.NewCoins(sdk.NewCoin(pool.Denom0, amt0), sdk.NewCoin(pool.Denom1, amt1))) + sdk.NewInt(160843141868)) querier := exchangekeeper.Querier{Keeper: s.App.ExchangeKeeper} resp, err := querier.OrderBook(sdk.WrapSDKContext(s.Ctx), &exchangetypes.QueryOrderBookRequest{ @@ -948,27 +943,14 @@ func (s *KeeperTestSuite) TestQueryOrderBookEdgecase2() { market, pool := s.CreateMarketAndPool("ucre", "uusd", utils.ParseDec("1")) lpAddr := s.FundedAccount(1, enoughCoins) - amt0, amt1 := types.AmountsForLiquidity( - utils.DecApproxSqrt(utils.ParseDec("1")), - utils.DecApproxSqrt(types.MinPrice), - utils.DecApproxSqrt(types.MaxPrice), - sdk.NewInt(10)) - s.AddLiquidity( - lpAddr, pool.Id, types.MinPrice, types.MaxPrice, - sdk.NewCoins(sdk.NewCoin(pool.Denom0, amt0), sdk.NewCoin(pool.Denom1, amt1))) + s.AddLiquidityByLiquidity( + lpAddr, pool.Id, types.MinPrice, types.MaxPrice, sdk.NewInt(10)) querier := exchangekeeper.Querier{Keeper: s.App.ExchangeKeeper} resp, err := querier.OrderBook(sdk.WrapSDKContext(s.Ctx), &exchangetypes.QueryOrderBookRequest{ MarketId: market.Id, }) s.Require().NoError(err) - expected := []exchangetypes.OrderBookPriceLevel{ - {P: utils.ParseDec("1000000000000000000000000000000000000.000000000000000000"), Q: utils.ParseDec("9.014670721835706842")}, - } - s.Require().GreaterOrEqual(len(resp.OrderBooks[0].Sells), len(expected)) - for i, level := range expected { - s.AssertEqual(level.P, resp.OrderBooks[0].Sells[i].P) - s.AssertEqual(level.Q, resp.OrderBooks[0].Sells[i].Q) - } - s.Require().Empty(resp.OrderBooks[0].Buys) + // Due to too low liquidity, order book is not displayed. + s.Require().Empty(resp.OrderBooks) } diff --git a/x/amm/keeper/pool_test.go b/x/amm/keeper/pool_test.go index 1498c338..16acf725 100644 --- a/x/amm/keeper/pool_test.go +++ b/x/amm/keeper/pool_test.go @@ -224,3 +224,24 @@ func (s *KeeperTestSuite) TestPoolOrdersEdgecase() { }, nil) s.Require().Len(obs.Levels(), 1) } + +func (s *KeeperTestSuite) TestPoolOrderMaxOrderPriceRatio() { + market := s.CreateMarket("ucre", "uusd") + + mmAddr := s.FundedAccount(1, enoughCoins) + s.MakeLastPrice(market.Id, mmAddr, utils.ParseDec("5")) + + // last price != pool price + pool := s.CreatePool(market.Id, utils.ParseDec("100")) + + s.AddLiquidityByLiquidity( + mmAddr, pool.Id, utils.ParseDec("50"), utils.ParseDec("200"), + sdk.NewInt(1000000)) + + ordererAddr := s.FundedAccount(2, enoughCoins) + s.PlaceLimitOrder( + market.Id, ordererAddr, false, utils.ParseDec("5.05"), sdk.NewDec(100_000000), 0) + + s.AssertEqual(utils.ParseDec("90"), s.keeper.MustGetPoolState(s.Ctx, pool.Id).CurrentPrice) + s.AssertEqual(utils.ParseDec("90"), *s.App.ExchangeKeeper.MustGetMarketState(s.Ctx, market.Id).LastPrice) +} diff --git a/x/amm/keeper/source.go b/x/amm/keeper/source.go index 18c8a166..828528d1 100644 --- a/x/amm/keeper/source.go +++ b/x/amm/keeper/source.go @@ -33,12 +33,19 @@ func (k OrderSource) ConstructMemOrderBookSide( if !found { return nil // no pool found } + maxPriceRatio := k.exchangeKeeper.GetMaxOrderPriceRatio(ctx) + poolState := k.MustGetPoolState(ctx, pool.Id) + minPrice, maxPrice := exchangetypes.OrderPriceLimit(poolState.CurrentPrice, maxPriceRatio) reserveAddr := pool.MustGetReserveAddress() accQty := utils.ZeroDec accQuote := utils.ZeroDec numPriceLevels := 0 k.IteratePoolOrders(ctx, pool, opts.IsBuy, func(price, qty, openQty sdk.Dec) (stop bool) { + if (opts.IsBuy && price.LT(minPrice)) || + (!opts.IsBuy && price.GT(maxPrice)) { + return true + } if opts.ReachedLimit(price, accQty, accQuote, numPriceLevels) { return true } diff --git a/x/amm/types/expected_keepers.go b/x/amm/types/expected_keepers.go index 63e57a42..70604b94 100644 --- a/x/amm/types/expected_keepers.go +++ b/x/amm/types/expected_keepers.go @@ -29,6 +29,7 @@ type BankKeeper interface { } type ExchangeKeeper interface { + GetMaxOrderPriceRatio(ctx sdk.Context) sdk.Dec GetMarket(ctx sdk.Context, marketId uint64) (market exchangetypes.Market, found bool) LookupMarket(ctx sdk.Context, marketId uint64) (found bool) IterateAllMarkets(ctx sdk.Context, cb func(market exchangetypes.Market) (stop bool)) diff --git a/x/exchange/types/market.go b/x/exchange/types/market.go index c8a1c607..651c1c61 100644 --- a/x/exchange/types/market.go +++ b/x/exchange/types/market.go @@ -81,8 +81,8 @@ func (marketState MarketState) Validate() error { return nil } -func OrderPriceLimit(lastPrice, maxOrderPriceRatio sdk.Dec) (minPrice, maxPrice sdk.Dec) { - minPrice = lastPrice.Mul(utils.OneDec.Sub(maxOrderPriceRatio)) - maxPrice = lastPrice.Mul(utils.OneDec.Add(maxOrderPriceRatio)) +func OrderPriceLimit(basePrice, maxOrderPriceRatio sdk.Dec) (minPrice, maxPrice sdk.Dec) { + minPrice = basePrice.Mul(utils.OneDec.Sub(maxOrderPriceRatio)) + maxPrice = basePrice.Mul(utils.OneDec.Add(maxOrderPriceRatio)) return }