code.vegaprotocol.io/vega@v0.79.0/datanode/sqlstore/stop_orders_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  	"fmt"
    20  	"sort"
    21  	"testing"
    22  	"time"
    23  
    24  	"code.vegaprotocol.io/vega/datanode/entities"
    25  	"code.vegaprotocol.io/vega/datanode/sqlstore"
    26  	"code.vegaprotocol.io/vega/datanode/sqlstore/helpers"
    27  	"code.vegaprotocol.io/vega/libs/ptr"
    28  	vegapb "code.vegaprotocol.io/vega/protos/vega"
    29  	commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1"
    30  
    31  	"github.com/georgysavva/scany/pgxscan"
    32  	"github.com/stretchr/testify/assert"
    33  	"github.com/stretchr/testify/require"
    34  )
    35  
    36  type testStopOrderInputs struct {
    37  	orderID        string
    38  	vegaTime       time.Time
    39  	createdAt      time.Time
    40  	triggerPrice   string
    41  	partyID        entities.PartyID
    42  	marketID       entities.MarketID
    43  	status         entities.StopOrderStatus
    44  	expiryStrategy entities.StopOrderExpiryStrategy
    45  }
    46  
    47  func generateTestStopOrders(t *testing.T, testOrders []testStopOrderInputs) []entities.StopOrder {
    48  	t.Helper()
    49  	orders := make([]entities.StopOrder, 0)
    50  
    51  	for i, o := range testOrders {
    52  		so := entities.StopOrder{
    53  			ID:               entities.StopOrderID(o.orderID),
    54  			ExpiryStrategy:   o.expiryStrategy,
    55  			TriggerDirection: 0,
    56  			Status:           o.status,
    57  			CreatedAt:        o.createdAt,
    58  			UpdatedAt:        nil,
    59  			OrderID:          "",
    60  			TriggerPrice:     ptr.From(o.triggerPrice),
    61  			PartyID:          o.partyID,
    62  			MarketID:         o.marketID,
    63  			VegaTime:         o.vegaTime,
    64  			SeqNum:           uint64(i),
    65  			TxHash:           txHashFromString(fmt.Sprintf("%s-%s-%03d", o.orderID, o.vegaTime.String(), i)),
    66  			Submission: &commandspb.OrderSubmission{
    67  				MarketId:    o.marketID.String(),
    68  				Price:       "100",
    69  				Size:        uint64(100 + i),
    70  				Side:        entities.SideBuy,
    71  				TimeInForce: entities.OrderTimeInForceUnspecified,
    72  				ExpiresAt:   0,
    73  				Type:        entities.OrderTypeMarket,
    74  				Reference:   o.orderID,
    75  			},
    76  			RejectionReason: entities.StopOrderRejectionReasonUnspecified,
    77  		}
    78  		orders = append(orders, so)
    79  	}
    80  
    81  	return orders
    82  }
    83  
    84  func TestStopOrders_Add(t *testing.T) {
    85  	so := sqlstore.NewStopOrders(connectionSource)
    86  	bs := sqlstore.NewBlocks(connectionSource)
    87  	ps := sqlstore.NewParties(connectionSource)
    88  	ms := sqlstore.NewMarkets(connectionSource)
    89  
    90  	ctx := tempTransaction(t)
    91  
    92  	blocks := []entities.Block{
    93  		addTestBlock(t, ctx, bs),
    94  		addTestBlock(t, ctx, bs),
    95  		addTestBlock(t, ctx, bs),
    96  	}
    97  
    98  	parties := []entities.Party{
    99  		addTestParty(t, ctx, ps, blocks[0]),
   100  		addTestParty(t, ctx, ps, blocks[0]),
   101  		addTestParty(t, ctx, ps, blocks[0]),
   102  	}
   103  
   104  	markets := helpers.GenerateMarkets(t, ctx, 3, blocks[0], ms)
   105  
   106  	inputs := make([]testStopOrderInputs, 0)
   107  
   108  	for _, b := range blocks {
   109  		for _, p := range parties {
   110  			for _, m := range markets {
   111  				inputs = append(inputs, testStopOrderInputs{
   112  					orderID:        GenerateID(),
   113  					vegaTime:       b.VegaTime,
   114  					createdAt:      b.VegaTime,
   115  					triggerPrice:   "100",
   116  					partyID:        p.ID,
   117  					marketID:       m.ID,
   118  					status:         entities.StopOrderStatusUnspecified,
   119  					expiryStrategy: entities.StopOrderExpiryStrategyUnspecified,
   120  				})
   121  			}
   122  		}
   123  	}
   124  
   125  	stopOrders := generateTestStopOrders(t, inputs)
   126  
   127  	t.Run("add should batch orders and not insert the records", func(t *testing.T) {
   128  		for _, o := range stopOrders {
   129  			err := so.Add(o)
   130  			require.NoError(t, err)
   131  		}
   132  
   133  		rows, err := connectionSource.Query(ctx, "select * from stop_orders")
   134  		require.NoError(t, err)
   135  		assert.False(t, rows.Next())
   136  
   137  		t.Run("and insert them when flush is called", func(t *testing.T) {
   138  			orders, err := so.Flush(ctx)
   139  			require.NoError(t, err)
   140  			assert.Len(t, orders, len(stopOrders))
   141  
   142  			var results []entities.StopOrder
   143  			err = pgxscan.Select(ctx, connectionSource, &results, "select * from stop_orders")
   144  			require.NoError(t, err)
   145  			assert.Len(t, results, len(stopOrders))
   146  			assert.ElementsMatch(t, results, orders)
   147  		})
   148  	})
   149  }
   150  
   151  func TestStopOrders_Get(t *testing.T) {
   152  	so := sqlstore.NewStopOrders(connectionSource)
   153  	bs := sqlstore.NewBlocks(connectionSource)
   154  	ps := sqlstore.NewParties(connectionSource)
   155  	ms := sqlstore.NewMarkets(connectionSource)
   156  
   157  	ctx := tempTransaction(t)
   158  
   159  	block := addTestBlock(t, ctx, bs)
   160  	block2 := addTestBlock(t, ctx, bs)
   161  
   162  	party := addTestParty(t, ctx, ps, block)
   163  
   164  	markets := helpers.GenerateMarkets(t, ctx, 1, block, ms)
   165  
   166  	orderID := GenerateID()
   167  	stopOrders := generateTestStopOrders(t, []testStopOrderInputs{
   168  		{
   169  			orderID:        orderID,
   170  			vegaTime:       block.VegaTime,
   171  			createdAt:      block.VegaTime,
   172  			triggerPrice:   "100",
   173  			partyID:        party.ID,
   174  			marketID:       markets[0].ID,
   175  			status:         entities.StopOrderStatusPending,
   176  			expiryStrategy: entities.StopOrderExpiryStrategyUnspecified,
   177  		},
   178  		{
   179  			orderID:        orderID,
   180  			vegaTime:       block2.VegaTime,
   181  			createdAt:      block.VegaTime,
   182  			triggerPrice:   "100",
   183  			partyID:        party.ID,
   184  			marketID:       markets[0].ID,
   185  			status:         entities.StopOrderStatusTriggered,
   186  			expiryStrategy: entities.StopOrderExpiryStrategyUnspecified,
   187  		},
   188  	})
   189  
   190  	for i := range stopOrders {
   191  		err := so.Add(stopOrders[i])
   192  		require.NoError(t, err)
   193  	}
   194  
   195  	want, err := so.Flush(ctx)
   196  	require.NoError(t, err)
   197  
   198  	t.Run("Get should return an error if the order ID does not exist", func(t *testing.T) {
   199  		got, err := so.GetStopOrder(ctx, "deadbeef")
   200  		require.Error(t, err)
   201  		assert.Equal(t, entities.StopOrder{}, got)
   202  	})
   203  
   204  	t.Run("Get should return the order if the order ID does exist", func(t *testing.T) {
   205  		got, err := so.GetStopOrder(ctx, orderID)
   206  		require.NoError(t, err)
   207  		assert.Equal(t, want[1], got)
   208  	})
   209  }
   210  
   211  func TestStopOrders_ListStopOrders(t *testing.T) {
   212  	so := sqlstore.NewStopOrders(connectionSource)
   213  	bs := sqlstore.NewBlocks(connectionSource)
   214  	ps := sqlstore.NewParties(connectionSource)
   215  	ms := sqlstore.NewMarkets(connectionSource)
   216  
   217  	ctx := tempTransaction(t)
   218  
   219  	blocks := []entities.Block{
   220  		addTestBlock(t, ctx, bs),
   221  		addTestBlock(t, ctx, bs),
   222  		addTestBlock(t, ctx, bs),
   223  		addTestBlock(t, ctx, bs),
   224  		addTestBlock(t, ctx, bs),
   225  		addTestBlock(t, ctx, bs),
   226  	}
   227  
   228  	parties := []entities.Party{
   229  		addTestParty(t, ctx, ps, blocks[0]),
   230  		addTestParty(t, ctx, ps, blocks[0]),
   231  		addTestParty(t, ctx, ps, blocks[0]),
   232  		addTestParty(t, ctx, ps, blocks[0]),
   233  	}
   234  
   235  	markets := helpers.GenerateMarkets(t, ctx, 10, blocks[0], ms)
   236  	orderIDs := []string{
   237  		"deadbeef01",
   238  		"deadbeef02",
   239  		"deadbeef03",
   240  		"deadbeef04",
   241  		"deadbeef05",
   242  		"deadbeef06",
   243  		"deadbeef07",
   244  		"deadbeef08",
   245  		"deadbeef09",
   246  		"deadbeef10",
   247  		"deadbeef11",
   248  		"deadbeef12",
   249  	}
   250  
   251  	stopOrders := generateTestStopOrders(t, []testStopOrderInputs{
   252  		{ // 0
   253  			orderID:        orderIDs[0],
   254  			vegaTime:       blocks[0].VegaTime,
   255  			createdAt:      blocks[0].VegaTime,
   256  			triggerPrice:   "100",
   257  			partyID:        parties[0].ID,
   258  			marketID:       markets[0].ID,
   259  			status:         entities.StopOrderStatusUnspecified,
   260  			expiryStrategy: entities.StopOrderExpiryStrategyUnspecified,
   261  		},
   262  		{ // 1
   263  			orderID:        orderIDs[1],
   264  			vegaTime:       blocks[0].VegaTime,
   265  			createdAt:      blocks[0].VegaTime,
   266  			triggerPrice:   "100",
   267  			partyID:        parties[1].ID,
   268  			marketID:       markets[1].ID,
   269  			status:         entities.StopOrderStatusUnspecified,
   270  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   271  		},
   272  		{ // 2
   273  			orderID:        orderIDs[2],
   274  			vegaTime:       blocks[0].VegaTime,
   275  			createdAt:      blocks[0].VegaTime,
   276  			triggerPrice:   "100",
   277  			partyID:        parties[2].ID,
   278  			marketID:       markets[2].ID,
   279  			status:         entities.StopOrderStatusUnspecified,
   280  			expiryStrategy: entities.StopOrderExpiryStrategyCancels,
   281  		},
   282  		{ // 3
   283  			orderID:        orderIDs[3],
   284  			vegaTime:       blocks[0].VegaTime,
   285  			createdAt:      blocks[0].VegaTime,
   286  			triggerPrice:   "100",
   287  			partyID:        parties[1].ID,
   288  			marketID:       markets[3].ID,
   289  			status:         entities.StopOrderStatusUnspecified,
   290  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   291  		},
   292  		{ // 4
   293  			orderID:        orderIDs[4],
   294  			vegaTime:       blocks[0].VegaTime,
   295  			createdAt:      blocks[0].VegaTime,
   296  			triggerPrice:   "100",
   297  			partyID:        parties[2].ID,
   298  			marketID:       markets[4].ID,
   299  			status:         entities.StopOrderStatusUnspecified,
   300  			expiryStrategy: entities.StopOrderExpiryStrategyCancels,
   301  		},
   302  		{ // 5
   303  			orderID:        orderIDs[5],
   304  			vegaTime:       blocks[0].VegaTime,
   305  			createdAt:      blocks[0].VegaTime,
   306  			triggerPrice:   "100",
   307  			partyID:        parties[1].ID,
   308  			marketID:       markets[5].ID,
   309  			status:         entities.StopOrderStatusUnspecified,
   310  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   311  		},
   312  		{ // 6
   313  			orderID:        orderIDs[6],
   314  			vegaTime:       blocks[0].VegaTime,
   315  			createdAt:      blocks[0].VegaTime,
   316  			triggerPrice:   "100",
   317  			partyID:        parties[2].ID,
   318  			marketID:       markets[6].ID,
   319  			status:         entities.StopOrderStatusUnspecified,
   320  			expiryStrategy: entities.StopOrderExpiryStrategyCancels,
   321  		},
   322  		{ // 7
   323  			orderID:        orderIDs[7],
   324  			vegaTime:       blocks[0].VegaTime,
   325  			createdAt:      blocks[0].VegaTime,
   326  			triggerPrice:   "100",
   327  			partyID:        parties[1].ID,
   328  			marketID:       markets[7].ID,
   329  			status:         entities.StopOrderStatusUnspecified,
   330  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   331  		},
   332  		{ // 8
   333  			orderID:        orderIDs[8],
   334  			vegaTime:       blocks[0].VegaTime,
   335  			createdAt:      blocks[0].VegaTime,
   336  			triggerPrice:   "100",
   337  			partyID:        parties[2].ID,
   338  			marketID:       markets[8].ID,
   339  			status:         entities.StopOrderStatusUnspecified,
   340  			expiryStrategy: entities.StopOrderExpiryStrategyCancels,
   341  		},
   342  		{ // 9
   343  			orderID:        orderIDs[9],
   344  			vegaTime:       blocks[0].VegaTime,
   345  			createdAt:      blocks[0].VegaTime,
   346  			triggerPrice:   "100",
   347  			partyID:        parties[1].ID,
   348  			marketID:       markets[9].ID,
   349  			status:         entities.StopOrderStatusUnspecified,
   350  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   351  		},
   352  		// block 2
   353  		{ // 10
   354  			orderID:        orderIDs[0],
   355  			vegaTime:       blocks[1].VegaTime,
   356  			createdAt:      blocks[0].VegaTime,
   357  			triggerPrice:   "100",
   358  			partyID:        parties[0].ID,
   359  			marketID:       markets[0].ID,
   360  			status:         entities.StopOrderStatusPending,
   361  			expiryStrategy: entities.StopOrderExpiryStrategyUnspecified,
   362  		},
   363  		{ // 11
   364  			orderID:        orderIDs[2],
   365  			vegaTime:       blocks[1].VegaTime,
   366  			createdAt:      blocks[0].VegaTime,
   367  			triggerPrice:   "100",
   368  			partyID:        parties[2].ID,
   369  			marketID:       markets[2].ID,
   370  			status:         entities.StopOrderStatusPending,
   371  			expiryStrategy: entities.StopOrderExpiryStrategyCancels,
   372  		},
   373  		{ // 12
   374  			orderID:        orderIDs[3],
   375  			vegaTime:       blocks[1].VegaTime,
   376  			createdAt:      blocks[0].VegaTime,
   377  			triggerPrice:   "100",
   378  			partyID:        parties[1].ID,
   379  			marketID:       markets[3].ID,
   380  			status:         entities.StopOrderStatusPending,
   381  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   382  		},
   383  		{ // 13
   384  			orderID:        orderIDs[4],
   385  			vegaTime:       blocks[1].VegaTime,
   386  			createdAt:      blocks[0].VegaTime,
   387  			triggerPrice:   "100",
   388  			partyID:        parties[2].ID,
   389  			marketID:       markets[4].ID,
   390  			status:         entities.StopOrderStatusPending,
   391  			expiryStrategy: entities.StopOrderExpiryStrategyCancels,
   392  		},
   393  		{ // 14
   394  			orderID:        orderIDs[6],
   395  			vegaTime:       blocks[1].VegaTime,
   396  			createdAt:      blocks[0].VegaTime,
   397  			triggerPrice:   "100",
   398  			partyID:        parties[2].ID,
   399  			marketID:       markets[6].ID,
   400  			status:         entities.StopOrderStatusPending,
   401  			expiryStrategy: entities.StopOrderExpiryStrategyCancels,
   402  		},
   403  		{ // 15
   404  			orderID:        orderIDs[7],
   405  			vegaTime:       blocks[1].VegaTime,
   406  			createdAt:      blocks[0].VegaTime,
   407  			triggerPrice:   "100",
   408  			partyID:        parties[1].ID,
   409  			marketID:       markets[7].ID,
   410  			status:         entities.StopOrderStatusPending,
   411  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   412  		},
   413  		// block 3
   414  		{ // 16
   415  			orderID:        orderIDs[0],
   416  			vegaTime:       blocks[2].VegaTime,
   417  			createdAt:      blocks[0].VegaTime,
   418  			triggerPrice:   "100",
   419  			partyID:        parties[0].ID,
   420  			marketID:       markets[0].ID,
   421  			status:         entities.StopOrderStatusCancelled,
   422  			expiryStrategy: entities.StopOrderExpiryStrategyUnspecified,
   423  		},
   424  		{ // 17
   425  			orderID:        orderIDs[1],
   426  			vegaTime:       blocks[2].VegaTime,
   427  			createdAt:      blocks[0].VegaTime,
   428  			triggerPrice:   "100",
   429  			partyID:        parties[1].ID,
   430  			marketID:       markets[1].ID,
   431  			status:         entities.StopOrderStatusPending,
   432  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   433  		},
   434  		{ // 18
   435  			orderID:        orderIDs[5],
   436  			vegaTime:       blocks[2].VegaTime,
   437  			createdAt:      blocks[0].VegaTime,
   438  			triggerPrice:   "100",
   439  			partyID:        parties[1].ID,
   440  			marketID:       markets[5].ID,
   441  			status:         entities.StopOrderStatusPending,
   442  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   443  		},
   444  		{ // 19
   445  			orderID:        orderIDs[8],
   446  			vegaTime:       blocks[2].VegaTime,
   447  			createdAt:      blocks[0].VegaTime,
   448  			triggerPrice:   "100",
   449  			partyID:        parties[2].ID,
   450  			marketID:       markets[8].ID,
   451  			status:         entities.StopOrderStatusPending,
   452  			expiryStrategy: entities.StopOrderExpiryStrategyCancels,
   453  		},
   454  		{ // 20
   455  			orderID:        orderIDs[9],
   456  			vegaTime:       blocks[2].VegaTime,
   457  			createdAt:      blocks[0].VegaTime,
   458  			triggerPrice:   "100",
   459  			partyID:        parties[1].ID,
   460  			marketID:       markets[9].ID,
   461  			status:         entities.StopOrderStatusPending,
   462  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   463  		},
   464  		// block 4
   465  		{ // 21
   466  			orderID:        orderIDs[1],
   467  			vegaTime:       blocks[3].VegaTime,
   468  			createdAt:      blocks[0].VegaTime,
   469  			triggerPrice:   "100",
   470  			partyID:        parties[1].ID,
   471  			marketID:       markets[1].ID,
   472  			status:         entities.StopOrderStatusExpired,
   473  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   474  		},
   475  		{ // 22
   476  			orderID:        orderIDs[2],
   477  			vegaTime:       blocks[3].VegaTime,
   478  			createdAt:      blocks[0].VegaTime,
   479  			triggerPrice:   "100",
   480  			partyID:        parties[2].ID,
   481  			marketID:       markets[2].ID,
   482  			status:         entities.StopOrderStatusExpired,
   483  			expiryStrategy: entities.StopOrderExpiryStrategyCancels,
   484  		},
   485  		{ // 23
   486  			orderID:        orderIDs[3],
   487  			vegaTime:       blocks[3].VegaTime,
   488  			createdAt:      blocks[0].VegaTime,
   489  			triggerPrice:   "100",
   490  			partyID:        parties[1].ID,
   491  			marketID:       markets[3].ID,
   492  			status:         entities.StopOrderStatusTriggered,
   493  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   494  		},
   495  		{ // 24
   496  			orderID:        orderIDs[6],
   497  			vegaTime:       blocks[3].VegaTime,
   498  			createdAt:      blocks[0].VegaTime,
   499  			triggerPrice:   "100",
   500  			partyID:        parties[2].ID,
   501  			marketID:       markets[6].ID,
   502  			status:         entities.StopOrderStatusCancelled,
   503  			expiryStrategy: entities.StopOrderExpiryStrategyCancels,
   504  		},
   505  		{ // 25
   506  			orderID:        orderIDs[7],
   507  			vegaTime:       blocks[3].VegaTime,
   508  			createdAt:      blocks[0].VegaTime,
   509  			triggerPrice:   "100",
   510  			partyID:        parties[1].ID,
   511  			marketID:       markets[7].ID,
   512  			status:         entities.StopOrderStatusTriggered,
   513  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   514  		},
   515  		// block 5
   516  		{ // 26
   517  			orderID:        orderIDs[4],
   518  			vegaTime:       blocks[4].VegaTime,
   519  			createdAt:      blocks[0].VegaTime,
   520  			triggerPrice:   "100",
   521  			partyID:        parties[2].ID,
   522  			marketID:       markets[4].ID,
   523  			status:         entities.StopOrderStatusTriggered,
   524  			expiryStrategy: entities.StopOrderExpiryStrategyCancels,
   525  		},
   526  		{ // 27
   527  			orderID:        orderIDs[5],
   528  			vegaTime:       blocks[4].VegaTime,
   529  			createdAt:      blocks[0].VegaTime,
   530  			triggerPrice:   "100",
   531  			partyID:        parties[1].ID,
   532  			marketID:       markets[5].ID,
   533  			status:         entities.StopOrderStatusCancelled,
   534  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   535  		},
   536  		{ // 28
   537  			orderID:        orderIDs[8],
   538  			vegaTime:       blocks[4].VegaTime,
   539  			createdAt:      blocks[0].VegaTime,
   540  			triggerPrice:   "100",
   541  			partyID:        parties[2].ID,
   542  			marketID:       markets[8].ID,
   543  			status:         entities.StopOrderStatusStopped,
   544  			expiryStrategy: entities.StopOrderExpiryStrategyCancels,
   545  		},
   546  		{ // 29
   547  			orderID:        orderIDs[9],
   548  			vegaTime:       blocks[4].VegaTime,
   549  			createdAt:      blocks[0].VegaTime,
   550  			triggerPrice:   "100",
   551  			partyID:        parties[1].ID,
   552  			marketID:       markets[9].ID,
   553  			status:         entities.StopOrderStatusStopped,
   554  			expiryStrategy: entities.StopOrderExpiryStrategySubmit,
   555  		},
   556  		{ // 30
   557  			orderID:        orderIDs[10],
   558  			vegaTime:       blocks[4].VegaTime,
   559  			createdAt:      blocks[0].VegaTime,
   560  			triggerPrice:   "100",
   561  			partyID:        parties[3].ID,
   562  			marketID:       markets[8].ID,
   563  			status:         entities.StopOrderStatusPending,
   564  			expiryStrategy: entities.StopOrderExpiryStrategyCancels,
   565  		},
   566  		{ // 31
   567  			orderID:        orderIDs[11],
   568  			vegaTime:       blocks[5].VegaTime,
   569  			createdAt:      blocks[0].VegaTime,
   570  			triggerPrice:   "100",
   571  			partyID:        parties[3].ID,
   572  			marketID:       markets[9].ID,
   573  			status:         entities.StopOrderStatusPending,
   574  			expiryStrategy: entities.StopOrderExpiryStrategyCancels,
   575  		},
   576  	})
   577  
   578  	for _, o := range stopOrders {
   579  		require.NoError(t, so.Add(o))
   580  	}
   581  
   582  	saved, err := so.Flush(ctx)
   583  	require.NoError(t, err)
   584  	require.ElementsMatch(t, stopOrders, saved)
   585  
   586  	t.Run("should return an error if oldest first order is requested in pagination", func(t *testing.T) {
   587  		filter := entities.StopOrderFilter{}
   588  		p := entities.CursorPagination{}
   589  
   590  		_, _, err := so.ListStopOrders(ctx, filter, p)
   591  		require.Error(t, err)
   592  		assert.EqualError(t, err, "oldest first order query is not currently supported")
   593  	})
   594  
   595  	t.Run("should list the latest version of each stop order", func(t *testing.T) {
   596  		want := []entities.StopOrder{
   597  			stopOrders[29],
   598  			stopOrders[28],
   599  			stopOrders[25],
   600  			stopOrders[24],
   601  			stopOrders[27],
   602  			stopOrders[26],
   603  			stopOrders[23],
   604  			stopOrders[22],
   605  			stopOrders[21],
   606  			stopOrders[16],
   607  			stopOrders[30],
   608  			stopOrders[31],
   609  		}
   610  
   611  		sort.Slice(want, func(i, j int) bool {
   612  			return want[i].ID < want[j].ID
   613  		})
   614  
   615  		filter := entities.StopOrderFilter{}
   616  		p := entities.CursorPagination{
   617  			NewestFirst: true,
   618  		}
   619  
   620  		got, pageInfo, err := so.ListStopOrders(ctx, filter, p)
   621  		require.NoError(t, err)
   622  		assert.Equal(t, want, got)
   623  		assert.Equal(t, entities.PageInfo{
   624  			HasNextPage:     false,
   625  			HasPreviousPage: false,
   626  			StartCursor:     want[0].Cursor().Encode(),
   627  			EndCursor:       want[len(want)-1].Cursor().Encode(),
   628  		}, pageInfo)
   629  	})
   630  
   631  	t.Run("should paginate the data correctly", func(t *testing.T) {
   632  		current := []entities.StopOrder{
   633  			stopOrders[31],
   634  			stopOrders[30],
   635  			stopOrders[29],
   636  			stopOrders[28],
   637  			stopOrders[25],
   638  			stopOrders[24],
   639  			stopOrders[27],
   640  			stopOrders[26],
   641  			stopOrders[23],
   642  			stopOrders[22],
   643  			stopOrders[21],
   644  			stopOrders[16],
   645  		}
   646  
   647  		sort.Slice(current, func(i, j int) bool {
   648  			return current[i].ID < current[j].ID
   649  		})
   650  
   651  		filter := entities.StopOrderFilter{}
   652  		first := int32(3)
   653  		currentIndex := -1
   654  
   655  		for {
   656  			var (
   657  				p                    entities.CursorPagination
   658  				err                  error
   659  				hasNext, hasPrevious bool
   660  				want                 []entities.StopOrder
   661  			)
   662  
   663  			if currentIndex > -1 {
   664  				p, err = entities.NewCursorPagination(&first, ptr.From(current[currentIndex].Cursor().Encode()), nil, nil, true)
   665  				require.NoError(t, err)
   666  				hasNext = (currentIndex + int(first)) < len(current)-1
   667  				hasPrevious = true
   668  			} else {
   669  				p, err = entities.NewCursorPagination(&first, nil, nil, nil, true)
   670  				require.NoError(t, err)
   671  				hasNext = true
   672  				hasPrevious = false
   673  			}
   674  
   675  			wantStart := currentIndex + 1
   676  			wantEnd := wantStart + int(first)
   677  
   678  			if wantEnd > len(current) {
   679  				wantEnd = len(current)
   680  			}
   681  
   682  			want = current[wantStart:wantEnd]
   683  
   684  			got, pageInfo, err := so.ListStopOrders(ctx, filter, p)
   685  			require.NoError(t, err)
   686  			assert.Equal(t, want, got)
   687  			assert.Equal(t, entities.PageInfo{
   688  				HasNextPage:     hasNext,
   689  				HasPreviousPage: hasPrevious,
   690  				StartCursor:     want[0].Cursor().Encode(),
   691  				EndCursor:       want[len(want)-1].Cursor().Encode(),
   692  			}, pageInfo)
   693  
   694  			currentIndex += len(got)
   695  			if currentIndex >= len(current)-1 {
   696  				break
   697  			}
   698  		}
   699  	})
   700  
   701  	t.Run("should filter orders", func(tt *testing.T) {
   702  		tt.Run("by party", func(ts *testing.T) {
   703  			filter := entities.StopOrderFilter{
   704  				PartyIDs: []string{
   705  					parties[0].ID.String(),
   706  					parties[1].ID.String(),
   707  				},
   708  			}
   709  
   710  			want := []entities.StopOrder{
   711  				stopOrders[29],
   712  				stopOrders[25],
   713  				stopOrders[27],
   714  				stopOrders[23],
   715  				stopOrders[21],
   716  				stopOrders[16],
   717  			}
   718  			sort.Slice(want, func(i, j int) bool {
   719  				if want[i].PartyID == want[j].PartyID {
   720  					return want[i].ID < want[j].ID
   721  				}
   722  				return want[i].PartyID < want[j].PartyID
   723  			})
   724  
   725  			p, err := entities.NewCursorPagination(nil, nil, nil, nil, true)
   726  			require.NoError(ts, err)
   727  
   728  			got, pageInfo, err := so.ListStopOrders(ctx, filter, p)
   729  			require.NoError(ts, err)
   730  			assert.Equal(ts, want, got)
   731  			assert.Equal(ts, entities.PageInfo{
   732  				HasNextPage:     false,
   733  				HasPreviousPage: false,
   734  				StartCursor:     want[0].Cursor().Encode(),
   735  				EndCursor:       want[len(want)-1].Cursor().Encode(),
   736  			}, pageInfo)
   737  		})
   738  
   739  		tt.Run("by market", func(ts *testing.T) {
   740  			filter := entities.StopOrderFilter{
   741  				MarketIDs: []string{
   742  					markets[0].ID.String(),
   743  					markets[1].ID.String(),
   744  					markets[3].ID.String(),
   745  					markets[6].ID.String(),
   746  					markets[7].ID.String(),
   747  					markets[8].ID.String(),
   748  				},
   749  			}
   750  
   751  			want := []entities.StopOrder{
   752  				stopOrders[30],
   753  				stopOrders[28],
   754  				stopOrders[25],
   755  				stopOrders[24],
   756  				stopOrders[23],
   757  				stopOrders[21],
   758  				stopOrders[16],
   759  			}
   760  			sort.Slice(want, func(i, j int) bool {
   761  				if want[i].MarketID == want[j].MarketID {
   762  					return want[i].ID < want[j].ID
   763  				}
   764  				return want[i].MarketID < want[j].MarketID
   765  			})
   766  
   767  			p, err := entities.NewCursorPagination(nil, nil, nil, nil, true)
   768  			require.NoError(ts, err)
   769  
   770  			got, pageInfo, err := so.ListStopOrders(ctx, filter, p)
   771  			require.NoError(ts, err)
   772  			assert.Equal(ts, want, got)
   773  			assert.Equal(ts, entities.PageInfo{
   774  				HasNextPage:     false,
   775  				HasPreviousPage: false,
   776  				StartCursor:     want[0].Cursor().Encode(),
   777  				EndCursor:       want[len(want)-1].Cursor().Encode(),
   778  			}, pageInfo)
   779  		})
   780  
   781  		tt.Run("by party and market", func(ts *testing.T) {
   782  			filter := entities.StopOrderFilter{
   783  				PartyIDs: []string{
   784  					parties[1].ID.String(),
   785  					parties[2].ID.String(),
   786  				},
   787  				MarketIDs: []string{
   788  					markets[1].ID.String(),
   789  					markets[3].ID.String(),
   790  					markets[6].ID.String(),
   791  					markets[7].ID.String(),
   792  					markets[8].ID.String(),
   793  				},
   794  			}
   795  
   796  			want := []entities.StopOrder{
   797  				stopOrders[28],
   798  				stopOrders[25],
   799  				stopOrders[24],
   800  				stopOrders[23],
   801  				stopOrders[21],
   802  			}
   803  			sort.Slice(want, func(i, j int) bool {
   804  				if want[i].PartyID == want[j].PartyID {
   805  					return want[i].ID < want[j].ID
   806  				}
   807  				return want[i].PartyID < want[j].PartyID
   808  			})
   809  
   810  			p, err := entities.NewCursorPagination(nil, nil, nil, nil, true)
   811  			require.NoError(ts, err)
   812  
   813  			got, pageInfo, err := so.ListStopOrders(ctx, filter, p)
   814  			require.NoError(ts, err)
   815  			assert.Equal(ts, want, got)
   816  			assert.Equal(ts, entities.PageInfo{
   817  				HasNextPage:     false,
   818  				HasPreviousPage: false,
   819  				StartCursor:     want[0].Cursor().Encode(),
   820  				EndCursor:       want[len(want)-1].Cursor().Encode(),
   821  			}, pageInfo)
   822  		})
   823  
   824  		tt.Run("by status", func(ts *testing.T) {
   825  			filter := entities.StopOrderFilter{
   826  				Statuses: []entities.StopOrderStatus{
   827  					entities.StopOrderStatusCancelled,
   828  					entities.StopOrderStatusTriggered,
   829  					entities.StopOrderStatusExpired,
   830  				},
   831  			}
   832  
   833  			want := []entities.StopOrder{
   834  				stopOrders[27],
   835  				stopOrders[26],
   836  				stopOrders[25],
   837  				stopOrders[24],
   838  				stopOrders[23],
   839  				stopOrders[22],
   840  				stopOrders[21],
   841  				stopOrders[16],
   842  			}
   843  			sort.Slice(want, func(i, j int) bool {
   844  				return want[i].ID < want[j].ID
   845  			})
   846  
   847  			p, err := entities.NewCursorPagination(nil, nil, nil, nil, true)
   848  			require.NoError(ts, err)
   849  
   850  			got, pageInfo, err := so.ListStopOrders(ctx, filter, p)
   851  			require.NoError(ts, err)
   852  			assert.Equal(ts, want, got)
   853  			assert.Equal(ts, entities.PageInfo{
   854  				HasNextPage:     false,
   855  				HasPreviousPage: false,
   856  				StartCursor:     want[0].Cursor().Encode(),
   857  				EndCursor:       want[len(want)-1].Cursor().Encode(),
   858  			}, pageInfo)
   859  		})
   860  
   861  		tt.Run("by trigger strategy", func(ts *testing.T) {
   862  			filter := entities.StopOrderFilter{
   863  				ExpiryStrategy: []entities.StopOrderExpiryStrategy{
   864  					entities.StopOrderExpiryStrategyUnspecified,
   865  					entities.StopOrderExpiryStrategyCancels,
   866  				},
   867  			}
   868  
   869  			want := []entities.StopOrder{
   870  				stopOrders[31],
   871  				stopOrders[30],
   872  				stopOrders[28],
   873  				stopOrders[26],
   874  				stopOrders[24],
   875  				stopOrders[22],
   876  				stopOrders[16],
   877  			}
   878  
   879  			sort.Slice(want, func(i, j int) bool {
   880  				return want[i].ID < want[j].ID
   881  			})
   882  
   883  			p, err := entities.NewCursorPagination(nil, nil, nil, nil, true)
   884  			require.NoError(ts, err)
   885  
   886  			got, pageInfo, err := so.ListStopOrders(ctx, filter, p)
   887  			require.NoError(ts, err)
   888  			assert.Equal(ts, want, got)
   889  			assert.Equal(ts, entities.PageInfo{
   890  				HasNextPage:     false,
   891  				HasPreviousPage: false,
   892  				StartCursor:     want[0].Cursor().Encode(),
   893  				EndCursor:       want[len(want)-1].Cursor().Encode(),
   894  			}, pageInfo)
   895  		})
   896  
   897  		tt.Run("by party and status", func(ts *testing.T) {
   898  			filter := entities.StopOrderFilter{
   899  				PartyIDs: []string{
   900  					parties[1].ID.String(),
   901  				},
   902  				Statuses: []entities.StopOrderStatus{
   903  					entities.StopOrderStatusTriggered,
   904  					entities.StopOrderStatusExpired,
   905  				},
   906  			}
   907  
   908  			want := []entities.StopOrder{
   909  				stopOrders[25],
   910  				stopOrders[23],
   911  				stopOrders[21],
   912  			}
   913  			sort.Slice(want, func(i, j int) bool {
   914  				if want[i].PartyID == want[j].PartyID {
   915  					return want[i].ID < want[j].ID
   916  				}
   917  				return want[i].PartyID < want[j].PartyID
   918  			})
   919  			p, err := entities.NewCursorPagination(nil, nil, nil, nil, true)
   920  			require.NoError(ts, err)
   921  
   922  			got, pageInfo, err := so.ListStopOrders(ctx, filter, p)
   923  			require.NoError(ts, err)
   924  			assert.Equal(ts, want, got)
   925  			assert.Equal(ts, entities.PageInfo{
   926  				HasNextPage:     false,
   927  				HasPreviousPage: false,
   928  				StartCursor:     want[0].Cursor().Encode(),
   929  				EndCursor:       want[len(want)-1].Cursor().Encode(),
   930  			}, pageInfo)
   931  		})
   932  
   933  		tt.Run("by market and trigger strategy", func(ts *testing.T) {
   934  			filter := entities.StopOrderFilter{
   935  				MarketIDs: []string{
   936  					markets[0].ID.String(),
   937  					markets[1].ID.String(),
   938  					markets[3].ID.String(),
   939  					markets[6].ID.String(),
   940  					markets[7].ID.String(),
   941  					markets[8].ID.String(),
   942  				},
   943  				ExpiryStrategy: []entities.StopOrderExpiryStrategy{
   944  					entities.StopOrderExpiryStrategyCancels,
   945  				},
   946  			}
   947  
   948  			want := []entities.StopOrder{
   949  				stopOrders[30],
   950  				stopOrders[28],
   951  				stopOrders[24],
   952  			}
   953  			sort.Slice(want, func(i, j int) bool {
   954  				if want[i].MarketID == want[j].MarketID {
   955  					return want[i].ID < want[j].ID
   956  				}
   957  				return want[i].MarketID < want[j].MarketID
   958  			})
   959  
   960  			p, err := entities.NewCursorPagination(nil, nil, nil, nil, true)
   961  			require.NoError(ts, err)
   962  
   963  			got, pageInfo, err := so.ListStopOrders(ctx, filter, p)
   964  			require.NoError(ts, err)
   965  			assert.Equal(ts, want, got)
   966  			assert.Equal(ts, entities.PageInfo{
   967  				HasNextPage:     false,
   968  				HasPreviousPage: false,
   969  				StartCursor:     want[0].Cursor().Encode(),
   970  				EndCursor:       want[len(want)-1].Cursor().Encode(),
   971  			}, pageInfo)
   972  		})
   973  
   974  		tt.Run("live only", func(ts *testing.T) {
   975  			filter := entities.StopOrderFilter{
   976  				LiveOnly: true,
   977  			}
   978  
   979  			want := []entities.StopOrder{
   980  				stopOrders[31],
   981  				stopOrders[30],
   982  			}
   983  			sort.Slice(want, func(i, j int) bool {
   984  				return want[i].ID < want[j].ID
   985  			})
   986  			p, err := entities.NewCursorPagination(nil, nil, nil, nil, true)
   987  			require.NoError(ts, err)
   988  			got, pageInfo, err := so.ListStopOrders(ctx, filter, p)
   989  			require.NoError(ts, err)
   990  
   991  			assert.Equal(ts, want, got)
   992  			assert.Equal(ts, entities.PageInfo{
   993  				HasNextPage:     false,
   994  				HasPreviousPage: false,
   995  				StartCursor:     want[0].Cursor().Encode(),
   996  				EndCursor:       want[1].Cursor().Encode(),
   997  			}, pageInfo)
   998  		})
   999  	})
  1000  }
  1001  
  1002  func TestStopOrderEnums(t *testing.T) {
  1003  	t.Run("Should write and retrieve all values of expiry strategy", testStopOrderExpiryStrategyEnum)
  1004  	t.Run("Should write and retrieve all values of rejection reason", testStopOrderExpiryRejectionReason)
  1005  	t.Run("Should write and retrieve all values of status", testStopOrderExpiryStatus)
  1006  	t.Run("Should write and retrieve all values of trigger direction", testStopOrderTriggerDirection)
  1007  }
  1008  
  1009  func testStopOrderTriggerDirection(t *testing.T) {
  1010  	var stopOrderTriggerDirection vegapb.StopOrder_TriggerDirection
  1011  	directions := getEnums(t, stopOrderTriggerDirection)
  1012  	assert.Len(t, directions, 3)
  1013  	for d, direction := range directions {
  1014  		t.Run(direction, func(t *testing.T) {
  1015  			ctx := tempTransaction(t)
  1016  			so := sqlstore.NewStopOrders(connectionSource)
  1017  			bs := sqlstore.NewBlocks(connectionSource)
  1018  			ps := sqlstore.NewParties(connectionSource)
  1019  			ms := sqlstore.NewMarkets(connectionSource)
  1020  
  1021  			block := addTestBlock(t, ctx, bs)
  1022  			party := addTestParty(t, ctx, ps, block)
  1023  			markets := helpers.GenerateMarkets(t, ctx, 1, block, ms)
  1024  
  1025  			o := entities.StopOrder{
  1026  				ID:               entities.StopOrderID(GenerateID()),
  1027  				ExpiryStrategy:   entities.StopOrderExpiryStrategySubmit,
  1028  				TriggerDirection: entities.StopOrderTriggerDirection(d),
  1029  				Status:           entities.StopOrderStatusPending,
  1030  				CreatedAt:        block.VegaTime,
  1031  				UpdatedAt:        nil,
  1032  				OrderID:          "",
  1033  				TriggerPrice:     ptr.From("100"),
  1034  				PartyID:          party.ID,
  1035  				MarketID:         markets[0].ID,
  1036  				VegaTime:         block.VegaTime,
  1037  				SeqNum:           1,
  1038  				TxHash:           generateTxHash(),
  1039  				Submission: &commandspb.OrderSubmission{
  1040  					MarketId:    markets[0].ID.String(),
  1041  					Price:       "100",
  1042  					Size:        uint64(100),
  1043  					Side:        entities.SideBuy,
  1044  					TimeInForce: entities.OrderTimeInForceUnspecified,
  1045  					ExpiresAt:   0,
  1046  					Type:        entities.OrderTypeMarket,
  1047  					Reference:   GenerateID(),
  1048  				},
  1049  				RejectionReason: entities.StopOrderRejectionReasonUnspecified,
  1050  			}
  1051  
  1052  			require.NoError(t, so.Add(o))
  1053  			_, err := so.Flush(ctx)
  1054  			require.NoError(t, err)
  1055  			got, err := so.GetStopOrder(ctx, o.ID.String())
  1056  			require.NoError(t, err)
  1057  			assert.Equal(t, o.TriggerDirection, got.TriggerDirection)
  1058  		})
  1059  	}
  1060  }
  1061  
  1062  func testStopOrderExpiryStatus(t *testing.T) {
  1063  	var stopOrderStatus vegapb.StopOrder_Status
  1064  	states := getEnums(t, stopOrderStatus)
  1065  	assert.Len(t, states, 7)
  1066  	for e, state := range states {
  1067  		t.Run(state, func(t *testing.T) {
  1068  			ctx := tempTransaction(t)
  1069  			so := sqlstore.NewStopOrders(connectionSource)
  1070  			bs := sqlstore.NewBlocks(connectionSource)
  1071  			ps := sqlstore.NewParties(connectionSource)
  1072  			ms := sqlstore.NewMarkets(connectionSource)
  1073  
  1074  			block := addTestBlock(t, ctx, bs)
  1075  			party := addTestParty(t, ctx, ps, block)
  1076  			markets := helpers.GenerateMarkets(t, ctx, 1, block, ms)
  1077  
  1078  			o := entities.StopOrder{
  1079  				ID:               entities.StopOrderID(GenerateID()),
  1080  				ExpiryStrategy:   entities.StopOrderExpiryStrategySubmit,
  1081  				TriggerDirection: entities.StopOrderTriggerDirectionRisesAbove,
  1082  				Status:           entities.StopOrderStatus(e),
  1083  				CreatedAt:        block.VegaTime,
  1084  				UpdatedAt:        nil,
  1085  				OrderID:          "",
  1086  				TriggerPrice:     ptr.From("100"),
  1087  				PartyID:          party.ID,
  1088  				MarketID:         markets[0].ID,
  1089  				VegaTime:         block.VegaTime,
  1090  				SeqNum:           1,
  1091  				TxHash:           generateTxHash(),
  1092  				Submission: &commandspb.OrderSubmission{
  1093  					MarketId:    markets[0].ID.String(),
  1094  					Price:       "100",
  1095  					Size:        uint64(100),
  1096  					Side:        entities.SideBuy,
  1097  					TimeInForce: entities.OrderTimeInForceUnspecified,
  1098  					ExpiresAt:   0,
  1099  					Type:        entities.OrderTypeMarket,
  1100  					Reference:   GenerateID(),
  1101  				},
  1102  				RejectionReason: entities.StopOrderRejectionReasonUnspecified,
  1103  			}
  1104  
  1105  			require.NoError(t, so.Add(o))
  1106  			_, err := so.Flush(ctx)
  1107  			require.NoError(t, err)
  1108  			got, err := so.GetStopOrder(ctx, o.ID.String())
  1109  			require.NoError(t, err)
  1110  			assert.Equal(t, o.Status, got.Status)
  1111  		})
  1112  	}
  1113  }
  1114  
  1115  func testStopOrderExpiryRejectionReason(t *testing.T) {
  1116  	var stopOrderRejectionReason vegapb.StopOrder_RejectionReason
  1117  	reasons := getEnums(t, stopOrderRejectionReason)
  1118  	assert.Len(t, reasons, 12)
  1119  	for r, reason := range reasons {
  1120  		t.Run(reason, func(t *testing.T) {
  1121  			ctx := tempTransaction(t)
  1122  			so := sqlstore.NewStopOrders(connectionSource)
  1123  			bs := sqlstore.NewBlocks(connectionSource)
  1124  			ps := sqlstore.NewParties(connectionSource)
  1125  			ms := sqlstore.NewMarkets(connectionSource)
  1126  
  1127  			block := addTestBlock(t, ctx, bs)
  1128  			party := addTestParty(t, ctx, ps, block)
  1129  			markets := helpers.GenerateMarkets(t, ctx, 1, block, ms)
  1130  
  1131  			o := entities.StopOrder{
  1132  				ID:               entities.StopOrderID(GenerateID()),
  1133  				ExpiryStrategy:   entities.StopOrderExpiryStrategySubmit,
  1134  				TriggerDirection: entities.StopOrderTriggerDirectionRisesAbove,
  1135  				Status:           entities.StopOrderStatusPending,
  1136  				CreatedAt:        block.VegaTime,
  1137  				UpdatedAt:        nil,
  1138  				OrderID:          "",
  1139  				TriggerPrice:     ptr.From("100"),
  1140  				PartyID:          party.ID,
  1141  				MarketID:         markets[0].ID,
  1142  				VegaTime:         block.VegaTime,
  1143  				SeqNum:           1,
  1144  				TxHash:           generateTxHash(),
  1145  				Submission: &commandspb.OrderSubmission{
  1146  					MarketId:    markets[0].ID.String(),
  1147  					Price:       "100",
  1148  					Size:        uint64(100),
  1149  					Side:        entities.SideBuy,
  1150  					TimeInForce: entities.OrderTimeInForceUnspecified,
  1151  					ExpiresAt:   0,
  1152  					Type:        entities.OrderTypeMarket,
  1153  					Reference:   GenerateID(),
  1154  				},
  1155  				RejectionReason: entities.StopOrderRejectionReason(r),
  1156  			}
  1157  
  1158  			require.NoError(t, so.Add(o))
  1159  			_, err := so.Flush(ctx)
  1160  			require.NoError(t, err)
  1161  			got, err := so.GetStopOrder(ctx, o.ID.String())
  1162  			require.NoError(t, err)
  1163  			assert.Equal(t, o.RejectionReason, got.RejectionReason)
  1164  		})
  1165  	}
  1166  }
  1167  
  1168  func testStopOrderExpiryStrategyEnum(t *testing.T) {
  1169  	var stopOrderExpiryStrategy vegapb.StopOrder_ExpiryStrategy
  1170  	strategies := getEnums(t, stopOrderExpiryStrategy)
  1171  	assert.Len(t, strategies, 3)
  1172  	for s, strategy := range strategies {
  1173  		t.Run(strategy, func(t *testing.T) {
  1174  			ctx := tempTransaction(t)
  1175  			so := sqlstore.NewStopOrders(connectionSource)
  1176  			bs := sqlstore.NewBlocks(connectionSource)
  1177  			ps := sqlstore.NewParties(connectionSource)
  1178  			ms := sqlstore.NewMarkets(connectionSource)
  1179  
  1180  			block := addTestBlock(t, ctx, bs)
  1181  			party := addTestParty(t, ctx, ps, block)
  1182  			markets := helpers.GenerateMarkets(t, ctx, 1, block, ms)
  1183  
  1184  			o := entities.StopOrder{
  1185  				ID:               entities.StopOrderID(GenerateID()),
  1186  				ExpiryStrategy:   entities.StopOrderExpiryStrategy(s),
  1187  				TriggerDirection: entities.StopOrderTriggerDirectionRisesAbove,
  1188  				Status:           entities.StopOrderStatusPending,
  1189  				CreatedAt:        block.VegaTime,
  1190  				UpdatedAt:        nil,
  1191  				OrderID:          "",
  1192  				TriggerPrice:     ptr.From("100"),
  1193  				PartyID:          party.ID,
  1194  				MarketID:         markets[0].ID,
  1195  				VegaTime:         block.VegaTime,
  1196  				SeqNum:           1,
  1197  				TxHash:           generateTxHash(),
  1198  				Submission: &commandspb.OrderSubmission{
  1199  					MarketId:    markets[0].ID.String(),
  1200  					Price:       "100",
  1201  					Size:        uint64(100),
  1202  					Side:        entities.SideBuy,
  1203  					TimeInForce: entities.OrderTimeInForceUnspecified,
  1204  					ExpiresAt:   0,
  1205  					Type:        entities.OrderTypeMarket,
  1206  					Reference:   GenerateID(),
  1207  				},
  1208  				RejectionReason: entities.StopOrderRejectionReasonUnspecified,
  1209  			}
  1210  
  1211  			require.NoError(t, so.Add(o))
  1212  			_, err := so.Flush(ctx)
  1213  			require.NoError(t, err)
  1214  			got, err := so.GetStopOrder(ctx, o.ID.String())
  1215  			require.NoError(t, err)
  1216  			assert.Equal(t, o.ExpiryStrategy, got.ExpiryStrategy)
  1217  		})
  1218  	}
  1219  }