code.vegaprotocol.io/vega@v0.79.0/datanode/sqlstore/trades_test.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package sqlstore_test
    17  
    18  import (
    19  	"context"
    20  	"encoding/hex"
    21  	"testing"
    22  	"time"
    23  
    24  	"code.vegaprotocol.io/vega/datanode/entities"
    25  	"code.vegaprotocol.io/vega/datanode/sqlstore"
    26  	"code.vegaprotocol.io/vega/libs/num"
    27  	types "code.vegaprotocol.io/vega/protos/vega"
    28  
    29  	"github.com/shopspring/decimal"
    30  	"github.com/stretchr/testify/assert"
    31  	"github.com/stretchr/testify/require"
    32  )
    33  
    34  const (
    35  	testMarket = "b4376d805a888548baabfae74ef6f4fa4680dc9718bab355fa7191715de4fafe"
    36  	testPartyA = "8cc0e020c0bc2f9eba77749d81ecec8283283b85941722c2cb88318aaf8b8cd8"
    37  	testPartyB = "521127F24B1FA40311BA2FB3F6977310346346604B275DB7B767B04240A5A5C3"
    38  	orderAId   = "787B72CB5DD7A5EA869E49F361CF957DF747F849B4ACE88ABC6DA0F9C450AFDD"
    39  	orderBId   = "83dc82be23c77daec384a239143f07f83c667acf60d734745b023c6567e7b57b"
    40  
    41  	tradeID1 = "0bd678723c33b059638953e0904d2ddbd78c2be72ab25a8753a622911c2d9c78"
    42  	tradeID2 = "af2bb48edd738353fcd7a2b6cea4821dd2382ec95497954535278dfbfff7b5b5"
    43  	tradeID3 = "3d4ed10064b7cedbc8a37316f7329f853c9588b6a55006ffb8bec3f1a4ccc88e"
    44  	tradeID4 = "8cc0e020c0bc2f9eba77749d81ecec8283283b85941722c2cb88318aaf8b8cd8"
    45  	tradeID5 = "8b6be1a03cc4d529f682887a78b66e6879d17f81e2b37356ca0acbc5d5886eb8"
    46  	tradeID6 = "8cc0e020c0bc2f9eba77749d81ecec8283283b85941722c2cb88318aaf8b8cd8"
    47  )
    48  
    49  func TestStorageGetByTxHash(t *testing.T) {
    50  	ctx := tempTransaction(t)
    51  
    52  	tradeStore := sqlstore.NewTrades(connectionSource)
    53  
    54  	insertedTrades := insertTestData(t, ctx, tradeStore)
    55  
    56  	trades, err := tradeStore.GetByTxHash(ctx, insertedTrades[0].TxHash)
    57  	assert.Nil(t, err)
    58  	assert.Equal(t, 1, len(trades))
    59  	assert.Equal(t, insertedTrades[0].ID.String(), trades[0].ID.String())
    60  	assert.Equal(t, insertedTrades[0].TxHash, trades[0].TxHash)
    61  
    62  	trades, err = tradeStore.GetByTxHash(ctx, insertedTrades[2].TxHash)
    63  	assert.Nil(t, err)
    64  	assert.Equal(t, 1, len(trades))
    65  	assert.Equal(t, insertedTrades[2].ID.String(), trades[0].ID.String())
    66  	assert.Equal(t, insertedTrades[2].TxHash, trades[0].TxHash)
    67  }
    68  
    69  func insertTestData(t *testing.T, ctx context.Context, tradeStore *sqlstore.Trades) []entities.Trade {
    70  	t.Helper()
    71  
    72  	// Insert some trades
    73  	bs := sqlstore.NewBlocks(connectionSource)
    74  	now := time.Now()
    75  	block1 := addTestBlockForTime(t, ctx, bs, now)
    76  	block2 := addTestBlockForTime(t, ctx, bs, now.Add(time.Second))
    77  
    78  	trade1 := &types.Trade{
    79  		Type:      types.Trade_TYPE_DEFAULT,
    80  		Id:        tradeID1,
    81  		Price:     "100",
    82  		Size:      100,
    83  		MarketId:  testMarket,
    84  		Buyer:     testPartyB,
    85  		Seller:    testPartyA,
    86  		Aggressor: types.Side_SIDE_SELL,
    87  		Timestamp: 1,
    88  		BuyOrder:  orderBId,
    89  		SellOrder: orderAId,
    90  	}
    91  
    92  	trade2 := &types.Trade{
    93  		Type:      types.Trade_TYPE_DEFAULT,
    94  		Id:        tradeID2,
    95  		Price:     "100",
    96  		Size:      100,
    97  		MarketId:  testMarket,
    98  		Buyer:     testPartyB,
    99  		Seller:    testPartyA,
   100  		Aggressor: types.Side_SIDE_SELL,
   101  		Timestamp: 1,
   102  		BuyOrder:  orderBId,
   103  		SellOrder: orderAId,
   104  	}
   105  
   106  	trade3 := &types.Trade{
   107  		Type:      types.Trade_TYPE_DEFAULT,
   108  		Id:        tradeID3,
   109  		Price:     "100",
   110  		Size:      100,
   111  		MarketId:  testMarket,
   112  		Buyer:     testPartyB,
   113  		Seller:    testPartyA,
   114  		Aggressor: types.Side_SIDE_SELL,
   115  		Timestamp: 1,
   116  		BuyOrder:  orderBId,
   117  		SellOrder: orderAId,
   118  	}
   119  
   120  	trade4 := &types.Trade{
   121  		Type:      types.Trade_TYPE_DEFAULT,
   122  		Id:        tradeID4,
   123  		Price:     "100",
   124  		Size:      100,
   125  		MarketId:  testMarket,
   126  		Buyer:     testPartyB,
   127  		Seller:    testPartyA,
   128  		Aggressor: types.Side_SIDE_SELL,
   129  		Timestamp: 1,
   130  		BuyOrder:  orderBId,
   131  		SellOrder: orderAId,
   132  	}
   133  
   134  	trade5 := &types.Trade{
   135  		Type:      types.Trade_TYPE_DEFAULT,
   136  		Id:        tradeID5,
   137  		Price:     "100",
   138  		Size:      100,
   139  		MarketId:  testMarket,
   140  		Buyer:     testPartyB,
   141  		Seller:    testPartyA,
   142  		Aggressor: types.Side_SIDE_SELL,
   143  		Timestamp: 1,
   144  		BuyOrder:  orderBId,
   145  		SellOrder: orderAId,
   146  	}
   147  
   148  	trade6 := &types.Trade{
   149  		Type:      types.Trade_TYPE_DEFAULT,
   150  		Id:        tradeID6,
   151  		Price:     "100",
   152  		Size:      100,
   153  		MarketId:  testMarket,
   154  		Buyer:     testPartyB,
   155  		Seller:    testPartyA,
   156  		Aggressor: types.Side_SIDE_SELL,
   157  		Timestamp: 1,
   158  		BuyOrder:  orderBId,
   159  		SellOrder: orderAId,
   160  	}
   161  
   162  	protos := []types.Trade{*trade1, *trade2, *trade3, *trade4, *trade5, *trade6}
   163  
   164  	inserted := []entities.Trade{}
   165  	var seqNum uint64
   166  	vegaTime := block1.VegaTime
   167  	for _, proto := range protos {
   168  		if seqNum == 3 {
   169  			seqNum = 0
   170  			vegaTime = block2.VegaTime
   171  		}
   172  		trade, err := entities.TradeFromProto(&proto, generateTxHash(), vegaTime, seqNum)
   173  		if err != nil {
   174  			t.Fatalf("failed to get trade from proto:%s", err)
   175  		}
   176  		err = tradeStore.Add(trade)
   177  		if err != nil {
   178  			t.Fatalf("failed to add trade:%s", err)
   179  		}
   180  		seqNum++
   181  
   182  		inserted = append(inserted, *trade)
   183  	}
   184  
   185  	tradeStore.Flush(ctx)
   186  	return inserted
   187  }
   188  
   189  func TestTrades_CursorPagination(t *testing.T) {
   190  	t.Run("Should return all trades for a given market when no cursor is given", testTradesCursorPaginationByMarketNoCursor)
   191  	t.Run("Should return all trades for a given party when no market and no cursor is given", testTradesCursorPaginationByPartyNoMarketNoCursor)
   192  	t.Run("Should return all trades for a given party and market when market ID and no cursor is given", testTradesCursorPaginationByPartyAndMarketNoCursor)
   193  	t.Run("Should return the first page of trades for a given market when a first cursor is set", testTradesCursorPaginationByMarketWithCursorFirst)
   194  	t.Run("Should return the first page of trades for a given party when a first cursor is set but not market", testTradesCursorPaginationByPartyWithCursorNoMarketFirst)
   195  	t.Run("Should return the first page of trades for a given party and market when a first cursor is set", testTradesCursorPaginationByPartyAndMarketWithCursorFirst)
   196  	t.Run("Should return the last page of trades for a given market when a last cursor is set", testTradesCursorPaginationByMarketWithCursorLast)
   197  	t.Run("Should return the last page of trades for a given party when a last cursor is set but not market", testTradesCursorPaginationByPartyWithCursorNoMarketLast)
   198  	t.Run("Should return the last page of trades for a given party and market when a last cursor is set", testTradesCursorPaginationByPartyAndMarketWithCursorLast)
   199  	t.Run("Should return the page of trades for a given market when a first and after cursor is set", testTradesCursorPaginationByMarketWithCursorForward)
   200  	t.Run("Should return the page of trades for a given party when a first and after cursor is set but not market", testTradesCursorPaginationByPartyWithCursorNoMarketForward)
   201  	t.Run("Should return the page of trades for a given party and market when a first and after cursor is set", testTradesCursorPaginationByPartyAndMarketWithCursorForward)
   202  	t.Run("Should return the page of trades for a given market when a last and before cursor is set", testTradesCursorPaginationByMarketWithCursorBackward)
   203  	t.Run("Should return the page of trades for a given party when a last and before cursor is set but not market", testTradesCursorPaginationByPartyWithCursorNoMarketBackward)
   204  	t.Run("Should return the page of trades for a given party and market when a last and before cursor is set", testTradesCursorPaginationByPartyAndMarketWithCursorBackward)
   205  
   206  	t.Run("Should return all trades for a given market when no cursor is given - newest first", testTradesCursorPaginationByMarketNoCursorNewestFirst)
   207  	t.Run("Should return all trades for a given party when no market and no cursor is given - newest first", testTradesCursorPaginationByPartyNoMarketNoCursorNewestFirst)
   208  	t.Run("Should return all trades for a given party and market when market ID and no cursor is given - newest first", testTradesCursorPaginationByPartyAndMarketNoCursorNewestFirst)
   209  	t.Run("Should return the first page of trades for a given market when a first cursor is set - newest first", testTradesCursorPaginationByMarketWithCursorFirstNewestFirst)
   210  	t.Run("Should return the first page of trades for a given party when a first cursor is set but not market - newest first", testTradesCursorPaginationByPartyWithCursorNoMarketFirstNewestFirst)
   211  	t.Run("Should return the first page of trades for a given party and market when a first cursor is set - newest first", testTradesCursorPaginationByPartyAndMarketWithCursorFirstNewestFirst)
   212  	t.Run("Should return the last page of trades for a given market when a last cursor is set - newest first", testTradesCursorPaginationByMarketWithCursorLastNewestFirst)
   213  	t.Run("Should return the last page of trades for a given party when a last cursor is set but not market - newest first", testTradesCursorPaginationByPartyWithCursorNoMarketLastNewestFirst)
   214  	t.Run("Should return the last page of trades for a given party and market when a last cursor is set - newest first", testTradesCursorPaginationByPartyAndMarketWithCursorLastNewestFirst)
   215  	t.Run("Should return the page of trades for a given market when a first and after cursor is set - newest first", testTradesCursorPaginationByMarketWithCursorForwardNewestFirst)
   216  	t.Run("Should return the page of trades for a given party when a first and after cursor is set but not market - newest first", testTradesCursorPaginationByPartyWithCursorNoMarketForwardNewestFirst)
   217  	t.Run("Should return the page of trades for a given party and market when a first and after cursor is set - newest first", testTradesCursorPaginationByPartyAndMarketWithCursorForwardNewestFirst)
   218  	t.Run("Should return the page of trades for a given market when a last and before cursor is set - newest first", testTradesCursorPaginationByMarketWithCursorBackwardNewestFirst)
   219  	t.Run("Should return the page of trades for a given party when a last and before cursor is set but not market - newest first", testTradesCursorPaginationByPartyWithCursorNoMarketBackwardNewestFirst)
   220  	t.Run("Should return the page of trades for a given party and market when a last and before cursor is set - newest first", testTradesCursorPaginationByPartyAndMarketWithCursorBackwardNewestFirst)
   221  
   222  	t.Run("Should return all trades between dates for a given market when no cursor is given", testTradesCursorPaginationBetweenDatesByMarketNoCursor)
   223  	t.Run("Should return all trades between dates for a given market when no cursor is given - newest first", testTradesCursorPaginationBetweenDatesByMarketNoCursorNewestFirst)
   224  	t.Run("Should return the last page of trades between dates for a given market when a last cursor is set", testTradesCursorPaginationBetweenDatesByMarketWithCursorLast)
   225  	t.Run("Should return the page of trades between dates for a given market when a first and after cursor is set", testTradesCursorPaginationBetweenDatesByMarketWithCursorForward)
   226  }
   227  
   228  func TestTransferFeeDiscount(t *testing.T) {
   229  	t.Run("get current transfer fee discount", tesGetCurrentTransferFeeDiscount)
   230  }
   231  
   232  func setupTradesTest(t *testing.T) (*sqlstore.Blocks, *sqlstore.Trades) {
   233  	t.Helper()
   234  	bs := sqlstore.NewBlocks(connectionSource)
   235  	ts := sqlstore.NewTrades(connectionSource)
   236  	return bs, ts
   237  }
   238  
   239  func populateTestTrades(ctx context.Context, t *testing.T, bs *sqlstore.Blocks, ts *sqlstore.Trades, blockTimes map[string]time.Time) {
   240  	t.Helper()
   241  
   242  	trades := []entities.Trade{
   243  		{
   244  			SeqNum:    1,
   245  			ID:        entities.TradeID("02a16077"),
   246  			MarketID:  entities.MarketID("deadbeef"),
   247  			Price:     decimal.NewFromFloat(1.0),
   248  			Size:      1,
   249  			Buyer:     entities.PartyID("dabbad00"),
   250  			Seller:    entities.PartyID("facefeed"),
   251  			BuyOrder:  entities.OrderID("02a16077"),
   252  			SellOrder: entities.OrderID("fb1528a5"),
   253  			Type:      entities.TradeTypeDefault,
   254  		},
   255  		{
   256  			SeqNum:    2,
   257  			ID:        entities.TradeID("44eea1bc"),
   258  			MarketID:  entities.MarketID("deadbeef"),
   259  			Price:     decimal.NewFromFloat(2.0),
   260  			Size:      2,
   261  			Buyer:     entities.PartyID("dabbad00"),
   262  			Seller:    entities.PartyID("facefeed"),
   263  			BuyOrder:  entities.OrderID("44eea1bc"),
   264  			SellOrder: entities.OrderID("da8d1803"),
   265  			Type:      entities.TradeTypeDefault,
   266  		},
   267  		{
   268  			SeqNum:    3,
   269  			ID:        entities.TradeID("65be62cd"),
   270  			MarketID:  entities.MarketID("deadbeef"),
   271  			Price:     decimal.NewFromFloat(3.0),
   272  			Size:      3,
   273  			Buyer:     entities.PartyID("dabbad00"),
   274  			Seller:    entities.PartyID("facefeed"),
   275  			BuyOrder:  entities.OrderID("65be62cd"),
   276  			SellOrder: entities.OrderID("c8744329"),
   277  			Type:      entities.TradeTypeDefault,
   278  		},
   279  		{
   280  			SeqNum:    4,
   281  			ID:        entities.TradeID("7a797e0e"),
   282  			MarketID:  entities.MarketID("deadbeef"),
   283  			Price:     decimal.NewFromFloat(4.0),
   284  			Size:      4,
   285  			Buyer:     entities.PartyID("dabbad00"),
   286  			Seller:    entities.PartyID("facefeed"),
   287  			BuyOrder:  entities.OrderID("7a797e0e"),
   288  			SellOrder: entities.OrderID("c612300d"),
   289  			Type:      entities.TradeTypeDefault,
   290  		},
   291  		{
   292  			SeqNum:    5,
   293  			ID:        entities.TradeID("7bb2356e"),
   294  			MarketID:  entities.MarketID("cafed00d"),
   295  			Price:     decimal.NewFromFloat(5.0),
   296  			Size:      5,
   297  			Buyer:     entities.PartyID("dabbad00"),
   298  			Seller:    entities.PartyID("facefeed"),
   299  			BuyOrder:  entities.OrderID("7bb2356e"),
   300  			SellOrder: entities.OrderID("b7c84b8e"),
   301  			Type:      entities.TradeTypeDefault,
   302  		},
   303  		{
   304  			SeqNum:    6,
   305  			ID:        entities.TradeID("b7c84b8e"),
   306  			MarketID:  entities.MarketID("cafed00d"),
   307  			Price:     decimal.NewFromFloat(6.0),
   308  			Size:      6,
   309  			Buyer:     entities.PartyID("d0d0caca"),
   310  			Seller:    entities.PartyID("decafbad"),
   311  			BuyOrder:  entities.OrderID("b7c84b8e"),
   312  			SellOrder: entities.OrderID("7bb2356e"),
   313  			Type:      entities.TradeTypeDefault,
   314  		},
   315  		{
   316  			SeqNum:    7,
   317  			ID:        entities.TradeID("c612300d"),
   318  			MarketID:  entities.MarketID("cafed00d"),
   319  			Price:     decimal.NewFromFloat(7.0),
   320  			Size:      7,
   321  			Buyer:     entities.PartyID("d0d0caca"),
   322  			Seller:    entities.PartyID("decafbad"),
   323  			BuyOrder:  entities.OrderID("c612300d"),
   324  			SellOrder: entities.OrderID("7a797e0e"),
   325  			Type:      entities.TradeTypeDefault,
   326  		},
   327  		{
   328  			SeqNum:    8,
   329  			ID:        entities.TradeID("c8744329"),
   330  			MarketID:  entities.MarketID("cafed00d"),
   331  			Price:     decimal.NewFromFloat(8.0),
   332  			Size:      8,
   333  			Buyer:     entities.PartyID("d0d0caca"),
   334  			Seller:    entities.PartyID("decafbad"),
   335  			BuyOrder:  entities.OrderID("c8744329"),
   336  			SellOrder: entities.OrderID("65be62cd"),
   337  			Type:      entities.TradeTypeDefault,
   338  		},
   339  		{
   340  			SeqNum:    9,
   341  			ID:        entities.TradeID("da8d1803"),
   342  			MarketID:  entities.MarketID("deadbaad"),
   343  			Price:     decimal.NewFromFloat(9.0),
   344  			Size:      9,
   345  			Buyer:     entities.PartyID("baadf00d"),
   346  			Seller:    entities.PartyID("0d15ea5e"),
   347  			BuyOrder:  entities.OrderID("da8d1803"),
   348  			SellOrder: entities.OrderID("44eea1bc"),
   349  			Type:      entities.TradeTypeDefault,
   350  		},
   351  		{
   352  			SeqNum:    10,
   353  			ID:        entities.TradeID("fb1528a5"),
   354  			MarketID:  entities.MarketID("deadbaad"),
   355  			Price:     decimal.NewFromFloat(10.0),
   356  			Size:      10,
   357  			Buyer:     entities.PartyID("baadf00d"),
   358  			Seller:    entities.PartyID("0d15ea5e"),
   359  			BuyOrder:  entities.OrderID("fb1528a5"),
   360  			SellOrder: entities.OrderID("02a16077"),
   361  			Type:      entities.TradeTypeDefault,
   362  		},
   363  	}
   364  	source := &testBlockSource{bs, time.Now()}
   365  	for _, td := range trades {
   366  		trade := td
   367  		block := source.getNextBlock(t, ctx)
   368  		trade.SyntheticTime = block.VegaTime
   369  		trade.VegaTime = block.VegaTime
   370  		blockTimes[trade.ID.String()] = block.VegaTime
   371  		err := ts.Add(&trade)
   372  		require.NoError(t, err)
   373  	}
   374  
   375  	_, err := ts.Flush(ctx)
   376  	require.NoError(t, err)
   377  }
   378  
   379  func testTradesCursorPaginationByMarketNoCursor(t *testing.T) {
   380  	ctx := tempTransaction(t)
   381  
   382  	bs, ts := setupTradesTest(t)
   383  	blockTimes := make(map[string]time.Time)
   384  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   385  	pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, false)
   386  	require.NoError(t, err)
   387  
   388  	marketID := []entities.MarketID{"deadbeef"}
   389  	got, pageInfo, err := ts.List(ctx, marketID, nil, nil, pagination, entities.DateRange{})
   390  	require.NoError(t, err)
   391  
   392  	assert.Len(t, got, 4)
   393  	assert.Equal(t, "02a16077", got[0].ID.String())
   394  	assert.Equal(t, uint64(1), got[0].Size)
   395  	assert.Equal(t, "7a797e0e", got[3].ID.String())
   396  	assert.Equal(t, uint64(4), got[3].Size)
   397  	assert.False(t, pageInfo.HasNextPage)
   398  	assert.False(t, pageInfo.HasPreviousPage)
   399  	assert.Equal(t, "02a16077", got[0].ID.String())
   400  	assert.Equal(t, "7a797e0e", got[3].ID.String())
   401  }
   402  
   403  func testTradesCursorPaginationByPartyNoMarketNoCursor(t *testing.T) {
   404  	ctx := tempTransaction(t)
   405  
   406  	bs, ts := setupTradesTest(t)
   407  	blockTimes := make(map[string]time.Time)
   408  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   409  	pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, false)
   410  	require.NoError(t, err)
   411  
   412  	partyID := []entities.PartyID{"dabbad00"}
   413  	got, pageInfo, err := ts.List(ctx, nil, partyID, nil, pagination, entities.DateRange{})
   414  	require.NoError(t, err)
   415  	assert.Len(t, got, 5)
   416  
   417  	assert.Equal(t, "02a16077", got[0].ID.String())
   418  	assert.Equal(t, uint64(1), got[0].Size)
   419  	assert.Equal(t, "7bb2356e", got[4].ID.String())
   420  	assert.Equal(t, uint64(5), got[4].Size)
   421  
   422  	assert.False(t, pageInfo.HasNextPage)
   423  	assert.False(t, pageInfo.HasPreviousPage)
   424  	assert.Equal(t, "02a16077", got[0].ID.String())
   425  	assert.Equal(t, "7bb2356e", got[4].ID.String())
   426  }
   427  
   428  func testTradesCursorPaginationByPartyAndMarketNoCursor(t *testing.T) {
   429  	ctx := tempTransaction(t)
   430  
   431  	bs, ts := setupTradesTest(t)
   432  	blockTimes := make(map[string]time.Time)
   433  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   434  	pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, false)
   435  	require.NoError(t, err)
   436  	partyID := []entities.PartyID{"dabbad00"}
   437  	marketID := []entities.MarketID{"deadbeef"}
   438  	got, pageInfo, err := ts.List(ctx, marketID, partyID, nil, pagination, entities.DateRange{})
   439  	require.NoError(t, err)
   440  	assert.Len(t, got, 4)
   441  	assert.Equal(t, "02a16077", got[0].ID.String())
   442  	assert.Equal(t, uint64(1), got[0].Size)
   443  	assert.Equal(t, "7a797e0e", got[3].ID.String())
   444  	assert.Equal(t, uint64(4), got[3].Size)
   445  	assert.False(t, pageInfo.HasNextPage)
   446  	assert.False(t, pageInfo.HasPreviousPage)
   447  	assert.Equal(t, "02a16077", got[0].ID.String())
   448  	assert.Equal(t, "7a797e0e", got[3].ID.String())
   449  }
   450  
   451  func testTradesCursorPaginationByMarketWithCursorFirst(t *testing.T) {
   452  	ctx := tempTransaction(t)
   453  
   454  	bs, ts := setupTradesTest(t)
   455  	blockTimes := make(map[string]time.Time)
   456  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   457  	first := int32(2)
   458  	pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, false)
   459  	require.NoError(t, err)
   460  	marketID := []entities.MarketID{"deadbeef"}
   461  	got, pageInfo, err := ts.List(ctx, marketID, nil, nil, pagination, entities.DateRange{})
   462  	require.NoError(t, err)
   463  
   464  	assert.Len(t, got, 2)
   465  	assert.Equal(t, "02a16077", got[0].ID.String())
   466  	assert.Equal(t, uint64(1), got[0].Size)
   467  	assert.Equal(t, "44eea1bc", got[1].ID.String())
   468  	assert.Equal(t, uint64(2), got[1].Size)
   469  	assert.True(t, pageInfo.HasNextPage)
   470  	assert.False(t, pageInfo.HasPreviousPage)
   471  	assert.Equal(t, "02a16077", got[0].ID.String())
   472  	assert.Equal(t, "44eea1bc", got[1].ID.String())
   473  }
   474  
   475  func testTradesCursorPaginationByPartyWithCursorNoMarketFirst(t *testing.T) {
   476  	ctx := tempTransaction(t)
   477  
   478  	bs, ts := setupTradesTest(t)
   479  	blockTimes := make(map[string]time.Time)
   480  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   481  	first := int32(2)
   482  	pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, false)
   483  	require.NoError(t, err)
   484  	partyID := []entities.PartyID{"dabbad00"}
   485  	got, pageInfo, err := ts.List(ctx, nil, partyID, nil, pagination, entities.DateRange{})
   486  	require.NoError(t, err)
   487  	assert.Len(t, got, 2)
   488  	assert.Equal(t, "02a16077", got[0].ID.String())
   489  	assert.Equal(t, uint64(1), got[0].Size)
   490  	assert.Equal(t, "44eea1bc", got[1].ID.String())
   491  	assert.Equal(t, uint64(2), got[1].Size)
   492  	assert.True(t, pageInfo.HasNextPage)
   493  	assert.False(t, pageInfo.HasPreviousPage)
   494  	assert.Equal(t, "02a16077", got[0].ID.String())
   495  	assert.Equal(t, "44eea1bc", got[1].ID.String())
   496  }
   497  
   498  func testTradesCursorPaginationByPartyAndMarketWithCursorFirst(t *testing.T) {
   499  	ctx := tempTransaction(t)
   500  
   501  	bs, ts := setupTradesTest(t)
   502  	blockTimes := make(map[string]time.Time)
   503  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   504  	first := int32(2)
   505  	pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, false)
   506  	require.NoError(t, err)
   507  	partyID := []entities.PartyID{"dabbad00"}
   508  	marketID := []entities.MarketID{"deadbeef"}
   509  	got, pageInfo, err := ts.List(ctx, marketID, partyID, nil, pagination, entities.DateRange{})
   510  	require.NoError(t, err)
   511  	assert.Len(t, got, 2)
   512  	assert.Equal(t, "02a16077", got[0].ID.String())
   513  	assert.Equal(t, uint64(1), got[0].Size)
   514  	assert.Equal(t, "44eea1bc", got[1].ID.String())
   515  	assert.Equal(t, uint64(2), got[1].Size)
   516  	assert.True(t, pageInfo.HasNextPage)
   517  	assert.False(t, pageInfo.HasPreviousPage)
   518  	assert.Equal(t, "02a16077", got[0].ID.String())
   519  	assert.Equal(t, "44eea1bc", got[1].ID.String())
   520  }
   521  
   522  func testTradesCursorPaginationByMarketWithCursorLast(t *testing.T) {
   523  	ctx := tempTransaction(t)
   524  
   525  	bs, ts := setupTradesTest(t)
   526  	blockTimes := make(map[string]time.Time)
   527  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   528  	last := int32(2)
   529  	pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, false)
   530  	require.NoError(t, err)
   531  	marketID := []entities.MarketID{"deadbeef"}
   532  	got, pageInfo, err := ts.List(ctx, marketID, nil, nil, pagination, entities.DateRange{})
   533  	require.NoError(t, err)
   534  
   535  	assert.Len(t, got, 2)
   536  	assert.Equal(t, "65be62cd", got[0].ID.String())
   537  	assert.Equal(t, uint64(3), got[0].Size)
   538  	assert.Equal(t, "7a797e0e", got[1].ID.String())
   539  	assert.Equal(t, uint64(4), got[1].Size)
   540  	assert.False(t, pageInfo.HasNextPage)
   541  	assert.True(t, pageInfo.HasPreviousPage)
   542  	assert.Equal(t, "65be62cd", got[0].ID.String())
   543  	assert.Equal(t, "7a797e0e", got[1].ID.String())
   544  }
   545  
   546  func testTradesCursorPaginationByPartyWithCursorNoMarketLast(t *testing.T) {
   547  	ctx := tempTransaction(t)
   548  
   549  	bs, ts := setupTradesTest(t)
   550  	blockTimes := make(map[string]time.Time)
   551  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   552  	last := int32(2)
   553  	pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, false)
   554  	require.NoError(t, err)
   555  	partyID := []entities.PartyID{"dabbad00"}
   556  	got, pageInfo, err := ts.List(ctx, nil, partyID, nil, pagination, entities.DateRange{})
   557  	require.NoError(t, err)
   558  	assert.Len(t, got, 2)
   559  	assert.Equal(t, "7a797e0e", got[0].ID.String())
   560  	assert.Equal(t, uint64(4), got[0].Size)
   561  	assert.Equal(t, "7bb2356e", got[1].ID.String())
   562  	assert.Equal(t, uint64(5), got[1].Size)
   563  	assert.False(t, pageInfo.HasNextPage)
   564  	assert.True(t, pageInfo.HasPreviousPage)
   565  	assert.Equal(t, "7a797e0e", got[0].ID.String())
   566  	assert.Equal(t, "7bb2356e", got[1].ID.String())
   567  }
   568  
   569  func testTradesCursorPaginationByPartyAndMarketWithCursorLast(t *testing.T) {
   570  	ctx := tempTransaction(t)
   571  
   572  	bs, ts := setupTradesTest(t)
   573  	blockTimes := make(map[string]time.Time)
   574  	last := int32(2)
   575  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   576  	pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, false)
   577  	require.NoError(t, err)
   578  	partyID := []entities.PartyID{"dabbad00"}
   579  	marketID := []entities.MarketID{"deadbeef"}
   580  	got, pageInfo, err := ts.List(ctx, marketID, partyID, nil, pagination, entities.DateRange{})
   581  	require.NoError(t, err)
   582  	assert.Len(t, got, 2)
   583  	assert.Equal(t, "65be62cd", got[0].ID.String())
   584  	assert.Equal(t, uint64(3), got[0].Size)
   585  	assert.Equal(t, "7a797e0e", got[1].ID.String())
   586  	assert.Equal(t, uint64(4), got[1].Size)
   587  	assert.False(t, pageInfo.HasNextPage)
   588  	assert.True(t, pageInfo.HasPreviousPage)
   589  	assert.Equal(t, "65be62cd", got[0].ID.String())
   590  	assert.Equal(t, "7a797e0e", got[1].ID.String())
   591  }
   592  
   593  func testTradesCursorPaginationByMarketWithCursorForward(t *testing.T) {
   594  	ctx := tempTransaction(t)
   595  
   596  	bs, ts := setupTradesTest(t)
   597  	blockTimes := make(map[string]time.Time)
   598  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   599  	first := int32(2)
   600  	after := entities.NewCursor(entities.TradeCursor{SyntheticTime: blockTimes["02a16077"]}.String()).Encode()
   601  	pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, false)
   602  	require.NoError(t, err)
   603  	marketID := []entities.MarketID{"deadbeef"}
   604  	got, pageInfo, err := ts.List(ctx, marketID, nil, nil, pagination, entities.DateRange{})
   605  	require.NoError(t, err)
   606  
   607  	assert.Len(t, got, 2)
   608  	assert.Equal(t, "44eea1bc", got[0].ID.String())
   609  	assert.Equal(t, uint64(2), got[0].Size)
   610  	assert.Equal(t, "65be62cd", got[1].ID.String())
   611  	assert.Equal(t, uint64(3), got[1].Size)
   612  	assert.True(t, pageInfo.HasNextPage)
   613  	assert.True(t, pageInfo.HasPreviousPage)
   614  	assert.Equal(t, "44eea1bc", got[0].ID.String())
   615  	assert.Equal(t, "65be62cd", got[1].ID.String())
   616  }
   617  
   618  func testTradesCursorPaginationByPartyWithCursorNoMarketForward(t *testing.T) {
   619  	ctx := tempTransaction(t)
   620  
   621  	bs, ts := setupTradesTest(t)
   622  	blockTimes := make(map[string]time.Time)
   623  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   624  	first := int32(2)
   625  	after := entities.NewCursor(entities.TradeCursor{SyntheticTime: blockTimes["44eea1bc"]}.String()).Encode()
   626  	pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, false)
   627  	require.NoError(t, err)
   628  	partyID := []entities.PartyID{"dabbad00"}
   629  	got, pageInfo, err := ts.List(ctx, nil, partyID, nil, pagination, entities.DateRange{})
   630  	require.NoError(t, err)
   631  	assert.Len(t, got, 2)
   632  	assert.Equal(t, "65be62cd", got[0].ID.String())
   633  	assert.Equal(t, uint64(3), got[0].Size)
   634  	assert.Equal(t, "7a797e0e", got[1].ID.String())
   635  	assert.Equal(t, uint64(4), got[1].Size)
   636  	assert.True(t, pageInfo.HasNextPage)
   637  	assert.True(t, pageInfo.HasPreviousPage)
   638  	assert.Equal(t, "65be62cd", got[0].ID.String())
   639  	assert.Equal(t, "7a797e0e", got[1].ID.String())
   640  }
   641  
   642  func testTradesCursorPaginationByPartyAndMarketWithCursorForward(t *testing.T) {
   643  	ctx := tempTransaction(t)
   644  
   645  	bs, ts := setupTradesTest(t)
   646  	blockTimes := make(map[string]time.Time)
   647  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   648  	first := int32(2)
   649  	after := entities.NewCursor(entities.TradeCursor{SyntheticTime: blockTimes["02a16077"]}.String()).Encode()
   650  	pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, false)
   651  	require.NoError(t, err)
   652  	partyID := []entities.PartyID{"dabbad00"}
   653  	marketID := []entities.MarketID{"deadbeef"}
   654  	got, pageInfo, err := ts.List(ctx, marketID, partyID, nil, pagination, entities.DateRange{})
   655  	require.NoError(t, err)
   656  	assert.Len(t, got, 2)
   657  	assert.Equal(t, "44eea1bc", got[0].ID.String())
   658  	assert.Equal(t, uint64(2), got[0].Size)
   659  	assert.Equal(t, "65be62cd", got[1].ID.String())
   660  	assert.Equal(t, uint64(3), got[1].Size)
   661  	assert.True(t, pageInfo.HasNextPage)
   662  	assert.True(t, pageInfo.HasPreviousPage)
   663  	assert.Equal(t, "44eea1bc", got[0].ID.String())
   664  	assert.Equal(t, "65be62cd", got[1].ID.String())
   665  }
   666  
   667  func testTradesCursorPaginationByMarketWithCursorBackward(t *testing.T) {
   668  	ctx := tempTransaction(t)
   669  
   670  	bs, ts := setupTradesTest(t)
   671  	blockTimes := make(map[string]time.Time)
   672  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   673  	last := int32(2)
   674  	before := entities.NewCursor(entities.TradeCursor{SyntheticTime: blockTimes["7a797e0e"]}.String()).Encode()
   675  	pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, false)
   676  	require.NoError(t, err)
   677  	marketID := []entities.MarketID{"deadbeef"}
   678  	got, pageInfo, err := ts.List(ctx, marketID, nil, nil, pagination, entities.DateRange{})
   679  	require.NoError(t, err)
   680  	assert.Len(t, got, 2)
   681  	assert.Equal(t, "44eea1bc", got[0].ID.String())
   682  	assert.Equal(t, uint64(2), got[0].Size)
   683  	assert.Equal(t, "65be62cd", got[1].ID.String())
   684  	assert.Equal(t, uint64(3), got[1].Size)
   685  	assert.True(t, pageInfo.HasNextPage)
   686  	assert.True(t, pageInfo.HasPreviousPage)
   687  	assert.Equal(t, "44eea1bc", got[0].ID.String())
   688  	assert.Equal(t, "65be62cd", got[1].ID.String())
   689  }
   690  
   691  func testTradesCursorPaginationByPartyWithCursorNoMarketBackward(t *testing.T) {
   692  	ctx := tempTransaction(t)
   693  
   694  	bs, ts := setupTradesTest(t)
   695  	blockTimes := make(map[string]time.Time)
   696  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   697  	last := int32(2)
   698  	before := entities.NewCursor(entities.TradeCursor{SyntheticTime: blockTimes["7bb2356e"]}.String()).Encode()
   699  	pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, false)
   700  	require.NoError(t, err)
   701  	partyID := []entities.PartyID{"dabbad00"}
   702  	got, pageInfo, err := ts.List(ctx, nil, partyID, nil, pagination, entities.DateRange{})
   703  	require.NoError(t, err)
   704  	assert.Len(t, got, 2)
   705  	assert.Equal(t, "65be62cd", got[0].ID.String())
   706  	assert.Equal(t, uint64(3), got[0].Size)
   707  	assert.Equal(t, "7a797e0e", got[1].ID.String())
   708  	assert.Equal(t, uint64(4), got[1].Size)
   709  	assert.True(t, pageInfo.HasNextPage)
   710  	assert.True(t, pageInfo.HasPreviousPage)
   711  	assert.Equal(t, "65be62cd", got[0].ID.String())
   712  	assert.Equal(t, "7a797e0e", got[1].ID.String())
   713  }
   714  
   715  func testTradesCursorPaginationByPartyAndMarketWithCursorBackward(t *testing.T) {
   716  	ctx := tempTransaction(t)
   717  
   718  	bs, ts := setupTradesTest(t)
   719  	blockTimes := make(map[string]time.Time)
   720  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   721  	last := int32(2)
   722  	before := entities.NewCursor(entities.TradeCursor{SyntheticTime: blockTimes["7a797e0e"]}.String()).Encode()
   723  	pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, false)
   724  	require.NoError(t, err)
   725  	partyID := []entities.PartyID{"dabbad00"}
   726  	marketID := []entities.MarketID{"deadbeef"}
   727  	got, pageInfo, err := ts.List(ctx, marketID, partyID, nil, pagination, entities.DateRange{})
   728  	require.NoError(t, err)
   729  	assert.Len(t, got, 2)
   730  	assert.Equal(t, "44eea1bc", got[0].ID.String())
   731  	assert.Equal(t, uint64(2), got[0].Size)
   732  	assert.Equal(t, "65be62cd", got[1].ID.String())
   733  	assert.Equal(t, uint64(3), got[1].Size)
   734  	assert.True(t, pageInfo.HasNextPage)
   735  	assert.True(t, pageInfo.HasPreviousPage)
   736  	assert.Equal(t, "44eea1bc", got[0].ID.String())
   737  	assert.Equal(t, "65be62cd", got[1].ID.String())
   738  }
   739  
   740  // Newest First.
   741  func testTradesCursorPaginationByMarketNoCursorNewestFirst(t *testing.T) {
   742  	ctx := tempTransaction(t)
   743  
   744  	bs, ts := setupTradesTest(t)
   745  	blockTimes := make(map[string]time.Time)
   746  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   747  	pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, true)
   748  	require.NoError(t, err)
   749  
   750  	marketID := []entities.MarketID{"deadbeef"}
   751  	got, pageInfo, err := ts.List(ctx, marketID, nil, nil, pagination, entities.DateRange{})
   752  	require.NoError(t, err)
   753  
   754  	assert.Len(t, got, 4)
   755  	assert.Equal(t, "7a797e0e", got[0].ID.String())
   756  	assert.Equal(t, uint64(4), got[0].Size)
   757  	assert.Equal(t, "02a16077", got[3].ID.String())
   758  	assert.Equal(t, uint64(1), got[3].Size)
   759  	assert.False(t, pageInfo.HasNextPage)
   760  	assert.False(t, pageInfo.HasPreviousPage)
   761  	assert.Equal(t, "7a797e0e", got[0].ID.String())
   762  	assert.Equal(t, "02a16077", got[3].ID.String())
   763  }
   764  
   765  func testTradesCursorPaginationByPartyNoMarketNoCursorNewestFirst(t *testing.T) {
   766  	ctx := tempTransaction(t)
   767  
   768  	bs, ts := setupTradesTest(t)
   769  	blockTimes := make(map[string]time.Time)
   770  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   771  	pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, true)
   772  	require.NoError(t, err)
   773  
   774  	partyID := []entities.PartyID{"dabbad00"}
   775  	got, pageInfo, err := ts.List(ctx, nil, partyID, nil, pagination, entities.DateRange{})
   776  	require.NoError(t, err)
   777  	assert.Len(t, got, 5)
   778  
   779  	assert.Equal(t, "7bb2356e", got[0].ID.String())
   780  	assert.Equal(t, uint64(5), got[0].Size)
   781  	assert.Equal(t, "02a16077", got[4].ID.String())
   782  	assert.Equal(t, uint64(1), got[4].Size)
   783  
   784  	assert.False(t, pageInfo.HasNextPage)
   785  	assert.False(t, pageInfo.HasPreviousPage)
   786  	assert.Equal(t, "7bb2356e", got[0].ID.String())
   787  	assert.Equal(t, "02a16077", got[4].ID.String())
   788  }
   789  
   790  func testTradesCursorPaginationByPartyAndMarketNoCursorNewestFirst(t *testing.T) {
   791  	ctx := tempTransaction(t)
   792  
   793  	bs, ts := setupTradesTest(t)
   794  	blockTimes := make(map[string]time.Time)
   795  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   796  	pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, true)
   797  	require.NoError(t, err)
   798  	partyID := []entities.PartyID{"dabbad00"}
   799  	marketID := []entities.MarketID{"deadbeef"}
   800  	got, pageInfo, err := ts.List(ctx, marketID, partyID, nil, pagination, entities.DateRange{})
   801  	require.NoError(t, err)
   802  	assert.Len(t, got, 4)
   803  	assert.Equal(t, "7a797e0e", got[0].ID.String())
   804  	assert.Equal(t, uint64(4), got[0].Size)
   805  	assert.Equal(t, "02a16077", got[3].ID.String())
   806  	assert.Equal(t, uint64(1), got[3].Size)
   807  	assert.False(t, pageInfo.HasNextPage)
   808  	assert.False(t, pageInfo.HasPreviousPage)
   809  	assert.Equal(t, "7a797e0e", got[0].ID.String())
   810  	assert.Equal(t, "02a16077", got[3].ID.String())
   811  }
   812  
   813  func testTradesCursorPaginationByMarketWithCursorFirstNewestFirst(t *testing.T) {
   814  	ctx := tempTransaction(t)
   815  
   816  	bs, ts := setupTradesTest(t)
   817  	blockTimes := make(map[string]time.Time)
   818  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   819  	first := int32(2)
   820  	pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, true)
   821  	require.NoError(t, err)
   822  	marketID := []entities.MarketID{"deadbeef"}
   823  	got, pageInfo, err := ts.List(ctx, marketID, nil, nil, pagination, entities.DateRange{})
   824  	require.NoError(t, err)
   825  
   826  	assert.Len(t, got, 2)
   827  	assert.Equal(t, "7a797e0e", got[0].ID.String())
   828  	assert.Equal(t, uint64(4), got[0].Size)
   829  	assert.Equal(t, "65be62cd", got[1].ID.String())
   830  	assert.Equal(t, uint64(3), got[1].Size)
   831  	assert.True(t, pageInfo.HasNextPage)
   832  	assert.False(t, pageInfo.HasPreviousPage)
   833  	assert.Equal(t, "7a797e0e", got[0].ID.String())
   834  	assert.Equal(t, "65be62cd", got[1].ID.String())
   835  }
   836  
   837  func testTradesCursorPaginationByPartyWithCursorNoMarketFirstNewestFirst(t *testing.T) {
   838  	ctx := tempTransaction(t)
   839  
   840  	bs, ts := setupTradesTest(t)
   841  	blockTimes := make(map[string]time.Time)
   842  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   843  	first := int32(2)
   844  	pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, true)
   845  	require.NoError(t, err)
   846  	partyID := []entities.PartyID{"dabbad00"}
   847  	got, pageInfo, err := ts.List(ctx, nil, partyID, nil, pagination, entities.DateRange{})
   848  	require.NoError(t, err)
   849  	assert.Len(t, got, 2)
   850  	assert.Equal(t, "7bb2356e", got[0].ID.String())
   851  	assert.Equal(t, uint64(5), got[0].Size)
   852  	assert.Equal(t, "7a797e0e", got[1].ID.String())
   853  	assert.Equal(t, uint64(4), got[1].Size)
   854  	assert.True(t, pageInfo.HasNextPage)
   855  	assert.False(t, pageInfo.HasPreviousPage)
   856  	assert.Equal(t, "7bb2356e", got[0].ID.String())
   857  	assert.Equal(t, "7a797e0e", got[1].ID.String())
   858  }
   859  
   860  func testTradesCursorPaginationByPartyAndMarketWithCursorFirstNewestFirst(t *testing.T) {
   861  	ctx := tempTransaction(t)
   862  
   863  	bs, ts := setupTradesTest(t)
   864  	blockTimes := make(map[string]time.Time)
   865  	first := int32(2)
   866  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   867  	pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, true)
   868  	require.NoError(t, err)
   869  	partyID := []entities.PartyID{"dabbad00"}
   870  	marketID := []entities.MarketID{"deadbeef"}
   871  	got, pageInfo, err := ts.List(ctx, marketID, partyID, nil, pagination, entities.DateRange{})
   872  	require.NoError(t, err)
   873  	assert.Len(t, got, 2)
   874  	assert.Equal(t, "7a797e0e", got[0].ID.String())
   875  	assert.Equal(t, uint64(4), got[0].Size)
   876  	assert.Equal(t, "65be62cd", got[1].ID.String())
   877  	assert.Equal(t, uint64(3), got[1].Size)
   878  	assert.True(t, pageInfo.HasNextPage)
   879  	assert.False(t, pageInfo.HasPreviousPage)
   880  	assert.Equal(t, "7a797e0e", got[0].ID.String())
   881  	assert.Equal(t, "65be62cd", got[1].ID.String())
   882  }
   883  
   884  func testTradesCursorPaginationByMarketWithCursorLastNewestFirst(t *testing.T) {
   885  	ctx := tempTransaction(t)
   886  
   887  	bs, ts := setupTradesTest(t)
   888  	blockTimes := make(map[string]time.Time)
   889  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   890  	last := int32(2)
   891  	pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, true)
   892  	require.NoError(t, err)
   893  	marketID := []entities.MarketID{"deadbeef"}
   894  	got, pageInfo, err := ts.List(ctx, marketID, nil, nil, pagination, entities.DateRange{})
   895  	require.NoError(t, err)
   896  
   897  	assert.Len(t, got, 2)
   898  	assert.Equal(t, "44eea1bc", got[0].ID.String())
   899  	assert.Equal(t, uint64(2), got[0].Size)
   900  	assert.Equal(t, "02a16077", got[1].ID.String())
   901  	assert.Equal(t, uint64(1), got[1].Size)
   902  	assert.False(t, pageInfo.HasNextPage)
   903  	assert.True(t, pageInfo.HasPreviousPage)
   904  	assert.Equal(t, "44eea1bc", got[0].ID.String())
   905  	assert.Equal(t, "02a16077", got[1].ID.String())
   906  }
   907  
   908  func testTradesCursorPaginationByPartyWithCursorNoMarketLastNewestFirst(t *testing.T) {
   909  	ctx := tempTransaction(t)
   910  
   911  	bs, ts := setupTradesTest(t)
   912  	blockTimes := make(map[string]time.Time)
   913  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   914  	last := int32(2)
   915  	pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, true)
   916  	require.NoError(t, err)
   917  	partyID := []entities.PartyID{"dabbad00"}
   918  	got, pageInfo, err := ts.List(ctx, nil, partyID, nil, pagination, entities.DateRange{})
   919  	require.NoError(t, err)
   920  	assert.Len(t, got, 2)
   921  	assert.Equal(t, "44eea1bc", got[0].ID.String())
   922  	assert.Equal(t, uint64(2), got[0].Size)
   923  	assert.Equal(t, "02a16077", got[1].ID.String())
   924  	assert.Equal(t, uint64(1), got[1].Size)
   925  	assert.False(t, pageInfo.HasNextPage)
   926  	assert.True(t, pageInfo.HasPreviousPage)
   927  	assert.Equal(t, "44eea1bc", got[0].ID.String())
   928  	assert.Equal(t, "02a16077", got[1].ID.String())
   929  }
   930  
   931  func testTradesCursorPaginationByPartyAndMarketWithCursorLastNewestFirst(t *testing.T) {
   932  	ctx := tempTransaction(t)
   933  
   934  	bs, ts := setupTradesTest(t)
   935  	blockTimes := make(map[string]time.Time)
   936  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   937  	last := int32(2)
   938  	pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, true)
   939  	require.NoError(t, err)
   940  	partyID := []entities.PartyID{"dabbad00"}
   941  	marketID := []entities.MarketID{"deadbeef"}
   942  	got, pageInfo, err := ts.List(ctx, marketID, partyID, nil, pagination, entities.DateRange{})
   943  	require.NoError(t, err)
   944  	assert.Len(t, got, 2)
   945  	assert.Equal(t, "44eea1bc", got[0].ID.String())
   946  	assert.Equal(t, uint64(2), got[0].Size)
   947  	assert.Equal(t, "02a16077", got[1].ID.String())
   948  	assert.Equal(t, uint64(1), got[1].Size)
   949  	assert.False(t, pageInfo.HasNextPage)
   950  	assert.True(t, pageInfo.HasPreviousPage)
   951  	assert.Equal(t, "44eea1bc", got[0].ID.String())
   952  	assert.Equal(t, "02a16077", got[1].ID.String())
   953  }
   954  
   955  func testTradesCursorPaginationByMarketWithCursorForwardNewestFirst(t *testing.T) {
   956  	ctx := tempTransaction(t)
   957  
   958  	bs, ts := setupTradesTest(t)
   959  	blockTimes := make(map[string]time.Time)
   960  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   961  	first := int32(2)
   962  	after := entities.NewCursor(entities.TradeCursor{SyntheticTime: blockTimes["7a797e0e"]}.String()).Encode()
   963  	pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, true)
   964  	require.NoError(t, err)
   965  	marketID := []entities.MarketID{"deadbeef"}
   966  	got, pageInfo, err := ts.List(ctx, marketID, nil, nil, pagination, entities.DateRange{})
   967  	require.NoError(t, err)
   968  
   969  	assert.Len(t, got, 2)
   970  	assert.Equal(t, "65be62cd", got[0].ID.String())
   971  	assert.Equal(t, uint64(3), got[0].Size)
   972  	assert.Equal(t, "44eea1bc", got[1].ID.String())
   973  	assert.Equal(t, uint64(2), got[1].Size)
   974  	assert.True(t, pageInfo.HasNextPage)
   975  	assert.True(t, pageInfo.HasPreviousPage)
   976  	assert.Equal(t, "65be62cd", got[0].ID.String())
   977  	assert.Equal(t, "44eea1bc", got[1].ID.String())
   978  }
   979  
   980  func testTradesCursorPaginationByPartyWithCursorNoMarketForwardNewestFirst(t *testing.T) {
   981  	ctx := tempTransaction(t)
   982  
   983  	bs, ts := setupTradesTest(t)
   984  	blockTimes := make(map[string]time.Time)
   985  	populateTestTrades(ctx, t, bs, ts, blockTimes)
   986  	first := int32(2)
   987  	after := entities.NewCursor(entities.TradeCursor{SyntheticTime: blockTimes["7a797e0e"]}.String()).Encode()
   988  	pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, true)
   989  	require.NoError(t, err)
   990  	partyID := []entities.PartyID{"dabbad00"}
   991  	got, pageInfo, err := ts.List(ctx, nil, partyID, nil, pagination, entities.DateRange{})
   992  	require.NoError(t, err)
   993  	assert.Len(t, got, 2)
   994  	assert.Equal(t, "65be62cd", got[0].ID.String())
   995  	assert.Equal(t, uint64(3), got[0].Size)
   996  	assert.Equal(t, "44eea1bc", got[1].ID.String())
   997  	assert.Equal(t, uint64(2), got[1].Size)
   998  	assert.True(t, pageInfo.HasNextPage)
   999  	assert.True(t, pageInfo.HasPreviousPage)
  1000  	assert.Equal(t, "65be62cd", got[0].ID.String())
  1001  	assert.Equal(t, "44eea1bc", got[1].ID.String())
  1002  }
  1003  
  1004  func testTradesCursorPaginationByPartyAndMarketWithCursorForwardNewestFirst(t *testing.T) {
  1005  	ctx := tempTransaction(t)
  1006  
  1007  	bs, ts := setupTradesTest(t)
  1008  	blockTimes := make(map[string]time.Time)
  1009  	populateTestTrades(ctx, t, bs, ts, blockTimes)
  1010  	first := int32(2)
  1011  	after := entities.NewCursor(entities.TradeCursor{SyntheticTime: blockTimes["7a797e0e"]}.String()).Encode()
  1012  	pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, true)
  1013  	require.NoError(t, err)
  1014  	partyID := []entities.PartyID{"dabbad00"}
  1015  	marketID := []entities.MarketID{"deadbeef"}
  1016  	got, pageInfo, err := ts.List(ctx, marketID, partyID, nil, pagination, entities.DateRange{})
  1017  	require.NoError(t, err)
  1018  	assert.Len(t, got, 2)
  1019  	assert.Equal(t, "65be62cd", got[0].ID.String())
  1020  	assert.Equal(t, uint64(3), got[0].Size)
  1021  	assert.Equal(t, "44eea1bc", got[1].ID.String())
  1022  	assert.Equal(t, uint64(2), got[1].Size)
  1023  	assert.True(t, pageInfo.HasNextPage)
  1024  	assert.True(t, pageInfo.HasPreviousPage)
  1025  	assert.Equal(t, "65be62cd", got[0].ID.String())
  1026  	assert.Equal(t, "44eea1bc", got[1].ID.String())
  1027  }
  1028  
  1029  func testTradesCursorPaginationByMarketWithCursorBackwardNewestFirst(t *testing.T) {
  1030  	ctx := tempTransaction(t)
  1031  
  1032  	bs, ts := setupTradesTest(t)
  1033  	blockTimes := make(map[string]time.Time)
  1034  	populateTestTrades(ctx, t, bs, ts, blockTimes)
  1035  	last := int32(2)
  1036  	before := entities.NewCursor(entities.TradeCursor{SyntheticTime: blockTimes["02a16077"]}.String()).Encode()
  1037  	pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, true)
  1038  	require.NoError(t, err)
  1039  	marketID := []entities.MarketID{"deadbeef"}
  1040  	got, pageInfo, err := ts.List(ctx, marketID, nil, nil, pagination, entities.DateRange{})
  1041  	require.NoError(t, err)
  1042  	assert.Len(t, got, 2)
  1043  	assert.Equal(t, "65be62cd", got[0].ID.String())
  1044  	assert.Equal(t, uint64(3), got[0].Size)
  1045  	assert.Equal(t, "44eea1bc", got[1].ID.String())
  1046  	assert.Equal(t, uint64(2), got[1].Size)
  1047  	assert.True(t, pageInfo.HasNextPage)
  1048  	assert.True(t, pageInfo.HasPreviousPage)
  1049  	assert.Equal(t, "65be62cd", got[0].ID.String())
  1050  	assert.Equal(t, "44eea1bc", got[1].ID.String())
  1051  }
  1052  
  1053  func testTradesCursorPaginationByPartyWithCursorNoMarketBackwardNewestFirst(t *testing.T) {
  1054  	ctx := tempTransaction(t)
  1055  
  1056  	bs, ts := setupTradesTest(t)
  1057  	blockTimes := make(map[string]time.Time)
  1058  	populateTestTrades(ctx, t, bs, ts, blockTimes)
  1059  	last := int32(2)
  1060  	before := entities.NewCursor(entities.TradeCursor{SyntheticTime: blockTimes["44eea1bc"]}.String()).Encode()
  1061  	pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, true)
  1062  	require.NoError(t, err)
  1063  	partyID := []entities.PartyID{"dabbad00"}
  1064  	got, pageInfo, err := ts.List(ctx, nil, partyID, nil, pagination, entities.DateRange{})
  1065  	require.NoError(t, err)
  1066  	assert.Len(t, got, 2)
  1067  	assert.Equal(t, "7a797e0e", got[0].ID.String())
  1068  	assert.Equal(t, uint64(4), got[0].Size)
  1069  	assert.Equal(t, "65be62cd", got[1].ID.String())
  1070  	assert.Equal(t, uint64(3), got[1].Size)
  1071  	assert.True(t, pageInfo.HasNextPage)
  1072  	assert.True(t, pageInfo.HasPreviousPage)
  1073  	assert.Equal(t, "7a797e0e", got[0].ID.String())
  1074  	assert.Equal(t, "65be62cd", got[1].ID.String())
  1075  }
  1076  
  1077  func testTradesCursorPaginationByPartyAndMarketWithCursorBackwardNewestFirst(t *testing.T) {
  1078  	ctx := tempTransaction(t)
  1079  
  1080  	bs, ts := setupTradesTest(t)
  1081  	blockTimes := make(map[string]time.Time)
  1082  	populateTestTrades(ctx, t, bs, ts, blockTimes)
  1083  	last := int32(2)
  1084  	before := entities.NewCursor(entities.TradeCursor{SyntheticTime: blockTimes["02a16077"]}.String()).Encode()
  1085  	pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, true)
  1086  	require.NoError(t, err)
  1087  	partyID := []entities.PartyID{"dabbad00"}
  1088  	marketID := []entities.MarketID{"deadbeef"}
  1089  	got, pageInfo, err := ts.List(ctx, marketID, partyID, nil, pagination, entities.DateRange{})
  1090  	require.NoError(t, err)
  1091  	assert.Len(t, got, 2)
  1092  	assert.Equal(t, "65be62cd", got[0].ID.String())
  1093  	assert.Equal(t, uint64(3), got[0].Size)
  1094  	assert.Equal(t, "44eea1bc", got[1].ID.String())
  1095  	assert.Equal(t, uint64(2), got[1].Size)
  1096  	assert.True(t, pageInfo.HasNextPage)
  1097  	assert.True(t, pageInfo.HasPreviousPage)
  1098  	assert.Equal(t, "65be62cd", got[0].ID.String())
  1099  	assert.Equal(t, "44eea1bc", got[1].ID.String())
  1100  }
  1101  
  1102  func testTradesCursorPaginationBetweenDatesByMarketNoCursor(t *testing.T) {
  1103  	ctx := tempTransaction(t)
  1104  
  1105  	bs, ts := setupTradesTest(t)
  1106  	blockTimes := make(map[string]time.Time)
  1107  	populateTestTrades(ctx, t, bs, ts, blockTimes)
  1108  	pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, false)
  1109  	require.NoError(t, err)
  1110  
  1111  	marketID := []entities.MarketID{"deadbeef"}
  1112  	startDate := blockTimes["44eea1bc"]
  1113  	endDate := blockTimes["7a797e0e"]
  1114  	got, pageInfo, err := ts.List(ctx, marketID, nil, nil, pagination, entities.DateRange{
  1115  		Start: &startDate,
  1116  		End:   &endDate,
  1117  	})
  1118  	require.NoError(t, err)
  1119  
  1120  	assert.Len(t, got, 2)
  1121  	assert.Equal(t, "44eea1bc", got[0].ID.String())
  1122  	assert.Equal(t, uint64(2), got[0].Size)
  1123  	assert.Equal(t, "65be62cd", got[1].ID.String())
  1124  	assert.Equal(t, uint64(3), got[1].Size)
  1125  	assert.False(t, pageInfo.HasNextPage)
  1126  	assert.False(t, pageInfo.HasPreviousPage)
  1127  }
  1128  
  1129  func testTradesCursorPaginationBetweenDatesByMarketNoCursorNewestFirst(t *testing.T) {
  1130  	ctx := tempTransaction(t)
  1131  
  1132  	bs, ts := setupTradesTest(t)
  1133  	blockTimes := make(map[string]time.Time)
  1134  	populateTestTrades(ctx, t, bs, ts, blockTimes)
  1135  	pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, true)
  1136  	require.NoError(t, err)
  1137  
  1138  	marketID := []entities.MarketID{"deadbeef"}
  1139  	startDate := blockTimes["44eea1bc"]
  1140  	endDate := blockTimes["7a797e0e"]
  1141  	got, pageInfo, err := ts.List(ctx, marketID, nil, nil, pagination, entities.DateRange{
  1142  		Start: &startDate,
  1143  		End:   &endDate,
  1144  	})
  1145  	require.NoError(t, err)
  1146  
  1147  	assert.Len(t, got, 2)
  1148  	assert.Equal(t, "65be62cd", got[0].ID.String())
  1149  	assert.Equal(t, uint64(3), got[0].Size)
  1150  	assert.Equal(t, "44eea1bc", got[1].ID.String())
  1151  	assert.Equal(t, uint64(2), got[1].Size)
  1152  	assert.False(t, pageInfo.HasNextPage)
  1153  	assert.False(t, pageInfo.HasPreviousPage)
  1154  }
  1155  
  1156  func testTradesCursorPaginationBetweenDatesByMarketWithCursorLast(t *testing.T) {
  1157  	ctx := tempTransaction(t)
  1158  
  1159  	bs, ts := setupTradesTest(t)
  1160  	blockTimes := make(map[string]time.Time)
  1161  	populateTestTrades(ctx, t, bs, ts, blockTimes)
  1162  	last := int32(2)
  1163  	pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, false)
  1164  	require.NoError(t, err)
  1165  	marketID := []entities.MarketID{"deadbeef"}
  1166  	startDate := blockTimes["02a16077"]
  1167  	endDate := blockTimes["7a797e0e"]
  1168  	got, pageInfo, err := ts.List(ctx, marketID, nil, nil, pagination, entities.DateRange{
  1169  		Start: &startDate,
  1170  		End:   &endDate,
  1171  	})
  1172  	require.NoError(t, err)
  1173  
  1174  	assert.Len(t, got, 2)
  1175  	assert.Equal(t, "44eea1bc", got[0].ID.String())
  1176  	assert.Equal(t, uint64(2), got[0].Size)
  1177  	assert.Equal(t, "65be62cd", got[1].ID.String())
  1178  	assert.Equal(t, uint64(3), got[1].Size)
  1179  	assert.False(t, pageInfo.HasNextPage)
  1180  	assert.True(t, pageInfo.HasPreviousPage)
  1181  }
  1182  
  1183  func testTradesCursorPaginationBetweenDatesByMarketWithCursorForward(t *testing.T) {
  1184  	ctx := tempTransaction(t)
  1185  
  1186  	bs, ts := setupTradesTest(t)
  1187  	blockTimes := make(map[string]time.Time)
  1188  	populateTestTrades(ctx, t, bs, ts, blockTimes)
  1189  	first := int32(2)
  1190  	after := entities.NewCursor(entities.TradeCursor{SyntheticTime: blockTimes["02a16077"]}.String()).Encode()
  1191  	pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, false)
  1192  	require.NoError(t, err)
  1193  	marketID := []entities.MarketID{"deadbeef"}
  1194  	startDate := blockTimes["02a16077"]
  1195  	endDate := blockTimes["7a797e0e"]
  1196  	got, pageInfo, err := ts.List(ctx, marketID, nil, nil, pagination, entities.DateRange{
  1197  		Start: &startDate,
  1198  		End:   &endDate,
  1199  	})
  1200  	require.NoError(t, err)
  1201  
  1202  	assert.Len(t, got, 2)
  1203  	assert.Equal(t, "44eea1bc", got[0].ID.String())
  1204  	assert.Equal(t, uint64(2), got[0].Size)
  1205  	assert.Equal(t, "65be62cd", got[1].ID.String())
  1206  	assert.Equal(t, uint64(3), got[1].Size)
  1207  	assert.False(t, pageInfo.HasNextPage)
  1208  	assert.True(t, pageInfo.HasPreviousPage)
  1209  }
  1210  
  1211  func tesGetCurrentTransferFeeDiscount(t *testing.T) {
  1212  	ctx := tempTransaction(t)
  1213  
  1214  	transfers := sqlstore.NewTransfers(connectionSource)
  1215  
  1216  	vegaTime := time.Now().Truncate(time.Microsecond)
  1217  
  1218  	partyID := entities.PartyID(hex.EncodeToString([]byte("party-1")))
  1219  	assetID := entities.AssetID(hex.EncodeToString([]byte("asset-1")))
  1220  	secondAssetID := entities.AssetID(hex.EncodeToString([]byte("asset-2")))
  1221  
  1222  	tfd := &entities.TransferFeesDiscount{
  1223  		PartyID:  partyID,
  1224  		AssetID:  assetID,
  1225  		Amount:   num.DecimalFromInt64(500),
  1226  		EpochSeq: 1,
  1227  		VegaTime: vegaTime,
  1228  	}
  1229  	assert.NoError(t, transfers.UpsertFeesDiscount(ctx, tfd))
  1230  	discount, err := transfers.GetCurrentTransferFeeDiscount(ctx, partyID, assetID)
  1231  	assert.NoError(t, err)
  1232  	assert.Equal(t, tfd, discount)
  1233  
  1234  	secondTfd := &entities.TransferFeesDiscount{
  1235  		PartyID:  partyID,
  1236  		AssetID:  secondAssetID,
  1237  		Amount:   num.DecimalFromInt64(150),
  1238  		EpochSeq: 1,
  1239  		VegaTime: vegaTime,
  1240  	}
  1241  	assert.NoError(t, transfers.UpsertFeesDiscount(ctx, secondTfd))
  1242  	discount, err = transfers.GetCurrentTransferFeeDiscount(ctx, partyID, secondAssetID)
  1243  	assert.NoError(t, err)
  1244  	assert.Equal(t, secondTfd, discount)
  1245  
  1246  	// update the amount for the same party and asset
  1247  	vegaTime = vegaTime.Add(time.Second)
  1248  	tfd.VegaTime = vegaTime
  1249  	tfd.Amount = num.DecimalFromInt64(400)
  1250  	assert.NoError(t, transfers.UpsertFeesDiscount(ctx, tfd))
  1251  
  1252  	discount, err = transfers.GetCurrentTransferFeeDiscount(ctx, partyID, assetID)
  1253  	assert.NoError(t, err)
  1254  	assert.Equal(t, tfd, discount)
  1255  }