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

     1  //go:build ignore
     2  
     3  package order
     4  
     5  import (
     6  	"math/rand"
     7  	"strconv"
     8  	"testing"
     9  	"time"
    10  
    11  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    12  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth"
    13  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/supply"
    14  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    15  	"github.com/stretchr/testify/require"
    16  
    17  	"github.com/fibonacci-chain/fbc/x/common"
    18  	"github.com/fibonacci-chain/fbc/x/dex"
    19  	"github.com/fibonacci-chain/fbc/x/order/keeper"
    20  	"github.com/fibonacci-chain/fbc/x/order/types"
    21  	token "github.com/fibonacci-chain/fbc/x/token/types"
    22  )
    23  
    24  func TestEndBlockerPeriodicMatch(t *testing.T) {
    25  	common.InitConfig()
    26  	mapp, addrKeysSlice := getMockApp(t, 2)
    27  	k := mapp.orderKeeper
    28  	mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}})
    29  
    30  	var startHeight int64 = 10
    31  	ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(startHeight)
    32  	mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply))
    33  
    34  	feeParams := types.DefaultTestParams()
    35  	mapp.orderKeeper.SetParams(ctx, &feeParams)
    36  
    37  	tokenPair := dex.GetBuiltInTokenPair()
    38  	err := mapp.dexKeeper.SaveTokenPair(ctx, tokenPair)
    39  	require.Nil(t, err)
    40  	mapp.dexKeeper.SetOperator(ctx, dex.DEXOperator{
    41  		Address:            tokenPair.Owner,
    42  		HandlingFeeAddress: tokenPair.Owner,
    43  	})
    44  
    45  	// mock orders
    46  	orders := []*types.Order{
    47  		types.MockOrder(types.FormatOrderID(startHeight, 1), types.TestTokenPair, types.BuyOrder, "10.0", "1.0"),
    48  		types.MockOrder(types.FormatOrderID(startHeight, 2), types.TestTokenPair, types.SellOrder, "10.0", "0.5"),
    49  		types.MockOrder(types.FormatOrderID(startHeight, 3), types.TestTokenPair, types.SellOrder, "10.0", "2.5"),
    50  	}
    51  	orders[0].Sender = addrKeysSlice[0].Address
    52  	orders[1].Sender = addrKeysSlice[1].Address
    53  	orders[2].Sender = addrKeysSlice[1].Address
    54  	for i := 0; i < 3; i++ {
    55  		err := k.PlaceOrder(ctx, orders[i])
    56  		require.NoError(t, err)
    57  	}
    58  	// subtract all okb of addr0
    59  	// 100 - 10 - 0.2592
    60  	err = k.LockCoins(ctx, addrKeysSlice[0].Address, sdk.SysCoins{{Denom: common.NativeToken,
    61  		Amount: sdk.MustNewDecFromStr("89.7408")}}, token.LockCoinsTypeQuantity)
    62  	require.NoError(t, err)
    63  
    64  	// call EndBlocker to execute periodic match
    65  	EndBlocker(ctx, k)
    66  
    67  	// check order status
    68  	order0 := k.GetOrder(ctx, orders[0].OrderID)
    69  	order1 := k.GetOrder(ctx, orders[1].OrderID)
    70  	order2 := k.GetOrder(ctx, orders[2].OrderID)
    71  	require.EqualValues(t, types.OrderStatusFilled, order0.Status)
    72  	require.EqualValues(t, types.OrderStatusFilled, order1.Status)
    73  	require.EqualValues(t, types.OrderStatusOpen, order2.Status)
    74  	require.EqualValues(t, sdk.MustNewDecFromStr("2"), order2.RemainQuantity)
    75  
    76  	// check depth book
    77  	depthBook := k.GetDepthBookCopy(types.TestTokenPair)
    78  	require.EqualValues(t, 1, len(depthBook.Items))
    79  	require.EqualValues(t, sdk.MustNewDecFromStr("10.0"), depthBook.Items[0].Price)
    80  	require.True(sdk.DecEq(t, sdk.ZeroDec(), depthBook.Items[0].BuyQuantity))
    81  	require.EqualValues(t, sdk.MustNewDecFromStr("2"), depthBook.Items[0].SellQuantity)
    82  
    83  	depthBookDB := k.GetDepthBookFromDB(ctx, types.TestTokenPair)
    84  	require.EqualValues(t, 1, len(depthBookDB.Items))
    85  	require.EqualValues(t, sdk.MustNewDecFromStr("10.0"), depthBookDB.Items[0].Price)
    86  	require.True(sdk.DecEq(t, sdk.ZeroDec(), depthBookDB.Items[0].BuyQuantity))
    87  	require.EqualValues(t, sdk.MustNewDecFromStr("2"), depthBookDB.Items[0].SellQuantity)
    88  
    89  	// check product price - order ids
    90  	key := types.FormatOrderIDsKey(types.TestTokenPair, sdk.MustNewDecFromStr("10.0"), types.SellOrder)
    91  	orderIDs := k.GetProductPriceOrderIDs(key)
    92  	require.EqualValues(t, 1, len(orderIDs))
    93  	require.EqualValues(t, order2.OrderID, orderIDs[0])
    94  	key = types.FormatOrderIDsKey(types.TestTokenPair, sdk.MustNewDecFromStr("10.0"), types.BuyOrder)
    95  	orderIDs = k.GetProductPriceOrderIDs(key)
    96  	require.EqualValues(t, 0, len(orderIDs))
    97  
    98  	// check block match result
    99  	result := k.GetBlockMatchResult()
   100  	require.EqualValues(t, sdk.MustNewDecFromStr("10.0"), result.ResultMap[types.TestTokenPair].Price)
   101  	require.EqualValues(t, sdk.MustNewDecFromStr("1.0"), result.ResultMap[types.TestTokenPair].Quantity)
   102  	require.EqualValues(t, 3, len(result.ResultMap[types.TestTokenPair].Deals))
   103  	require.EqualValues(t, order0.OrderID, result.ResultMap[types.TestTokenPair].Deals[0].OrderID)
   104  	require.EqualValues(t, order1.OrderID, result.ResultMap[types.TestTokenPair].Deals[1].OrderID)
   105  	require.EqualValues(t, order2.OrderID, result.ResultMap[types.TestTokenPair].Deals[2].OrderID)
   106  	// check closed order id
   107  	closedOrderIDs := k.GetLastClosedOrderIDs(ctx)
   108  	require.Equal(t, 2, len(closedOrderIDs))
   109  	require.Equal(t, orders[0].OrderID, closedOrderIDs[0])
   110  	require.Equal(t, orders[1].OrderID, closedOrderIDs[1])
   111  
   112  	// check account balance
   113  	acc0 := mapp.AccountKeeper.GetAccount(ctx, addrKeysSlice[0].Address)
   114  	acc1 := mapp.AccountKeeper.GetAccount(ctx, addrKeysSlice[1].Address)
   115  	expectCoins0 := sdk.SysCoins{
   116  		sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr("0.2592")),
   117  		sdk.NewDecCoinFromDec(common.TestToken, sdk.MustNewDecFromStr("100.999")), // 100 + 1 * (1 - 0.001)
   118  	}
   119  	expectCoins1 := sdk.SysCoins{
   120  		sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr("109.7308")), // 100 + 10 * (1-0.001) - 0.2592
   121  		sdk.NewDecCoinFromDec(common.TestToken, sdk.MustNewDecFromStr("97")),         // 100 - 0.5 - 2.5
   122  	}
   123  	require.EqualValues(t, expectCoins0.String(), acc0.GetCoins().String())
   124  	require.EqualValues(t, expectCoins1.String(), acc1.GetCoins().String())
   125  
   126  	// check fee pool
   127  	feeCollector := mapp.supplyKeeper.GetModuleAccount(ctx, auth.FeeCollectorName)
   128  	collectedFees := feeCollector.GetCoins()
   129  	require.EqualValues(t, "", collectedFees.String())
   130  }
   131  
   132  func TestEndBlockerPeriodicMatchBusyProduct(t *testing.T) {
   133  	mapp, addrKeysSlice := getMockApp(t, 2)
   134  	k := mapp.orderKeeper
   135  	mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}})
   136  	ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(10)
   137  	mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply))
   138  	feeParams := types.DefaultTestParams()
   139  	feeParams.MaxDealsPerBlock = 2
   140  	k.SetParams(ctx, &feeParams)
   141  
   142  	tokenPair := dex.GetBuiltInTokenPair()
   143  	err := mapp.dexKeeper.SaveTokenPair(ctx, tokenPair)
   144  	require.Nil(t, err)
   145  	mapp.dexKeeper.SetOperator(ctx, dex.DEXOperator{
   146  		Address:            tokenPair.Owner,
   147  		HandlingFeeAddress: tokenPair.Owner,
   148  	})
   149  
   150  	// mock orders
   151  	orders := []*types.Order{
   152  		types.MockOrder("", types.TestTokenPair, types.BuyOrder, "10.0", "1.0"),
   153  		types.MockOrder("", types.TestTokenPair, types.SellOrder, "10.0", "0.5"),
   154  		types.MockOrder("", types.TestTokenPair, types.SellOrder, "10.0", "2.5"),
   155  	}
   156  	orders[0].Sender = addrKeysSlice[0].Address
   157  	orders[1].Sender = addrKeysSlice[1].Address
   158  	orders[2].Sender = addrKeysSlice[1].Address
   159  	for i := 0; i < 3; i++ {
   160  		err := k.PlaceOrder(ctx, orders[i])
   161  		require.NoError(t, err)
   162  	}
   163  
   164  	// ------- call EndBlocker at height 10 -------//
   165  	EndBlocker(ctx, k)
   166  
   167  	// check product lock
   168  	lock := k.GetDexKeeper().GetLockedProductsCopy(ctx).Data[types.TestTokenPair]
   169  	require.NotNil(t, lock)
   170  	require.EqualValues(t, 10, lock.BlockHeight)
   171  	require.EqualValues(t, sdk.MustNewDecFromStr("10.0"), lock.Price)
   172  	require.EqualValues(t, sdk.MustNewDecFromStr("1.0"), lock.Quantity)
   173  	require.EqualValues(t, sdk.MustNewDecFromStr("1.0"), lock.BuyExecuted)
   174  	require.EqualValues(t, sdk.MustNewDecFromStr("0.5"), lock.SellExecuted)
   175  
   176  	// check order status
   177  	order0 := k.GetOrder(ctx, orders[0].OrderID)
   178  	order1 := k.GetOrder(ctx, orders[1].OrderID)
   179  	order2 := k.GetOrder(ctx, orders[2].OrderID)
   180  	require.EqualValues(t, types.OrderStatusFilled, order0.Status)
   181  	require.EqualValues(t, types.OrderStatusFilled, order1.Status)
   182  	require.EqualValues(t, types.OrderStatusOpen, order2.Status)
   183  	require.EqualValues(t, sdk.MustNewDecFromStr("2.5"), order2.RemainQuantity)
   184  
   185  	// check depth book
   186  	depthBook := k.GetDepthBookCopy(types.TestTokenPair)
   187  	require.EqualValues(t, 1, len(depthBook.Items))
   188  	require.EqualValues(t, sdk.MustNewDecFromStr("10.0"), depthBook.Items[0].Price)
   189  	require.True(sdk.DecEq(t, sdk.ZeroDec(), depthBook.Items[0].BuyQuantity))
   190  	require.EqualValues(t, sdk.MustNewDecFromStr("2.5"), depthBook.Items[0].SellQuantity)
   191  
   192  	// check product price - order ids
   193  	key := types.FormatOrderIDsKey(types.TestTokenPair, sdk.MustNewDecFromStr("10.0"), types.SellOrder)
   194  	orderIDs := k.GetProductPriceOrderIDs(key)
   195  	require.EqualValues(t, 1, len(orderIDs))
   196  	require.EqualValues(t, order2.OrderID, orderIDs[0])
   197  	key = types.FormatOrderIDsKey(types.TestTokenPair, sdk.MustNewDecFromStr("10.0"), types.BuyOrder)
   198  	orderIDs = k.GetProductPriceOrderIDs(key)
   199  	require.EqualValues(t, 0, len(orderIDs))
   200  
   201  	// check block match result
   202  	result := k.GetBlockMatchResult()
   203  	require.EqualValues(t, 10, result.ResultMap[types.TestTokenPair].BlockHeight)
   204  	require.EqualValues(t, sdk.MustNewDecFromStr("10.0"), result.ResultMap[types.TestTokenPair].Price)
   205  	require.EqualValues(t, sdk.MustNewDecFromStr("1.0"), result.ResultMap[types.TestTokenPair].Quantity)
   206  	require.EqualValues(t, 2, len(result.ResultMap[types.TestTokenPair].Deals))
   207  	require.EqualValues(t, order0.OrderID, result.ResultMap[types.TestTokenPair].Deals[0].OrderID)
   208  	require.EqualValues(t, order1.OrderID, result.ResultMap[types.TestTokenPair].Deals[1].OrderID)
   209  
   210  	// check account balance
   211  	acc0 := mapp.AccountKeeper.GetAccount(ctx, addrKeysSlice[0].Address)
   212  	acc1 := mapp.AccountKeeper.GetAccount(ctx, addrKeysSlice[1].Address)
   213  	expectCoins0 := sdk.SysCoins{
   214  		sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr("90")),    // 100 - 10
   215  		sdk.NewDecCoinFromDec(common.TestToken, sdk.MustNewDecFromStr("100.999")), // 100 + 1 * (1 - 0.001)
   216  	}
   217  	expectCoins1 := sdk.SysCoins{
   218  		sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr("104.7358")), // 100 + 5 * (1 - 0.001) - 0.2592
   219  		sdk.NewDecCoinFromDec(common.TestToken, sdk.MustNewDecFromStr("97")),         // 100 - 0.5 - 2.5
   220  	}
   221  
   222  	require.EqualValues(t, expectCoins0.String(), acc0.GetCoins().String())
   223  	require.EqualValues(t, expectCoins1.String(), acc1.GetCoins().String())
   224  
   225  	// ------- call EndBlock at height 11, continue filling ------- //
   226  	ctx = mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(11)
   227  	BeginBlocker(ctx, k)
   228  	EndBlocker(ctx, k)
   229  
   230  	// check product lock
   231  	lock = k.GetDexKeeper().GetLockedProductsCopy(ctx).Data[types.TestTokenPair]
   232  	require.Nil(t, lock)
   233  
   234  	// check order status
   235  	order2 = k.GetOrder(ctx, orders[2].OrderID)
   236  	require.EqualValues(t, types.OrderStatusOpen, order2.Status)
   237  	require.EqualValues(t, sdk.MustNewDecFromStr("2.0"), order2.RemainQuantity)
   238  
   239  	// check depth book
   240  	depthBook = k.GetDepthBookCopy(types.TestTokenPair)
   241  	require.EqualValues(t, sdk.MustNewDecFromStr("2.0"), depthBook.Items[0].SellQuantity)
   242  
   243  	// check block match result
   244  	result = k.GetBlockMatchResult()
   245  	require.EqualValues(t, 10, result.ResultMap[types.TestTokenPair].BlockHeight)
   246  	require.EqualValues(t, sdk.MustNewDecFromStr("10.0"), result.ResultMap[types.TestTokenPair].Price)
   247  	require.EqualValues(t, sdk.MustNewDecFromStr("1.0"), result.ResultMap[types.TestTokenPair].Quantity)
   248  	require.EqualValues(t, 1, len(result.ResultMap[types.TestTokenPair].Deals))
   249  	require.EqualValues(t, order2.OrderID, result.ResultMap[types.TestTokenPair].Deals[0].OrderID)
   250  
   251  	// check account balance
   252  	acc0 = mapp.AccountKeeper.GetAccount(ctx, addrKeysSlice[0].Address)
   253  	acc1 = mapp.AccountKeeper.GetAccount(ctx, addrKeysSlice[1].Address)
   254  	expectCoins0 = sdk.SysCoins{
   255  		sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr("90")),    // 100 - 10
   256  		sdk.NewDecCoinFromDec(common.TestToken, sdk.MustNewDecFromStr("100.999")), // 100 + 1 * (1 - 0.001)
   257  	}
   258  	expectCoins1 = sdk.SysCoins{
   259  		sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr("109.7308")), // 100 + 10 * (1 - 0.001) - 0.2592
   260  		sdk.NewDecCoinFromDec(common.TestToken, sdk.MustNewDecFromStr("97")),         // 100 - 0.5 - 2.5
   261  	}
   262  	require.EqualValues(t, expectCoins0.String(), acc0.GetCoins().String())
   263  	require.EqualValues(t, expectCoins1.String(), acc1.GetCoins().String())
   264  }
   265  
   266  func TestEndBlockerDropExpireData(t *testing.T) {
   267  	mapp, addrKeysSlice := getMockApp(t, 2)
   268  	k := mapp.orderKeeper
   269  	mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}})
   270  	ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(10)
   271  	mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply))
   272  	feeParams := types.DefaultTestParams()
   273  	mapp.orderKeeper.SetParams(ctx, &feeParams)
   274  
   275  	tokenPair := dex.GetBuiltInTokenPair()
   276  	err := mapp.dexKeeper.SaveTokenPair(ctx, tokenPair)
   277  	require.Nil(t, err)
   278  
   279  	// mock orders
   280  	orders := []*types.Order{
   281  		types.MockOrder("", types.TestTokenPair, types.BuyOrder, "9.8", "1.0"),
   282  		types.MockOrder("", types.TestTokenPair, types.SellOrder, "10.0", "1.5"),
   283  		types.MockOrder("", types.TestTokenPair, types.BuyOrder, "10.0", "1.0"),
   284  	}
   285  	orders[0].Sender = addrKeysSlice[0].Address
   286  	orders[1].Sender = addrKeysSlice[1].Address
   287  	orders[2].Sender = addrKeysSlice[0].Address
   288  	for i := 0; i < 3; i++ {
   289  		err := k.PlaceOrder(ctx, orders[i])
   290  		require.NoError(t, err)
   291  	}
   292  
   293  	EndBlocker(ctx, k) // update blockMatchResult, updatedOrderIds
   294  
   295  	// check before expire: order, blockOrderNum, blockMatchResult, updatedOrderIDs
   296  	require.NotNil(t, k.GetOrder(ctx, orders[1].OrderID))
   297  	require.EqualValues(t, 3, k.GetBlockOrderNum(ctx, 10))
   298  	blockMatchResult := k.GetBlockMatchResult()
   299  	require.NotNil(t, blockMatchResult)
   300  	updatedOrderIDs := k.GetUpdatedOrderIDs()
   301  	require.EqualValues(t, []string{orders[2].OrderID, orders[1].OrderID}, updatedOrderIDs)
   302  
   303  	ctx = mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(11)
   304  	EndBlocker(ctx, k)
   305  	// call EndBlocker to expire orders
   306  	ctx = mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(10 + feeParams.OrderExpireBlocks)
   307  	param := types.DefaultTestParams()
   308  	mapp.orderKeeper.SetParams(ctx, &param)
   309  	EndBlocker(ctx, k)
   310  
   311  	order0 := k.GetOrder(ctx, orders[0].OrderID)
   312  	order1 := k.GetOrder(ctx, orders[1].OrderID)
   313  	order2 := k.GetOrder(ctx, orders[2].OrderID)
   314  
   315  	require.EqualValues(t, types.OrderStatusExpired, order0.Status)
   316  	require.EqualValues(t, types.OrderStatusPartialFilledExpired, order1.Status)
   317  	require.Nil(t, order2)
   318  
   319  	// call EndBlocker to drop expire orders
   320  	ctx = mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(11 + feeParams.OrderExpireBlocks)
   321  	EndBlocker(ctx, k)
   322  
   323  	// check after expire: order, blockOrderNum, blockMatchResult, updatedOrderIDs
   324  	require.Nil(t, k.GetOrder(ctx, orders[0].OrderID))
   325  	require.Nil(t, k.GetOrder(ctx, orders[1].OrderID))
   326  	require.EqualValues(t, 0, k.GetBlockOrderNum(ctx, 10))
   327  }
   328  
   329  // test order expire when product is busy
   330  func TestEndBlockerExpireOrdersBusyProduct(t *testing.T) {
   331  	mapp, addrKeysSlice := getMockApp(t, 1)
   332  	k := mapp.orderKeeper
   333  	mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}})
   334  	ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(10)
   335  	mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply))
   336  	feeParams := types.DefaultTestParams()
   337  
   338  	tokenPair := dex.GetBuiltInTokenPair()
   339  	err := mapp.dexKeeper.SaveTokenPair(ctx, tokenPair)
   340  	require.Nil(t, err)
   341  	mapp.orderKeeper.SetParams(ctx, &feeParams)
   342  
   343  	// mock orders
   344  	orders := []*types.Order{
   345  		types.MockOrder("", types.TestTokenPair, types.SellOrder, "10.0", "2.0"),
   346  	}
   347  	orders[0].Sender = addrKeysSlice[0].Address
   348  	err = k.PlaceOrder(ctx, orders[0])
   349  	require.NoError(t, err)
   350  	EndBlocker(ctx, k)
   351  	// call EndBlocker at 86400 + 9
   352  	ctx = mapp.BaseApp.NewContext(false, abci.Header{}).
   353  		WithBlockHeight(9 + feeParams.OrderExpireBlocks)
   354  	EndBlocker(ctx, k)
   355  
   356  	// call EndBlocker at 86400 + 10, lock product
   357  	ctx = mapp.BaseApp.NewContext(false, abci.Header{}).
   358  		WithBlockHeight(10 + feeParams.OrderExpireBlocks)
   359  	lock := &types.ProductLock{
   360  		Price:        sdk.MustNewDecFromStr("10.0"),
   361  		Quantity:     sdk.MustNewDecFromStr("1.0"),
   362  		BuyExecuted:  sdk.MustNewDecFromStr("1.0"),
   363  		SellExecuted: sdk.MustNewDecFromStr("1.0"),
   364  	}
   365  	k.SetProductLock(ctx, types.TestTokenPair, lock)
   366  	EndBlocker(ctx, k)
   367  
   368  	// check order
   369  	order := k.GetOrder(ctx, orders[0].OrderID)
   370  	require.EqualValues(t, types.OrderStatusOpen, order.Status)
   371  	require.EqualValues(t, 9+feeParams.OrderExpireBlocks, k.GetLastExpiredBlockHeight(ctx))
   372  
   373  	// call EndBlocker at 86400 + 11, unlock product
   374  	ctx = mapp.BaseApp.NewContext(false, abci.Header{}).
   375  		WithBlockHeight(11 + feeParams.OrderExpireBlocks)
   376  	k.UnlockProduct(ctx, types.TestTokenPair)
   377  	EndBlocker(ctx, k)
   378  
   379  	// check order
   380  	order = k.GetOrder(ctx, orders[0].OrderID)
   381  	require.EqualValues(t, types.OrderStatusExpired, order.Status)
   382  	require.EqualValues(t, 11+feeParams.OrderExpireBlocks, k.GetLastExpiredBlockHeight(ctx))
   383  }
   384  
   385  //func TestEndBlockerExpireOrders(t *testing.T) {
   386  //	mapp, addrKeysSlice := getMockApp(t, 3)
   387  //	k := mapp.orderKeeper
   388  //	mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}})
   389  //
   390  //	var startHeight int64 = 10
   391  //	ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(startHeight)
   392  //	mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply))
   393  //
   394  //	feeParams := types.DefaultTestParams()
   395  //
   396  //	tokenPair := dex.GetBuiltInTokenPair()
   397  //	err := mapp.dexKeeper.SaveTokenPair(ctx, tokenPair)
   398  //	require.Nil(t, err)
   399  //
   400  //	tokenPairDex := dex.GetBuiltInTokenPair()
   401  //	err = mapp.dexKeeper.SaveTokenPair(ctx, tokenPairDex)
   402  //	require.Nil(t, err)
   403  //	mapp.dexKeeper.SetOperator(ctx, dex.DEXOperator{
   404  //		Address:            tokenPair.Owner,
   405  //		HandlingFeeAddress: tokenPair.Owner,
   406  //	})
   407  //
   408  //	mapp.orderKeeper.SetParams(ctx, &feeParams)
   409  //	EndBlocker(ctx, k)
   410  //
   411  //	// mock orders
   412  //	orders := []*types.Order{
   413  //		types.MockOrder(types.FormatOrderID(startHeight, 1), types.TestTokenPair, types.BuyOrder, "9.8", "1.0"),
   414  //		types.MockOrder(types.FormatOrderID(startHeight, 2), types.TestTokenPair, types.SellOrder, "10.0", "1.0"),
   415  //		types.MockOrder(types.FormatOrderID(startHeight, 3), types.TestTokenPair, types.BuyOrder, "10.0", "0.5"),
   416  //	}
   417  //	orders[0].Sender = addrKeysSlice[0].Address
   418  //	orders[1].Sender = addrKeysSlice[1].Address
   419  //	orders[2].Sender = addrKeysSlice[2].Address
   420  //	for i := 0; i < 3; i++ {
   421  //		err := k.PlaceOrder(ctx, orders[i])
   422  //		require.NoError(t, err)
   423  //	}
   424  //	EndBlocker(ctx, k)
   425  //
   426  //	// check account balance
   427  //	acc0 := mapp.AccountKeeper.GetAccount(ctx, addrKeysSlice[0].Address)
   428  //	acc1 := mapp.AccountKeeper.GetAccount(ctx, addrKeysSlice[1].Address)
   429  //	expectCoins0 := sdk.SysCoins{
   430  //		// 100 - 9.8 - 0.2592 = 89.9408
   431  //		sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr("89.9408")),
   432  //		sdk.NewDecCoinFromDec(common.TestToken, sdk.MustNewDecFromStr("100")),
   433  //	}
   434  //	expectCoins1 := sdk.SysCoins{
   435  //		// 100 + 10 * 0.5 * (1 - 0.001) - 0.2592 = 104.7408
   436  //		sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr("104.7358")),
   437  //		sdk.NewDecCoinFromDec(common.TestToken, sdk.MustNewDecFromStr("99")),
   438  //	}
   439  //	require.EqualValues(t, expectCoins0.String(), acc0.GetCoins().String())
   440  //	require.EqualValues(t, expectCoins1.String(), acc1.GetCoins().String())
   441  //
   442  //	// check depth book
   443  //	depthBook := k.GetDepthBookCopy(types.TestTokenPair)
   444  //	require.EqualValues(t, 2, len(depthBook.Items))
   445  //
   446  //	// call EndBlocker to expire orders
   447  //	mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}})
   448  //	ctx = mapp.BaseApp.NewContext(false, abci.Header{}).
   449  //		WithBlockHeight(startHeight + feeParams.OrderExpireBlocks)
   450  //
   451  //	EndBlocker(ctx, k)
   452  //
   453  //	// check order status
   454  //	order0 := k.GetOrder(ctx, orders[0].OrderID)
   455  //	order1 := k.GetOrder(ctx, orders[1].OrderID)
   456  //	require.EqualValues(t, types.OrderStatusExpired, order0.Status)
   457  //	require.EqualValues(t, types.OrderStatusPartialFilledExpired, order1.Status)
   458  //
   459  //	// check depth book
   460  //	depthBook = k.GetDepthBookCopy(types.TestTokenPair)
   461  //	require.EqualValues(t, 0, len(depthBook.Items))
   462  //	// check order ids
   463  //	key := types.FormatOrderIDsKey(types.TestTokenPair, sdk.MustNewDecFromStr("9.8"), types.BuyOrder)
   464  //	orderIDs := k.GetProductPriceOrderIDs(key)
   465  //	require.EqualValues(t, 0, len(orderIDs))
   466  //	// check updated order ids
   467  //	updatedOrderIDs := k.GetUpdatedOrderIDs()
   468  //	require.EqualValues(t, 2, len(updatedOrderIDs))
   469  //	require.EqualValues(t, orders[0].OrderID, updatedOrderIDs[0])
   470  //	// check closed order id
   471  //	closedOrderIDs := k.GetDiskCache().GetClosedOrderIDs()
   472  //	require.Equal(t, 2, len(closedOrderIDs))
   473  //	require.Equal(t, orders[0].OrderID, closedOrderIDs[0])
   474  //
   475  //	// check account balance
   476  //	acc0 = mapp.AccountKeeper.GetAccount(ctx, addrKeysSlice[0].Address)
   477  //	acc1 = mapp.AccountKeeper.GetAccount(ctx, addrKeysSlice[1].Address)
   478  //	expectCoins0 = sdk.SysCoins{
   479  //		sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr("99.7408")), // 100 - 0.2592
   480  //		sdk.NewDecCoinFromDec(common.TestToken, sdk.MustNewDecFromStr("100")),
   481  //	}
   482  //	expectCoins1 = sdk.SysCoins{
   483  //		// 100 + 10 * 0.5 * (1 - 0.001) - 0.2592
   484  //		sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr("104.7358")),
   485  //		sdk.NewDecCoinFromDec(common.TestToken, sdk.MustNewDecFromStr("99.5")),
   486  //	}
   487  //	require.EqualValues(t, expectCoins0.String(), acc0.GetCoins().String())
   488  //	require.EqualValues(t, expectCoins1.String(), acc1.GetCoins().String())
   489  //
   490  //	// check fee pool
   491  //	feeCollector := mapp.supplyKeeper.GetModuleAccount(ctx, auth.FeeCollectorName)
   492  //	collectedFees := feeCollector.GetCoins()
   493  //	// 0.2592 + 0.2592
   494  //	require.EqualValues(t, "0.518400000000000000"+common.NativeToken, collectedFees.String())
   495  //}
   496  
   497  func TestEndBlockerCleanupOrdersWhoseTokenPairHaveBeenDelisted(t *testing.T) {
   498  	mapp, addrKeysSlice := getMockApp(t, 2)
   499  	k := mapp.orderKeeper
   500  	mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}})
   501  
   502  	var startHeight int64 = 10
   503  	ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(startHeight)
   504  	mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply))
   505  
   506  	feeParams := types.DefaultTestParams()
   507  	mapp.orderKeeper.SetParams(ctx, &feeParams)
   508  
   509  	// mock orders
   510  	orders := []*types.Order{
   511  		types.MockOrder(types.FormatOrderID(startHeight, 1), types.TestTokenPair, types.BuyOrder, "10.0", "1.0"),
   512  		types.MockOrder(types.FormatOrderID(startHeight, 2), types.TestTokenPair, types.SellOrder, "10.0", "0.5"),
   513  		types.MockOrder(types.FormatOrderID(startHeight, 3), types.TestTokenPair, types.SellOrder, "10.0", "2.5"),
   514  	}
   515  	orders[0].Sender = addrKeysSlice[0].Address
   516  	orders[1].Sender = addrKeysSlice[1].Address
   517  	orders[2].Sender = addrKeysSlice[1].Address
   518  	for i := 0; i < 3; i++ {
   519  		err := k.PlaceOrder(ctx, orders[i])
   520  		require.NoError(t, err)
   521  	}
   522  
   523  	// call EndBlocker to execute periodic match
   524  	EndBlocker(ctx, k)
   525  
   526  	// check depth book
   527  	depthBook := k.GetDepthBookCopy(types.TestTokenPair)
   528  	require.EqualValues(t, 0, len(depthBook.Items))
   529  
   530  	depthBookDB := k.GetDepthBookFromDB(ctx, types.TestTokenPair)
   531  	require.EqualValues(t, 0, len(depthBookDB.Items))
   532  
   533  	// check product price - order ids
   534  	key := types.FormatOrderIDsKey(types.TestTokenPair, sdk.MustNewDecFromStr("10.0"), types.SellOrder)
   535  	orderIDs := k.GetProductPriceOrderIDs(key)
   536  	require.EqualValues(t, 0, len(orderIDs))
   537  
   538  	key = types.FormatOrderIDsKey(types.TestTokenPair, sdk.MustNewDecFromStr("10.0"), types.BuyOrder)
   539  	orderIDs = k.GetProductPriceOrderIDs(key)
   540  	require.EqualValues(t, 0, len(orderIDs))
   541  
   542  	// check closed order id
   543  	closedOrderIDs := k.GetLastClosedOrderIDs(ctx)
   544  	require.Equal(t, 3, len(closedOrderIDs))
   545  	require.Equal(t, orders[0].OrderID, closedOrderIDs[0])
   546  	require.Equal(t, orders[1].OrderID, closedOrderIDs[1])
   547  	require.Equal(t, orders[2].OrderID, closedOrderIDs[2])
   548  
   549  	// check account balance
   550  	acc0 := mapp.AccountKeeper.GetAccount(ctx, addrKeysSlice[0].Address)
   551  	acc1 := mapp.AccountKeeper.GetAccount(ctx, addrKeysSlice[1].Address)
   552  	expectCoins0 := sdk.SysCoins{
   553  		sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr("100")),
   554  		sdk.NewDecCoinFromDec(common.TestToken, sdk.MustNewDecFromStr("100")),
   555  	}
   556  	expectCoins1 := sdk.SysCoins{
   557  		sdk.NewDecCoinFromDec(common.NativeToken, sdk.MustNewDecFromStr("100")),
   558  		sdk.NewDecCoinFromDec(common.TestToken, sdk.MustNewDecFromStr("100")),
   559  	}
   560  	require.EqualValues(t, expectCoins0.String(), acc0.GetCoins().String())
   561  	require.EqualValues(t, expectCoins1.String(), acc1.GetCoins().String())
   562  
   563  	// check fee pool
   564  	feeCollector := mapp.supplyKeeper.GetModuleAccount(ctx, auth.FeeCollectorName)
   565  	collectedFees := feeCollector.GetCoins()
   566  	require.EqualValues(t, "", collectedFees.String())
   567  }
   568  
   569  func TestFillPrecision(t *testing.T) {
   570  	mapp, addrKeysSlice := getMockApp(t, 2)
   571  	k := mapp.orderKeeper
   572  	mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}})
   573  
   574  	var startHeight int64 = 10
   575  	ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(startHeight)
   576  	BeginBlocker(ctx, k)
   577  
   578  	mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply))
   579  	feeParams := types.DefaultParams()
   580  	mapp.orderKeeper.SetParams(ctx, &feeParams)
   581  
   582  	tokenPair := dex.GetBuiltInTokenPair()
   583  	err := mapp.dexKeeper.SaveTokenPair(ctx, tokenPair)
   584  	require.Nil(t, err)
   585  
   586  	// mock orders
   587  	orderIdx := 0
   588  	roundN := 1 // Need more balance to make a large round
   589  	orderNums := 20
   590  	var orders []*types.Order
   591  
   592  	for j := 0; j < roundN; j++ {
   593  		rand.Seed(time.Now().Unix())
   594  		price := float64(25000+rand.Intn(5000)) / 10000
   595  
   596  		for i := 0; i < orderNums; i++ {
   597  			var buyPrice string
   598  			var sellPrice string
   599  			var quantity string
   600  
   601  			rand.Seed(time.Now().Unix() + int64(orderIdx))
   602  
   603  			// Test Same precision of price and quantity
   604  			quantity = strconv.FormatFloat(float64(rand.Intn(99999))/100000, 'f', 4, 64)
   605  			buyPrice = strconv.FormatFloat(price+0.0001, 'f', 4, 64)
   606  			sellPrice = strconv.FormatFloat(price, 'f', 4, 64)
   607  
   608  			tmp, err := strconv.ParseFloat(quantity, 64)
   609  			if tmp == 0.0 {
   610  				continue
   611  			}
   612  
   613  			orderIdx += 1
   614  			buyOrder := types.MockOrder(types.FormatOrderID(startHeight, int64(orderIdx)), types.TestTokenPair, types.BuyOrder, buyPrice, quantity)
   615  			orderIdx += 1
   616  			sellOrder := types.MockOrder(types.FormatOrderID(startHeight, int64(orderIdx)), types.TestTokenPair, types.SellOrder, sellPrice, quantity)
   617  
   618  			buyOrder.Sender = addrKeysSlice[0].Address
   619  			sellOrder.Sender = addrKeysSlice[1].Address
   620  
   621  			orders = append(orders, buyOrder, sellOrder)
   622  			err = k.PlaceOrder(ctx, buyOrder)
   623  			require.NoError(t, err)
   624  
   625  			orders = append(orders, sellOrder)
   626  			err = k.PlaceOrder(ctx, sellOrder)
   627  		}
   628  	}
   629  	// call EndBlocker to execute periodic match
   630  	EndBlocker(ctx, k)
   631  
   632  	N := len(orders) / 1000
   633  	for i := 0; i < N; i++ {
   634  		ctx = mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(startHeight + int64(1+i))
   635  		BeginBlocker(ctx, k)
   636  		EndBlocker(ctx, k)
   637  	}
   638  
   639  	invaFunc := keeper.ModuleAccountInvariant(mapp.orderKeeper)
   640  	_, isInval := invaFunc(ctx)
   641  	require.EqualValues(t, false, isInval)
   642  }
   643  
   644  func buildRandomOrderMsg(addr sdk.AccAddress) MsgNewOrders {
   645  	price := strconv.Itoa(rand.Intn(10) + 100)
   646  	orderItems := []types.OrderItem{
   647  		types.NewOrderItem(types.TestTokenPair, types.BuyOrder, price, "1.0"),
   648  	}
   649  	msg := types.NewMsgNewOrders(addr, orderItems)
   650  	return msg
   651  
   652  }
   653  
   654  //func TestEndBlocker(t *testing.T) {
   655  //	mapp, addrKeysSlice := getMockAppWithBalance(t, 2, 100000000)
   656  //	k := mapp.orderKeeper
   657  //	mapp.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: 2}})
   658  //
   659  //	var startHeight int64 = 10
   660  //	ctx := mapp.BaseApp.NewContext(false, abci.Header{}).WithBlockHeight(startHeight)
   661  //	mapp.supplyKeeper.SetSupply(ctx, supply.NewSupply(mapp.TotalCoinsSupply))
   662  //
   663  //	feeParams := types.DefaultTestParams()
   664  //	mapp.orderKeeper.SetParams(ctx, &feeParams)
   665  //
   666  //	tokenPair := dex.GetBuiltInTokenPair()
   667  //	err := mapp.dexKeeper.SaveTokenPair(ctx, tokenPair)
   668  //	require.Nil(t, err)
   669  //
   670  //	handler := NewOrderHandler(k)
   671  //
   672  //	blockHeight := startHeight
   673  //	for i := 0; i < 100000; i++ {
   674  //		msg := buildRandomOrderMsg(addrKeysSlice[0].Address)
   675  //		result, err := handler(ctx, msg)
   676  //		if (i+1)%1000 == 0 {
   677  //			blockHeight = blockHeight + 1
   678  //			ctx.SetBlockHeight(blockHeight)
   679  //		}
   680  //		require.Nil(t, err)
   681  //		require.EqualValues(t, "", result.Log)
   682  //	}
   683  //	// call EndBlocker to execute periodic match
   684  //	EndBlocker(ctx, k)
   685  //
   686  //	quantityList := [3]string{"200", "500", "1000"}
   687  //	for _, quantity := range quantityList {
   688  //		startTime := time.Now()
   689  //		blockHeight = blockHeight + 1
   690  //		ctx.SetBlockHeight(blockHeight)
   691  //		orderItems := []types.OrderItem{
   692  //			types.NewOrderItem(types.TestTokenPair, types.SellOrder, "100", quantity),
   693  //		}
   694  //		msg := types.NewMsgNewOrders(addrKeysSlice[1].Address, orderItems)
   695  //		handler(ctx, msg)
   696  //		EndBlocker(ctx, k)
   697  //		fmt.Println(time.Since(startTime))
   698  //		fmt.Println(k.GetOrder(ctx, types.FormatOrderID(blockHeight, 1)))
   699  //	}
   700  //}