github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/order/match/periodicauction/match_test.go (about)

     1  //go:build ignore
     2  
     3  package periodicauction
     4  
     5  import (
     6  	"math/rand"
     7  	"strconv"
     8  	"testing"
     9  
    10  	"github.com/fibonacci-chain/fbc/x/dex"
    11  	orderkeeper "github.com/fibonacci-chain/fbc/x/order/keeper"
    12  
    13  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/fibonacci-chain/fbc/x/order/types"
    17  )
    18  
    19  type BookItemTestData struct {
    20  	Price        string
    21  	BuyQuantity  string
    22  	SellQuantity string
    23  }
    24  
    25  type MatchTestData struct {
    26  	items          []BookItemTestData
    27  	pricePrecision int64
    28  	refPrice       string
    29  	output         string
    30  }
    31  
    32  func runPeriodicAuctionMatchPriceTest(t *testing.T, testData *MatchTestData, check bool) {
    33  	book := types.DepthBook{}
    34  	for _, input := range testData.items {
    35  		price, err := sdk.NewDecFromStr(input.Price)
    36  		require.Nil(t, err)
    37  		buy, err := sdk.NewDecFromStr(input.BuyQuantity)
    38  		require.Nil(t, err)
    39  		sell, err := sdk.NewDecFromStr(input.SellQuantity)
    40  		require.Nil(t, err)
    41  		book.Items = append(book.Items, types.DepthBookItem{
    42  			Price:        price,
    43  			BuyQuantity:  buy,
    44  			SellQuantity: sell,
    45  		})
    46  	}
    47  	refPrice, err := sdk.NewDecFromStr(testData.refPrice)
    48  	require.Nil(t, err)
    49  	needres, err := sdk.NewDecFromStr(testData.output)
    50  	require.Nil(t, err)
    51  	bestPrice, _ := periodicAuctionMatchPrice(&book, testData.pricePrecision, refPrice)
    52  	if check {
    53  		if !needres.Equal(bestPrice) {
    54  			t.Fatalf("need:%s calc:%s\n", needres.String(), bestPrice.String())
    55  		}
    56  	}
    57  
    58  }
    59  
    60  func TestPeriodicAuctionMatchPriceRandomData(t *testing.T) {
    61  	for i := 0; i < 10000; i++ {
    62  		n := rand.Int()%200 + 2
    63  		data := MatchTestData{
    64  			pricePrecision: 1,
    65  			refPrice:       "1",
    66  			output:         "98",
    67  		}
    68  		for j := 0; j < n; j++ {
    69  			data.items = append(data.items, BookItemTestData{
    70  				Price:        strconv.Itoa(100 - j),
    71  				BuyQuantity:  strconv.Itoa(rand.Intn(2) * rand.Intn(10)),
    72  				SellQuantity: strconv.Itoa(rand.Intn(2) * rand.Intn(10)),
    73  			})
    74  		}
    75  		runPeriodicAuctionMatchPriceTest(t, &data, false)
    76  	}
    77  }
    78  
    79  func TestPeriodicAuctionMatchPrice(t *testing.T) {
    80  	data := MatchTestData{
    81  		items: []BookItemTestData{{
    82  			"100", "150", "0",
    83  		}, {
    84  			"99", "10", "0",
    85  		}, {
    86  			"98", "0", "250",
    87  		}, {
    88  			"97", "0", "50",
    89  		},
    90  		},
    91  		pricePrecision: 1,
    92  		refPrice:       "1",
    93  		output:         "98",
    94  	}
    95  	runPeriodicAuctionMatchPriceTest(t, &data, true)
    96  }
    97  
    98  func TestPeriodicAuctionMatchPriceRule0(t *testing.T) {
    99  	data := MatchTestData{
   100  		items: []BookItemTestData{{
   101  			"100", "0", "40",
   102  		}, {
   103  			"99", "0", "30",
   104  		}, {
   105  			"98", "80", "0",
   106  		}, {
   107  			"97", "70", "0",
   108  		},
   109  		},
   110  		pricePrecision: 1,
   111  		refPrice:       "1",
   112  		output:         "1",
   113  	}
   114  	runPeriodicAuctionMatchPriceTest(t, &data, true)
   115  }
   116  
   117  func TestPeriodicAuctionMatchPriceRule1(t *testing.T) {
   118  	data := MatchTestData{
   119  		items: []BookItemTestData{{
   120  			"100", "150", "0",
   121  		}, {
   122  			"98", "150", "250",
   123  		}, {
   124  			"97", "0", "50",
   125  		},
   126  		},
   127  		pricePrecision: 1,
   128  		refPrice:       "1",
   129  		output:         "98",
   130  	}
   131  	runPeriodicAuctionMatchPriceTest(t, &data, true)
   132  }
   133  
   134  func TestPeriodicAuctionMatchPriceRule2(t *testing.T) {
   135  	data := MatchTestData{
   136  		items: []BookItemTestData{{
   137  			"102", "30", "0",
   138  		}, {
   139  			"101", "10", "0",
   140  		}, {
   141  			"99", "50", "0",
   142  		}, {
   143  			"98", "0", "10",
   144  		}, {
   145  			"97", "0", "50",
   146  		}, {
   147  			"96", "15", "0",
   148  		}, {
   149  			"95", "0", "50",
   150  		},
   151  		},
   152  		pricePrecision: 1,
   153  		refPrice:       "1",
   154  		output:         "97",
   155  	}
   156  	runPeriodicAuctionMatchPriceTest(t, &data, true)
   157  }
   158  
   159  func TestPeriodicAuctionMatchPriceRule3A(t *testing.T) {
   160  	data := MatchTestData{
   161  		items: []BookItemTestData{{
   162  			"102", "60", "0",
   163  		}, {
   164  			"100", "0", "20",
   165  		}, {
   166  			"95", "0", "30",
   167  		},
   168  		},
   169  		pricePrecision: 1,
   170  		refPrice:       "100",
   171  		output:         "102",
   172  	}
   173  	runPeriodicAuctionMatchPriceTest(t, &data, true)
   174  }
   175  
   176  func TestPeriodicAuctionMatchPriceRule3B(t *testing.T) {
   177  	data := MatchTestData{
   178  		items: []BookItemTestData{{
   179  			"102", "30", "0",
   180  		}, {
   181  			"97", "20", "0",
   182  		}, {
   183  			"95", "0", "60",
   184  		},
   185  		},
   186  		pricePrecision: 1,
   187  		refPrice:       "96",
   188  		output:         "95",
   189  	}
   190  	runPeriodicAuctionMatchPriceTest(t, &data, true)
   191  }
   192  
   193  func TestPeriodicAuctionMatchPriceRule3C(t *testing.T) {
   194  	data := MatchTestData{
   195  		items: []BookItemTestData{{
   196  			"100", "25", "0",
   197  		}, {
   198  			"98", "0", "35",
   199  		}, {
   200  			"97", "35", "0",
   201  		}, {
   202  			"95", "0", "25",
   203  		},
   204  		},
   205  		pricePrecision: 1,
   206  		refPrice:       "99",
   207  		output:         "99",
   208  	}
   209  	runPeriodicAuctionMatchPriceTest(t, &data, true)
   210  }
   211  
   212  func TestPeriodicAuctionMatchPriceByEmptyDepthBook(t *testing.T) {
   213  	depthBook := &types.DepthBook{}
   214  	bestPrice, maxExecution := periodicAuctionMatchPrice(depthBook, 10, sdk.MustNewDecFromStr("10.0"))
   215  
   216  	require.EqualValues(t, sdk.ZeroDec(), bestPrice)
   217  	require.EqualValues(t, sdk.ZeroDec(), maxExecution)
   218  }
   219  
   220  func TestPreMatchProcessing(t *testing.T) {
   221  	testInput := orderkeeper.CreateTestInput(t)
   222  
   223  	// mock orders, DepthBook, and orderIDsMap
   224  	orders := []*types.Order{
   225  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   226  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   227  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   228  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   229  	}
   230  	orders[0].Sender = testInput.TestAddrs[0]
   231  	orders[1].Sender = testInput.TestAddrs[0]
   232  	orders[2].Sender = testInput.TestAddrs[1]
   233  	orders[3].Sender = testInput.TestAddrs[1]
   234  
   235  	depthBook := &types.DepthBook{}
   236  	for i := 0; i < 4; i++ {
   237  		depthBook.InsertOrder(orders[i])
   238  	}
   239  
   240  	buyAmountSum, sellAmountSum := preMatchProcessing(depthBook)
   241  	require.Equal(t, sdk.NewDec(3), buyAmountSum[1])
   242  	require.Equal(t, sdk.NewDec(4), sellAmountSum[0])
   243  }
   244  
   245  func TestExecRule0(t *testing.T) {
   246  	buyAmountSum := []sdk.Dec{sdk.NewDec(0.0), sdk.NewDec(3.0), sdk.NewDec(3.0)}
   247  	sellAmountSum := []sdk.Dec{sdk.NewDec(4.0), sdk.NewDec(3.0), sdk.NewDec(3.0)}
   248  
   249  	maxExecution, execution := execRule0(buyAmountSum, sellAmountSum)
   250  	require.EqualValues(t, sdk.NewDec(3), maxExecution)
   251  	require.EqualValues(t, sdk.NewDec(3), execution[1])
   252  }
   253  
   254  func TestExecRule1(t *testing.T) {
   255  	maxExecution := sdk.NewDec(3.0)
   256  	execution := []sdk.Dec{sdk.NewDec(0.0), sdk.NewDec(3.0), sdk.NewDec(3.0)}
   257  
   258  	indexesRule1 := execRule1(maxExecution, execution)
   259  	require.EqualValues(t, []int{1, 2}, indexesRule1)
   260  }
   261  
   262  func TestExecRule2(t *testing.T) {
   263  	buyAmountSum := []sdk.Dec{sdk.NewDec(0.0), sdk.NewDec(3.0), sdk.NewDec(3.0)}
   264  	sellAmountSum := []sdk.Dec{sdk.NewDec(4.0), sdk.NewDec(3.0), sdk.NewDec(3.0)}
   265  	indexesRule1 := []int{1, 2}
   266  
   267  	indexesRule2, _ := execRule2(buyAmountSum, sellAmountSum, indexesRule1)
   268  	require.EqualValues(t, []int{1, 2}, indexesRule2)
   269  }
   270  
   271  func TestExecRule3(t *testing.T) {
   272  	testInput := orderkeeper.CreateTestInput(t)
   273  	keeper := testInput.OrderKeeper
   274  	ctx := testInput.Ctx
   275  	tokenPair := dex.GetBuiltInTokenPair()
   276  	err := testInput.DexKeeper.SaveTokenPair(ctx, tokenPair)
   277  	require.Nil(t, err)
   278  
   279  	// mock orders, DepthBook, and orderIDsMap
   280  	orders := []*types.Order{
   281  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   282  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   283  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   284  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   285  	}
   286  	orders[0].Sender = testInput.TestAddrs[0]
   287  	orders[1].Sender = testInput.TestAddrs[0]
   288  	orders[2].Sender = testInput.TestAddrs[1]
   289  	orders[3].Sender = testInput.TestAddrs[1]
   290  	depthBook := &types.DepthBook{}
   291  
   292  	for i := 0; i < 4; i++ {
   293  		err := keeper.PlaceOrder(ctx, orders[i])
   294  		require.NoError(t, err)
   295  		depthBook.InsertOrder(orders[i])
   296  	}
   297  
   298  	indexesRule1 := []int{1, 2}
   299  	refPrice := sdk.NewDec(10.0)
   300  	pricePrecision := tokenPair.MaxPriceDigit
   301  	indexesRule2 := []int{1, 2}
   302  	imbalance := []sdk.Dec{sdk.NewDec(0.0), sdk.NewDec(0.0)}
   303  
   304  	bestPrice := execRule3(depthBook, indexesRule1[0], refPrice, pricePrecision, indexesRule2, imbalance)
   305  	require.EqualValues(t, sdk.NewDec(10), bestPrice)
   306  }
   307  
   308  func TestBestPriceFromRefPrice(t *testing.T) {
   309  	minPrice, err := sdk.NewDecFromStr("10.1")
   310  	require.EqualValues(t, nil, err)
   311  	maxPrice, err := sdk.NewDecFromStr("9.9")
   312  	require.EqualValues(t, nil, err)
   313  	refPrice, err := sdk.NewDecFromStr("10.0")
   314  	require.EqualValues(t, nil, err)
   315  
   316  	bestPrice := bestPriceFromRefPrice(minPrice, maxPrice, refPrice)
   317  	require.EqualValues(t, sdk.NewDec(10), bestPrice)
   318  }
   319  
   320  func TestExpireOrdersInExpiredBlock(t *testing.T) {
   321  	testInput := orderkeeper.CreateTestInput(t)
   322  	keeper := testInput.OrderKeeper
   323  	ctx := testInput.Ctx
   324  	tokenPair := dex.GetBuiltInTokenPair()
   325  	err := testInput.DexKeeper.SaveTokenPair(ctx, tokenPair)
   326  	require.Nil(t, err)
   327  
   328  	orders := []*types.Order{
   329  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   330  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   331  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   332  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   333  	}
   334  	orders[0].Sender = testInput.TestAddrs[0]
   335  	orders[1].Sender = testInput.TestAddrs[0]
   336  	orders[2].Sender = testInput.TestAddrs[1]
   337  	orders[3].Sender = testInput.TestAddrs[1]
   338  
   339  	for i := 0; i < 4; i++ {
   340  		err := keeper.PlaceOrder(ctx, orders[i])
   341  		require.EqualValues(t, nil, err)
   342  	}
   343  
   344  	keeper.DropExpiredOrdersByBlockHeight(ctx, ctx.BlockHeight())
   345  
   346  	order := keeper.GetOrder(ctx, "ID0000000000-1")
   347  	require.NotEqual(t, nil, order)
   348  	require.EqualValues(t, int64(types.OrderStatusExpired), order.Status)
   349  }
   350  
   351  func TestMarkCurBlockToFeatureExpireBlockList(t *testing.T) {
   352  	testInput := orderkeeper.CreateTestInput(t)
   353  	keeper := testInput.OrderKeeper
   354  	ctx := testInput.Ctx
   355  	feeParams := types.DefaultTestParams()
   356  
   357  	markCurBlockToFutureExpireBlockList(ctx, keeper)
   358  	expiredBlocks := keeper.GetExpireBlockHeight(ctx, ctx.BlockHeight()+feeParams.OrderExpireBlocks)
   359  	require.EqualValues(t, 0, expiredBlocks[0])
   360  }
   361  
   362  func TestCleanLastBlockClosedOrders(t *testing.T) {
   363  	testInput := orderkeeper.CreateTestInput(t)
   364  	keeper := testInput.OrderKeeper
   365  	ctx := testInput.Ctx
   366  
   367  	orders := []*types.Order{
   368  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   369  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   370  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   371  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   372  	}
   373  	orders[0].Sender = testInput.TestAddrs[0]
   374  	orders[1].Sender = testInput.TestAddrs[0]
   375  	orders[2].Sender = testInput.TestAddrs[1]
   376  	orders[3].Sender = testInput.TestAddrs[1]
   377  
   378  	for i := 0; i < 4; i++ {
   379  		err := keeper.PlaceOrder(ctx, orders[i])
   380  		require.EqualValues(t, nil, err)
   381  	}
   382  
   383  	keeper.SetLastClosedOrderIDs(ctx, []string{orders[0].OrderID})
   384  
   385  	cleanLastBlockClosedOrders(ctx, keeper)
   386  
   387  	order := keeper.GetOrder(ctx, orders[0].OrderID)
   388  	require.EqualValues(t, (*types.Order)(nil), order)
   389  }
   390  
   391  func TestCacheExpiredBlockToCurrentHeight(t *testing.T) {
   392  	testInput := orderkeeper.CreateTestInput(t)
   393  	keeper := testInput.OrderKeeper
   394  	ctx := testInput.Ctx
   395  
   396  	orders := []*types.Order{
   397  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   398  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   399  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   400  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   401  	}
   402  	orders[0].Sender = testInput.TestAddrs[0]
   403  	orders[1].Sender = testInput.TestAddrs[0]
   404  	orders[2].Sender = testInput.TestAddrs[1]
   405  	orders[3].Sender = testInput.TestAddrs[1]
   406  
   407  	for i := 0; i < 4; i++ {
   408  		err := keeper.PlaceOrder(ctx, orders[i])
   409  		require.EqualValues(t, nil, err)
   410  	}
   411  
   412  	keeper.DropExpiredOrdersByBlockHeight(ctx, ctx.BlockHeight())
   413  	keeper.SetExpireBlockHeight(ctx, ctx.BlockHeight(), []int64{ctx.BlockHeight()})
   414  
   415  	cacheExpiredBlockToCurrentHeight(ctx, keeper)
   416  
   417  	num := keeper.GetCache().GetExpireNum()
   418  	require.EqualValues(t, len(orders), int(num))
   419  }
   420  
   421  func TestCleanupExpiredOrders(t *testing.T) {
   422  	testInput := orderkeeper.CreateTestInput(t)
   423  	keeper := testInput.OrderKeeper
   424  	ctx := testInput.Ctx
   425  	feeParams := types.DefaultTestParams()
   426  
   427  	orders := []*types.Order{
   428  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   429  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   430  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   431  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   432  	}
   433  	orders[0].Sender = testInput.TestAddrs[0]
   434  	orders[1].Sender = testInput.TestAddrs[0]
   435  	orders[2].Sender = testInput.TestAddrs[1]
   436  	orders[3].Sender = testInput.TestAddrs[1]
   437  
   438  	for i := 0; i < 4; i++ {
   439  		err := keeper.PlaceOrder(ctx, orders[i])
   440  		require.EqualValues(t, nil, err)
   441  	}
   442  
   443  	keeper.SetLastClosedOrderIDs(ctx, []string{orders[0].OrderID})
   444  	keeper.ExpireOrder(ctx, orders[1], ctx.Logger())
   445  
   446  	cleanupExpiredOrders(ctx, keeper)
   447  
   448  	expiredBlocks := keeper.GetExpireBlockHeight(ctx, ctx.BlockHeight()+
   449  		feeParams.OrderExpireBlocks)
   450  	require.EqualValues(t, true, expiredBlocks[0] == ctx.BlockHeight())
   451  
   452  	lastClosedOrderIDs := keeper.GetLastClosedOrderIDs(ctx)
   453  	require.EqualValues(t, true, lastClosedOrderIDs[0] == orders[0].OrderID)
   454  
   455  	num := keeper.GetCache().GetExpireNum()
   456  	require.EqualValues(t, 1, int(num))
   457  }
   458  
   459  func TestMatchOrders(t *testing.T) {
   460  	testInput := orderkeeper.CreateTestInput(t)
   461  	keeper := testInput.OrderKeeper
   462  	ctx := testInput.Ctx
   463  	tokenPair := dex.GetBuiltInTokenPair()
   464  	err := testInput.DexKeeper.SaveTokenPair(ctx, tokenPair)
   465  	require.Nil(t, err)
   466  
   467  	// mock orders, DepthBook, and orderIDsMap
   468  	orders := []*types.Order{
   469  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   470  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   471  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   472  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   473  	}
   474  	orders[0].Sender = testInput.TestAddrs[0]
   475  	orders[1].Sender = testInput.TestAddrs[0]
   476  	orders[2].Sender = testInput.TestAddrs[1]
   477  	orders[3].Sender = testInput.TestAddrs[1]
   478  	depthBook := &types.DepthBook{}
   479  
   480  	for i := 0; i < 4; i++ {
   481  		err := keeper.PlaceOrder(ctx, orders[i])
   482  		require.EqualValues(t, nil, err)
   483  		depthBook.InsertOrder(orders[i])
   484  	}
   485  
   486  	matchOrders(ctx, keeper)
   487  
   488  	depthBook = keeper.GetDepthBookCopy(types.TestTokenPair)
   489  	require.EqualValues(t, 1, len(depthBook.Items))
   490  	require.EqualValues(t, sdk.MustNewDecFromStr("10.2"), depthBook.Items[0].Price)
   491  	require.EqualValues(t, sdk.ZeroDec(), depthBook.Items[0].BuyQuantity)
   492  	require.EqualValues(t, sdk.MustNewDecFromStr("1"), depthBook.Items[0].SellQuantity)
   493  
   494  	orders = []*types.Order{
   495  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   496  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   497  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   498  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   499  	}
   500  	orders[0].Sender = testInput.TestAddrs[0]
   501  	orders[1].Sender = testInput.TestAddrs[0]
   502  	orders[2].Sender = testInput.TestAddrs[1]
   503  	orders[3].Sender = testInput.TestAddrs[1]
   504  
   505  	for i := 0; i < 4; i++ {
   506  		err := keeper.PlaceOrder(ctx, orders[i])
   507  		require.EqualValues(t, nil, err)
   508  		depthBook.InsertOrder(orders[i])
   509  	}
   510  	updatedProductsBasePrice := calcMatchPriceAndExecution(ctx, keeper, []string{types.TestTokenPair})
   511  	lockProduct(ctx, keeper, ctx.Logger(), types.TestTokenPair, updatedProductsBasePrice[types.TestTokenPair],
   512  		sdk.ZeroDec(), sdk.ZeroDec())
   513  
   514  	matchOrders(ctx, keeper)
   515  
   516  	depthBook = keeper.GetDepthBookCopy(types.TestTokenPair)
   517  	require.EqualValues(t, 1, len(depthBook.Items))
   518  	require.EqualValues(t, sdk.MustNewDecFromStr("10.2"), depthBook.Items[0].Price)
   519  	require.EqualValues(t, sdk.ZeroDec(), depthBook.Items[0].BuyQuantity)
   520  	require.EqualValues(t, sdk.MustNewDecFromStr("2"), depthBook.Items[0].SellQuantity)
   521  }
   522  
   523  func TestMatchOrdersByEmptyBlock(t *testing.T) {
   524  	testInput := orderkeeper.CreateTestInput(t)
   525  	keeper := testInput.OrderKeeper
   526  	ctx := testInput.Ctx
   527  	tokenPair := dex.GetBuiltInTokenPair()
   528  	err := testInput.DexKeeper.SaveTokenPair(ctx, tokenPair)
   529  	require.Nil(t, err)
   530  
   531  	matchOrders(ctx, keeper)
   532  	require.EqualValues(t, int64(0), keeper.GetBlockOrderNum(ctx, ctx.BlockHeight()))
   533  	require.EqualValues(t, false, keeper.AnyProductLocked(ctx))
   534  }
   535  
   536  func TestCalcMatchPriceAndExecution(t *testing.T) {
   537  	testInput := orderkeeper.CreateTestInput(t)
   538  	keeper := testInput.OrderKeeper
   539  	ctx := testInput.Ctx
   540  	tokenPair := dex.GetBuiltInTokenPair()
   541  	err := testInput.DexKeeper.SaveTokenPair(ctx, tokenPair)
   542  	require.Nil(t, err)
   543  
   544  	// mock orders, DepthBook, and orderIDsMap
   545  	orders := []*types.Order{
   546  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   547  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   548  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   549  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   550  	}
   551  	orders[0].Sender = testInput.TestAddrs[0]
   552  	orders[1].Sender = testInput.TestAddrs[0]
   553  	orders[2].Sender = testInput.TestAddrs[1]
   554  	orders[3].Sender = testInput.TestAddrs[1]
   555  	depthBook := &types.DepthBook{}
   556  
   557  	for i := 0; i < 4; i++ {
   558  		err := keeper.PlaceOrder(ctx, orders[i])
   559  		require.EqualValues(t, nil, err)
   560  		depthBook.InsertOrder(orders[i])
   561  	}
   562  
   563  	products := keeper.GetDiskCache().GetUpdatedDepthbookKeys()
   564  	keeper.GetDexKeeper().SortProducts(ctx, products) // sort products
   565  
   566  	updatedProductsBasePrice := calcMatchPriceAndExecution(ctx, keeper, products)
   567  	matchResult, ok := updatedProductsBasePrice[types.TestTokenPair]
   568  	require.EqualValues(t, ok, true)
   569  	require.EqualValues(t, matchResult.BlockHeight, ctx.BlockHeight())
   570  	require.EqualValues(t, sdk.MustNewDecFromStr("10.0"), matchResult.Price)
   571  	require.EqualValues(t, sdk.MustNewDecFromStr("3.0"), matchResult.Quantity)
   572  }
   573  
   574  func TestLockProduct(t *testing.T) {
   575  	testInput := orderkeeper.CreateTestInput(t)
   576  	keeper := testInput.OrderKeeper
   577  	ctx := testInput.Ctx
   578  	tokenPair := dex.GetBuiltInTokenPair()
   579  	err := testInput.DexKeeper.SaveTokenPair(ctx, tokenPair)
   580  	require.Nil(t, err)
   581  
   582  	// mock orders, DepthBook, and orderIDsMap
   583  	orders := []*types.Order{
   584  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   585  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   586  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   587  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   588  	}
   589  	orders[0].Sender = testInput.TestAddrs[0]
   590  	orders[1].Sender = testInput.TestAddrs[0]
   591  	orders[2].Sender = testInput.TestAddrs[1]
   592  	orders[3].Sender = testInput.TestAddrs[1]
   593  	depthBook := &types.DepthBook{}
   594  
   595  	for i := 0; i < 4; i++ {
   596  		err := keeper.PlaceOrder(ctx, orders[i])
   597  		require.EqualValues(t, nil, err)
   598  		depthBook.InsertOrder(orders[i])
   599  	}
   600  
   601  	updatedProductsBasePrice := calcMatchPriceAndExecution(ctx, keeper, []string{types.TestTokenPair})
   602  
   603  	lockProduct(ctx, keeper, ctx.Logger(), types.TestTokenPair, updatedProductsBasePrice[types.TestTokenPair],
   604  		sdk.ZeroDec(), sdk.ZeroDec())
   605  
   606  	require.EqualValues(t, true, keeper.IsProductLocked(ctx, types.TestTokenPair))
   607  }
   608  
   609  func TestExecuteMatchedUpdatedProduct(t *testing.T) {
   610  	testInput := orderkeeper.CreateTestInput(t)
   611  	keeper := testInput.OrderKeeper
   612  	ctx := testInput.Ctx
   613  	feeParams := types.DefaultTestParams()
   614  	tokenPair := dex.GetBuiltInTokenPair()
   615  	err := testInput.DexKeeper.SaveTokenPair(ctx, tokenPair)
   616  	require.Nil(t, err)
   617  
   618  	// mock orders, DepthBook, and orderIDsMap
   619  	orders := []*types.Order{
   620  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   621  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   622  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   623  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   624  	}
   625  	orders[0].Sender = testInput.TestAddrs[0]
   626  	orders[1].Sender = testInput.TestAddrs[0]
   627  	orders[2].Sender = testInput.TestAddrs[1]
   628  	orders[3].Sender = testInput.TestAddrs[1]
   629  	depthBook := &types.DepthBook{}
   630  
   631  	for i := 0; i < 4; i++ {
   632  		err := keeper.PlaceOrder(ctx, orders[i])
   633  		require.EqualValues(t, nil, err)
   634  		depthBook.InsertOrder(orders[i])
   635  	}
   636  
   637  	updatedProductsBasePrice := calcMatchPriceAndExecution(ctx, keeper, []string{types.TestTokenPair})
   638  
   639  	blockRemainDeals := executeMatchedUpdatedProduct(ctx, keeper, updatedProductsBasePrice, &feeParams,
   640  		1000, types.TestTokenPair, ctx.Logger())
   641  
   642  	require.EqualValues(t, 997, int(blockRemainDeals))
   643  }
   644  
   645  func TestExecuteMatchedUpdatedProductByLimitedBlockDeals(t *testing.T) {
   646  	testInput := orderkeeper.CreateTestInput(t)
   647  	keeper := testInput.OrderKeeper
   648  	ctx := testInput.Ctx
   649  	feeParams := types.DefaultTestParams()
   650  	tokenPair := dex.GetBuiltInTokenPair()
   651  	err := testInput.DexKeeper.SaveTokenPair(ctx, tokenPair)
   652  	require.Nil(t, err)
   653  
   654  	// mock orders, DepthBook, and orderIDsMap
   655  	orders := []*types.Order{
   656  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   657  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   658  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   659  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   660  	}
   661  	orders[0].Sender = testInput.TestAddrs[0]
   662  	orders[1].Sender = testInput.TestAddrs[0]
   663  	orders[2].Sender = testInput.TestAddrs[1]
   664  	orders[3].Sender = testInput.TestAddrs[1]
   665  	depthBook := &types.DepthBook{}
   666  
   667  	for i := 0; i < 4; i++ {
   668  		err := keeper.PlaceOrder(ctx, orders[i])
   669  		require.EqualValues(t, nil, err)
   670  		depthBook.InsertOrder(orders[i])
   671  	}
   672  
   673  	updatedProductsBasePrice := calcMatchPriceAndExecution(ctx, keeper, []string{types.TestTokenPair})
   674  
   675  	blockRemainDeals := executeMatchedUpdatedProduct(ctx, keeper, updatedProductsBasePrice, &feeParams,
   676  		0, types.TestTokenPair, ctx.Logger())
   677  
   678  	require.EqualValues(t, 0, int(blockRemainDeals))
   679  	require.EqualValues(t, true, keeper.IsProductLocked(ctx, types.TestTokenPair))
   680  }
   681  
   682  func TestExecuteLockedProduct(t *testing.T) {
   683  	testInput := orderkeeper.CreateTestInput(t)
   684  	keeper := testInput.OrderKeeper
   685  	ctx := testInput.Ctx
   686  	feeParams := types.DefaultTestParams()
   687  	tokenPair := dex.GetBuiltInTokenPair()
   688  	err := testInput.DexKeeper.SaveTokenPair(ctx, tokenPair)
   689  	require.Nil(t, err)
   690  
   691  	// mock orders, DepthBook, and orderIDsMap
   692  	orders := []*types.Order{
   693  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   694  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   695  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   696  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   697  	}
   698  	orders[0].Sender = testInput.TestAddrs[0]
   699  	orders[1].Sender = testInput.TestAddrs[0]
   700  	orders[2].Sender = testInput.TestAddrs[1]
   701  	orders[3].Sender = testInput.TestAddrs[1]
   702  	depthBook := &types.DepthBook{}
   703  
   704  	for i := 0; i < 4; i++ {
   705  		err := keeper.PlaceOrder(ctx, orders[i])
   706  		require.EqualValues(t, nil, err)
   707  		depthBook.InsertOrder(orders[i])
   708  	}
   709  
   710  	updatedProductsBasePrice := calcMatchPriceAndExecution(ctx, keeper, []string{types.TestTokenPair})
   711  	lockProduct(ctx, keeper, ctx.Logger(), types.TestTokenPair, updatedProductsBasePrice[types.TestTokenPair],
   712  		sdk.ZeroDec(), sdk.ZeroDec())
   713  
   714  	lockMap := keeper.GetDexKeeper().GetLockedProductsCopy(ctx)
   715  
   716  	blockRemainDeals := executeLockedProduct(ctx, keeper, updatedProductsBasePrice, lockMap, &feeParams,
   717  		1000, types.TestTokenPair, ctx.Logger())
   718  
   719  	require.EqualValues(t, 997, int(blockRemainDeals))
   720  }
   721  
   722  func TestExecuteLockedProductByLimitedBlockDeals(t *testing.T) {
   723  	testInput := orderkeeper.CreateTestInput(t)
   724  	keeper := testInput.OrderKeeper
   725  	ctx := testInput.Ctx
   726  	feeParams := types.DefaultTestParams()
   727  	tokenPair := dex.GetBuiltInTokenPair()
   728  	err := testInput.DexKeeper.SaveTokenPair(ctx, tokenPair)
   729  	require.Nil(t, err)
   730  
   731  	// mock orders, DepthBook, and orderIDsMap
   732  	orders := []*types.Order{
   733  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   734  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   735  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   736  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   737  	}
   738  	orders[0].Sender = testInput.TestAddrs[0]
   739  	orders[1].Sender = testInput.TestAddrs[0]
   740  	orders[2].Sender = testInput.TestAddrs[1]
   741  	orders[3].Sender = testInput.TestAddrs[1]
   742  	depthBook := &types.DepthBook{}
   743  
   744  	for i := 0; i < 4; i++ {
   745  		err := keeper.PlaceOrder(ctx, orders[i])
   746  		require.EqualValues(t, nil, err)
   747  		depthBook.InsertOrder(orders[i])
   748  	}
   749  
   750  	updatedProductsBasePrice := calcMatchPriceAndExecution(ctx, keeper, []string{types.TestTokenPair})
   751  	lockProduct(ctx, keeper, ctx.Logger(), types.TestTokenPair, updatedProductsBasePrice[types.TestTokenPair],
   752  		sdk.ZeroDec(), sdk.ZeroDec())
   753  
   754  	lockMap := keeper.GetDexKeeper().GetLockedProductsCopy(ctx)
   755  
   756  	blockRemainDeals := executeLockedProduct(ctx, keeper, updatedProductsBasePrice, lockMap, &feeParams,
   757  		0, types.TestTokenPair, ctx.Logger())
   758  
   759  	require.EqualValues(t, 0, int(blockRemainDeals))
   760  }
   761  
   762  func TestExecuteLockedProductByLargeLockQuantity(t *testing.T) {
   763  	testInput := orderkeeper.CreateTestInput(t)
   764  	keeper := testInput.OrderKeeper
   765  	ctx := testInput.Ctx
   766  	feeParams := types.DefaultTestParams()
   767  	tokenPair := dex.GetBuiltInTokenPair()
   768  	err := testInput.DexKeeper.SaveTokenPair(ctx, tokenPair)
   769  	require.Nil(t, err)
   770  
   771  	// mock orders, DepthBook, and orderIDsMap
   772  	orders := []*types.Order{
   773  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   774  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   775  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   776  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   777  	}
   778  	orders[0].Sender = testInput.TestAddrs[0]
   779  	orders[1].Sender = testInput.TestAddrs[0]
   780  	orders[2].Sender = testInput.TestAddrs[1]
   781  	orders[3].Sender = testInput.TestAddrs[1]
   782  	depthBook := &types.DepthBook{}
   783  
   784  	for i := 0; i < 4; i++ {
   785  		err := keeper.PlaceOrder(ctx, orders[i])
   786  		require.EqualValues(t, nil, err)
   787  		depthBook.InsertOrder(orders[i])
   788  	}
   789  
   790  	updatedProductsBasePrice := calcMatchPriceAndExecution(ctx, keeper, []string{types.TestTokenPair})
   791  	lockProduct(ctx, keeper, ctx.Logger(), types.TestTokenPair, updatedProductsBasePrice[types.TestTokenPair],
   792  		sdk.ZeroDec(), sdk.ZeroDec())
   793  
   794  	lockMap := keeper.GetDexKeeper().GetLockedProductsCopy(ctx)
   795  	lock := lockMap.Data[types.TestTokenPair]
   796  	lock.Quantity = lock.Quantity.Add(sdk.NewDec(100))
   797  
   798  	blockRemainDeals := executeLockedProduct(ctx, keeper, updatedProductsBasePrice, lockMap, &feeParams,
   799  		1000, types.TestTokenPair, ctx.Logger())
   800  
   801  	require.EqualValues(t, 997, int(blockRemainDeals))
   802  }
   803  
   804  func TestExecuteMatch(t *testing.T) {
   805  	testInput := orderkeeper.CreateTestInput(t)
   806  	keeper := testInput.OrderKeeper
   807  	ctx := testInput.Ctx
   808  	tokenPair := dex.GetBuiltInTokenPair()
   809  	err := testInput.DexKeeper.SaveTokenPair(ctx, tokenPair)
   810  	require.Nil(t, err)
   811  
   812  	// mock orders, DepthBook, and orderIDsMap
   813  	orders := []*types.Order{
   814  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   815  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   816  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   817  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   818  	}
   819  	orders[0].Sender = testInput.TestAddrs[0]
   820  	orders[1].Sender = testInput.TestAddrs[0]
   821  	orders[2].Sender = testInput.TestAddrs[1]
   822  	orders[3].Sender = testInput.TestAddrs[1]
   823  	depthBook := &types.DepthBook{}
   824  
   825  	for i := 0; i < 4; i++ {
   826  		err := keeper.PlaceOrder(ctx, orders[i])
   827  		require.EqualValues(t, nil, err)
   828  		depthBook.InsertOrder(orders[i])
   829  	}
   830  
   831  	products := keeper.GetDiskCache().GetUpdatedDepthbookKeys()
   832  	keeper.GetDexKeeper().SortProducts(ctx, products) // sort products
   833  	updatedProductsBasePrice := calcMatchPriceAndExecution(ctx, keeper, products)
   834  	lockMap := keeper.GetDexKeeper().GetLockedProductsCopy(ctx)
   835  	for product := range lockMap.Data {
   836  		products = append(products, product)
   837  	}
   838  	keeper.GetDexKeeper().SortProducts(ctx, products) // sort products
   839  
   840  	executeMatch(ctx, keeper, products, updatedProductsBasePrice, lockMap)
   841  
   842  	depthBook = keeper.GetDepthBookCopy(types.TestTokenPair)
   843  	require.EqualValues(t, 1, len(depthBook.Items))
   844  	require.EqualValues(t, sdk.MustNewDecFromStr("10.2"), depthBook.Items[0].Price)
   845  	require.EqualValues(t, sdk.ZeroDec(), depthBook.Items[0].BuyQuantity)
   846  	require.EqualValues(t, sdk.MustNewDecFromStr("1"), depthBook.Items[0].SellQuantity)
   847  }
   848  
   849  func TestCleanupOrdersWhoseTokenPairHaveBeenDelisted(t *testing.T) {
   850  	testInput := orderkeeper.CreateTestInput(t)
   851  	keeper := testInput.OrderKeeper
   852  	ctx := testInput.Ctx
   853  
   854  	// mock orders, DepthBook, and orderIDsMap
   855  	orders := []*types.Order{
   856  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "1.0"),
   857  		mockOrder("", types.TestTokenPair, types.BuyOrder, "10.1", "2.0"),
   858  		mockOrder("", types.TestTokenPair, types.SellOrder, "9.9", "3.0"),
   859  		mockOrder("", types.TestTokenPair, types.SellOrder, "10.2", "1.0"),
   860  	}
   861  	orders[0].Sender = testInput.TestAddrs[0]
   862  	orders[1].Sender = testInput.TestAddrs[0]
   863  	orders[2].Sender = testInput.TestAddrs[1]
   864  	orders[3].Sender = testInput.TestAddrs[1]
   865  	depthBook := &types.DepthBook{}
   866  
   867  	for i := 0; i < 4; i++ {
   868  		err := keeper.PlaceOrder(ctx, orders[i])
   869  		require.EqualValues(t, nil, err)
   870  		depthBook.InsertOrder(orders[i])
   871  	}
   872  
   873  	cleanupOrdersWhoseTokenPairHaveBeenDelisted(ctx, keeper)
   874  
   875  	depthBook = keeper.GetDepthBookCopy(types.TestTokenPair)
   876  	require.EqualValues(t, 0, len(depthBook.Items))
   877  
   878  }