code.vegaprotocol.io/vega@v0.79.0/core/execution/update_market_state_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 execution_test
    17  
    18  import (
    19  	"context"
    20  	"encoding/hex"
    21  	"fmt"
    22  	"testing"
    23  	"time"
    24  
    25  	dstypes "code.vegaprotocol.io/vega/core/datasource/common"
    26  	"code.vegaprotocol.io/vega/core/execution"
    27  	"code.vegaprotocol.io/vega/core/types"
    28  	vgcontext "code.vegaprotocol.io/vega/libs/context"
    29  	"code.vegaprotocol.io/vega/libs/num"
    30  	vgtest "code.vegaprotocol.io/vega/libs/test"
    31  	paths2 "code.vegaprotocol.io/vega/paths"
    32  
    33  	"github.com/stretchr/testify/require"
    34  )
    35  
    36  func TestVerifyUpdateMarketState(t *testing.T) {
    37  	now := time.Now()
    38  	exec := getEngine(t, paths2.New(t.TempDir()), now)
    39  	pubKey := &dstypes.SignerPubKey{
    40  		PubKey: &dstypes.PubKey{
    41  			Key: "0xDEADBEEF",
    42  		},
    43  	}
    44  	mkt := newMarket("MarketID", pubKey)
    45  	err := exec.engine.SubmitMarket(context.Background(), mkt, "", time.Now())
    46  	require.NoError(t, err)
    47  
    48  	config := &types.MarketStateUpdateConfiguration{
    49  		MarketID:   "wrong",
    50  		UpdateType: types.MarketStateUpdateTypeTerminate,
    51  	}
    52  
    53  	require.Equal(t, execution.ErrMarketDoesNotExist, exec.engine.VerifyUpdateMarketState(config))
    54  
    55  	config.MarketID = mkt.ID
    56  	require.Equal(t, fmt.Errorf("missing settlement price for governance initiated futures market termination"), exec.engine.VerifyUpdateMarketState(config))
    57  }
    58  
    59  func TestTerminateMarketViaGovernance(t *testing.T) {
    60  	ctx := vgtest.VegaContext("chainid", 100)
    61  
    62  	now := time.Now()
    63  	exec := getEngine(t, paths2.New(t.TempDir()), now)
    64  	pubKey := &dstypes.SignerPubKey{
    65  		PubKey: &dstypes.PubKey{
    66  			Key: "0xDEADBEEF",
    67  		},
    68  	}
    69  	mkt := newMarket("MarketID", pubKey)
    70  	err := exec.engine.SubmitMarket(context.Background(), mkt, "", time.Now())
    71  	require.NoError(t, err)
    72  
    73  	exec.engine.StartOpeningAuction(context.Background(), mkt.ID)
    74  
    75  	config := &types.MarketStateUpdateConfiguration{
    76  		MarketID:        mkt.ID,
    77  		UpdateType:      types.MarketStateUpdateTypeTerminate,
    78  		SettlementPrice: num.NewUint(100),
    79  	}
    80  	require.NoError(t, exec.engine.UpdateMarketState(ctx, config))
    81  	state, err := exec.engine.GetMarketState(mkt.ID)
    82  	require.NoError(t, err)
    83  	require.Equal(t, types.MarketStateClosed, state)
    84  }
    85  
    86  func TestSuspendMarketViaGovernance(t *testing.T) {
    87  	ctx := vgtest.VegaContext("chainid", 100)
    88  	now := time.Now()
    89  	exec := getEngine(t, paths2.New(t.TempDir()), now)
    90  	pubKey := &dstypes.SignerPubKey{
    91  		PubKey: &dstypes.PubKey{
    92  			Key: "0xDEADBEEF",
    93  		},
    94  	}
    95  	mkt := newMarket("MarketID", pubKey)
    96  	err := exec.engine.SubmitMarket(context.Background(), mkt, "", time.Now())
    97  	require.NoError(t, err)
    98  
    99  	exec.engine.StartOpeningAuction(context.Background(), mkt.ID)
   100  
   101  	// during opening auction
   102  	state, err := exec.engine.GetMarketData(mkt.ID)
   103  	require.NoError(t, err)
   104  	require.Equal(t, types.MarketStateActive, state.MarketState)
   105  	require.Equal(t, types.MarketTradingModeContinuous, state.MarketTradingMode)
   106  
   107  	config := &types.MarketStateUpdateConfiguration{
   108  		MarketID:        mkt.ID,
   109  		UpdateType:      types.MarketStateUpdateTypeSuspend,
   110  		SettlementPrice: num.NewUint(100),
   111  	}
   112  	require.NoError(t, exec.engine.UpdateMarketState(ctx, config))
   113  
   114  	// after governance suspension
   115  	state, err = exec.engine.GetMarketData(mkt.ID)
   116  	require.NoError(t, err)
   117  	require.Equal(t, types.MarketStateSuspendedViaGovernance, state.MarketState)
   118  	require.Equal(t, types.MarketTradingModeSuspendedViaGovernance, state.MarketTradingMode)
   119  
   120  	exec.engine.OnTick(ctx, exec.timeService.GetTimeNow())
   121  
   122  	config.UpdateType = types.MarketStateUpdateTypeResume
   123  	require.NoError(t, exec.engine.UpdateMarketState(ctx, config))
   124  
   125  	// after governance suspension ended - enter liquidity auction
   126  	state, err = exec.engine.GetMarketData(mkt.ID)
   127  	require.NoError(t, err)
   128  	require.Equal(t, types.MarketStateActive, state.MarketState)
   129  	require.Equal(t, types.MarketTradingModeContinuous, state.MarketTradingMode)
   130  
   131  	// now suspend via governance again
   132  	config.UpdateType = types.MarketStateUpdateTypeSuspend
   133  	require.NoError(t, exec.engine.UpdateMarketState(ctx, config))
   134  
   135  	exec.engine.OnTick(ctx, exec.timeService.GetTimeNow())
   136  
   137  	// after governance suspension
   138  	state, err = exec.engine.GetMarketData(mkt.ID)
   139  	require.NoError(t, err)
   140  	require.Equal(t, types.MarketStateSuspendedViaGovernance, state.MarketState)
   141  	// because we're in monitoring auction and the state here is taken from the auction state it is reported as monitoring auction
   142  	require.Equal(t, types.MarketTradingModeSuspendedViaGovernance, state.MarketTradingMode)
   143  
   144  	// release suspension should go back to liquidity auction
   145  	config.UpdateType = types.MarketStateUpdateTypeResume
   146  	require.NoError(t, exec.engine.UpdateMarketState(ctx, config))
   147  
   148  	exec.engine.OnTick(ctx, exec.timeService.GetTimeNow())
   149  
   150  	// after governance suspension ended - enter liquidity auction
   151  	state, err = exec.engine.GetMarketData(mkt.ID)
   152  	require.NoError(t, err)
   153  	require.Equal(t, types.MarketStateActive, state.MarketState)
   154  	require.Equal(t, types.MarketTradingModeContinuous, state.MarketTradingMode)
   155  }
   156  
   157  func TestSubmitOrderWhenSuspended(t *testing.T) {
   158  	ctx := vgtest.VegaContext("chainid", 100)
   159  	now := time.Now()
   160  	exec := getEngineWithParties(t, now, num.NewUint(1000000000), "lp", "p1", "p2", "p3", "p4")
   161  	pubKey := &dstypes.SignerPubKey{
   162  		PubKey: &dstypes.PubKey{
   163  			Key: "0xDEADBEEF",
   164  		},
   165  	}
   166  	mkt := newMarket("MarketID", pubKey)
   167  	err := exec.engine.SubmitMarket(context.Background(), mkt, "", now)
   168  	require.NoError(t, err)
   169  
   170  	exec.engine.StartOpeningAuction(context.Background(), mkt.ID)
   171  
   172  	// during opening auction
   173  	state, err := exec.engine.GetMarketData(mkt.ID)
   174  	require.NoError(t, err)
   175  	require.Equal(t, types.MarketStateActive, state.MarketState)
   176  	require.Equal(t, types.MarketTradingModeContinuous, state.MarketTradingMode)
   177  
   178  	config := &types.MarketStateUpdateConfiguration{
   179  		MarketID:        mkt.ID,
   180  		UpdateType:      types.MarketStateUpdateTypeSuspend,
   181  		SettlementPrice: num.NewUint(100),
   182  	}
   183  	require.NoError(t, exec.engine.UpdateMarketState(ctx, config))
   184  
   185  	// after governance suspension
   186  	state, err = exec.engine.GetMarketData(mkt.ID)
   187  	require.NoError(t, err)
   188  	require.Equal(t, types.MarketStateSuspendedViaGovernance, state.MarketState)
   189  	require.Equal(t, types.MarketTradingModeSuspendedViaGovernance, state.MarketTradingMode)
   190  
   191  	// check we can submit an order
   192  	os1 := &types.OrderSubmission{
   193  		MarketID:    mkt.ID,
   194  		Price:       num.NewUint(99),
   195  		Size:        1,
   196  		Side:        types.SideBuy,
   197  		TimeInForce: types.OrderTimeInForceGTC,
   198  		Type:        types.OrderTypeLimit,
   199  		Reference:   "o1",
   200  	}
   201  	idgen := &stubIDGen{}
   202  	vgctx := vgcontext.WithTraceID(context.Background(), hex.EncodeToString([]byte("0deadbeef")))
   203  	_, err = exec.engine.SubmitOrder(vgctx, os1, "p1", idgen, "o1p1")
   204  	require.NoError(t, err)
   205  }
   206  
   207  func TestDoubleSuspendMarketViaGovernance(t *testing.T) {
   208  	ctx := vgtest.VegaContext("chainid", 100)
   209  	now := time.Now()
   210  	exec := getEngine(t, paths2.New(t.TempDir()), now)
   211  	pubKey := &dstypes.SignerPubKey{
   212  		PubKey: &dstypes.PubKey{
   213  			Key: "0xDEADBEEF",
   214  		},
   215  	}
   216  	mkt := newMarket("MarketID", pubKey)
   217  	err := exec.engine.SubmitMarket(context.Background(), mkt, "", time.Now())
   218  	require.NoError(t, err)
   219  
   220  	exec.engine.StartOpeningAuction(context.Background(), mkt.ID)
   221  
   222  	// during opening auction
   223  	state, err := exec.engine.GetMarketData(mkt.ID)
   224  	require.NoError(t, err)
   225  	require.Equal(t, types.MarketStateActive, state.MarketState)
   226  	require.Equal(t, types.MarketTradingModeContinuous, state.MarketTradingMode)
   227  
   228  	config := &types.MarketStateUpdateConfiguration{
   229  		MarketID:        mkt.ID,
   230  		UpdateType:      types.MarketStateUpdateTypeSuspend,
   231  		SettlementPrice: num.NewUint(100),
   232  	}
   233  	require.NoError(t, exec.engine.UpdateMarketState(ctx, config))
   234  
   235  	// after governance suspension
   236  	state, err = exec.engine.GetMarketData(mkt.ID)
   237  	require.NoError(t, err)
   238  	require.Equal(t, types.MarketStateSuspendedViaGovernance, state.MarketState)
   239  	require.Equal(t, types.MarketTradingModeSuspendedViaGovernance, state.MarketTradingMode)
   240  	require.Equal(t, types.AuctionTriggerGovernanceSuspension, state.Trigger)
   241  	require.Equal(t, types.AuctionTriggerUnspecified, state.ExtensionTrigger)
   242  
   243  	// suspend again
   244  	require.Error(t, fmt.Errorf("invalid state update request. Market for suspend is already suspended"), exec.engine.UpdateMarketState(ctx, config))
   245  	state, err = exec.engine.GetMarketData(mkt.ID)
   246  	require.NoError(t, err)
   247  	require.Equal(t, types.MarketStateSuspendedViaGovernance, state.MarketState)
   248  	require.Equal(t, types.MarketTradingModeSuspendedViaGovernance, state.MarketTradingMode)
   249  	require.Equal(t, types.AuctionTriggerGovernanceSuspension, state.Trigger)
   250  	require.Equal(t, types.AuctionTriggerUnspecified, state.ExtensionTrigger)
   251  
   252  	exec.engine.OnTick(ctx, exec.timeService.GetTimeNow())
   253  
   254  	config.UpdateType = types.MarketStateUpdateTypeResume
   255  	require.NoError(t, exec.engine.UpdateMarketState(ctx, config))
   256  
   257  	exec.engine.OnTick(ctx, exec.timeService.GetTimeNow())
   258  
   259  	// after governance suspension ended - enter liquidity auction
   260  	state, err = exec.engine.GetMarketData(mkt.ID)
   261  	require.NoError(t, err)
   262  	require.Equal(t, types.MarketStateActive, state.MarketState)
   263  	require.Equal(t, types.MarketTradingModeContinuous, state.MarketTradingMode)
   264  	require.Equal(t, types.AuctionTriggerUnspecified, state.Trigger)
   265  	require.Equal(t, types.AuctionTriggerUnspecified, state.ExtensionTrigger)
   266  	require.Equal(t, int64(0), state.AuctionEnd)
   267  	require.Equal(t, int64(0), state.AuctionStart)
   268  }