code.vegaprotocol.io/vega@v0.79.0/core/execution/future/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 future_test 17 18 import ( 19 "context" 20 "testing" 21 "time" 22 23 "code.vegaprotocol.io/vega/core/execution/common" 24 "code.vegaprotocol.io/vega/core/types" 25 vegacontext "code.vegaprotocol.io/vega/libs/context" 26 vgcrypto "code.vegaprotocol.io/vega/libs/crypto" 27 "code.vegaprotocol.io/vega/libs/num" 28 29 "github.com/golang/mock/gomock" 30 "github.com/stretchr/testify/assert" 31 "github.com/stretchr/testify/require" 32 ) 33 34 func TestMarketStates(t *testing.T) { 35 t.Run("test initial state is PROPOSED", testInitialStateIsProposed) 36 t.Run("cannot do order stuff in PROPOSED state", testCannotDoOrderStuffInProposedState) 37 t.Run("can move from PROPOSED to REJECTED state", testCanMoveFromProposedToRejectedState) 38 t.Run("can move from PROPOSED to PENDING state", testCanMoveFromProposedToPendingState) 39 t.Run("can move from PENDING to ACTIVE state", testCanMoveFromPendingToActiveState) 40 t.Run("can place order in PENDING state", testCanPlaceOrderInActiveState) 41 } 42 43 func testInitialStateIsProposed(t *testing.T) { 44 now := time.Unix(10, 0) 45 auctionDuration := &types.AuctionDuration{ 46 Duration: 30, // seconds 47 } 48 tm := getTestMarket2(t, now, nil, auctionDuration, false, 0.99) 49 defer tm.ctrl.Finish() 50 51 assert.Equal(t, types.MarketStateProposed, tm.market.State()) 52 } 53 54 func testCannotDoOrderStuffInProposedState(t *testing.T) { 55 now := time.Unix(10, 0) 56 auctionDuration := &types.AuctionDuration{ 57 Duration: 30, // seconds 58 } 59 ctx := context.Background() 60 61 tm := getTestMarket2(t, now, nil, auctionDuration, false, 0.99) 62 defer tm.ctrl.Finish() 63 assert.Equal(t, types.MarketStateProposed, tm.market.State()) 64 65 addAccountWithAmount(tm, "someparty", 100000000) 66 tm.broker.EXPECT().Send(gomock.Any()).AnyTimes() 67 68 // expect error 69 o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideBuy, "party-A", 5, 5000) 70 o1conf, err := tm.market.SubmitOrder(ctx, o1) 71 assert.Nil(t, o1conf) 72 assert.EqualError(t, err, common.ErrTradingNotAllowed.Error()) 73 74 o2conf, err := tm.market.CancelAllOrders(ctx, "someparty") 75 assert.Nil(t, o2conf) 76 assert.EqualError(t, err, common.ErrTradingNotAllowed.Error()) 77 78 o3conf, err := tm.market.CancelOrder(ctx, "someparty", "someorder", vgcrypto.RandomHash()) 79 assert.Nil(t, o3conf) 80 assert.EqualError(t, err, common.ErrTradingNotAllowed.Error()) 81 82 amendment := &types.OrderAmendment{ 83 OrderID: o1.ID, 84 Price: num.NewUint(4000), 85 SizeDelta: 10, 86 } 87 88 amendConf, err := tm.market.AmendOrder(ctx, amendment, "party-A", vgcrypto.RandomHash()) 89 assert.Nil(t, amendConf) 90 assert.EqualError(t, err, common.ErrTradingNotAllowed.Error()) 91 92 // but can place liquidity submission 93 lpsub := &types.LiquidityProvisionSubmission{ 94 MarketID: tm.market.GetID(), 95 CommitmentAmount: num.NewUint(1), 96 Fee: num.DecimalFromFloat(0.1), 97 } 98 99 err = tm.market.SubmitLiquidityProvision(ctx, lpsub, "someparty", vgcrypto.RandomHash()) 100 101 // we expect an error as this lp may be stupid 102 // but not equal to the trading not allowed one 103 assert.NoError(t, err) 104 } 105 106 func testCanMoveFromProposedToRejectedState(t *testing.T) { 107 now := time.Unix(10, 0) 108 auctionDuration := &types.AuctionDuration{ 109 Duration: 30, // seconds 110 } 111 tm := getTestMarket2(t, now, nil, auctionDuration, false, 0.99) 112 defer tm.ctrl.Finish() 113 114 assert.Equal(t, types.MarketStateProposed, tm.market.State()) 115 116 err := tm.market.Reject(context.Background()) 117 assert.NoError(t, err) 118 assert.Equal(t, types.MarketStateRejected, tm.market.State()) 119 } 120 121 func testCanMoveFromProposedToPendingState(t *testing.T) { 122 now := time.Unix(10, 0) 123 auctionDuration := &types.AuctionDuration{ 124 Duration: 30, // seconds 125 } 126 tm := getTestMarket2(t, now, nil, auctionDuration, false, 0.99) 127 defer tm.ctrl.Finish() 128 129 assert.Equal(t, types.MarketStateProposed, tm.market.State()) 130 131 err := tm.market.StartOpeningAuction(context.Background()) 132 assert.NoError(t, err) 133 assert.Equal(t, types.MarketStatePending, tm.market.State()) 134 } 135 136 func testCanMoveFromPendingToActiveState(t *testing.T) { 137 now := time.Unix(10, 0) 138 auctionDuration := &types.AuctionDuration{ 139 Duration: 30, // seconds 140 } 141 tm := getTestMarket2(t, now, nil, auctionDuration, false, 0.99) 142 defer tm.ctrl.Finish() 143 144 assert.Equal(t, types.MarketStateProposed, tm.market.State()) 145 146 err := tm.market.StartOpeningAuction(context.Background()) 147 assert.NoError(t, err) 148 assert.Equal(t, types.MarketStatePending, tm.market.State()) 149 150 addAccountWithAmount(tm, "party1", 100000000) 151 addAccountWithAmount(tm, "party2", 100000000) 152 addAccountWithAmount(tm, "party3", 100000000) 153 addAccountWithAmount(tm, "party4", 100000000) 154 addAccountWithAmount(tm, "lpprov", 100000000) 155 orders := []*types.Order{ 156 getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "order1", types.SideBuy, "party1", 1, 5000), 157 getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "order2", types.SideSell, "party2", 1, 5000), 158 getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "order3", types.SideBuy, "party3", 1, 4500), // buy too low 159 getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "order4", types.SideSell, "party4", 1, 5500), // sell too expensive 160 } 161 for _, o := range orders { 162 conf, err := tm.market.SubmitOrder(context.Background(), o) 163 assert.NotNil(t, conf) 164 assert.NoError(t, err) 165 } 166 lp := &types.LiquidityProvisionSubmission{ 167 MarketID: tm.market.GetID(), 168 CommitmentAmount: num.NewUint(15000), 169 Fee: num.DecimalFromFloat(0.01), 170 } 171 require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash())) 172 // now move to after the opening auction time 173 now = now.Add(40 * time.Second) 174 tm.now = now 175 tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now) 176 assert.Equal(t, types.MarketStateActive, tm.market.State()) 177 } 178 179 func testCanPlaceOrderInActiveState(t *testing.T) { 180 now := time.Unix(10, 0) 181 auctionDuration := &types.AuctionDuration{ 182 Duration: 30, // seconds 183 } 184 tm := getTestMarket2(t, now, nil, auctionDuration, false, 0.99) 185 defer tm.ctrl.Finish() 186 187 assert.Equal(t, types.MarketStateProposed, tm.market.State()) 188 189 err := tm.market.StartOpeningAuction(context.Background()) 190 assert.NoError(t, err) 191 assert.Equal(t, types.MarketStatePending, tm.market.State()) 192 193 addAccountWithAmount(tm, "party1", 100000000) 194 addAccountWithAmount(tm, "party2", 100000000) 195 addAccountWithAmount(tm, "party3", 100000000) 196 addAccountWithAmount(tm, "party4", 100000000) 197 addAccountWithAmount(tm, "lpprov", 100000000) 198 orders := []*types.Order{ 199 getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "order1", types.SideBuy, "party1", 1, 5000), 200 getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "order2", types.SideSell, "party2", 1, 5000), 201 getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "order3", types.SideBuy, "party3", 1, 4500), // buy too low 202 getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "order4", types.SideSell, "party4", 1, 5500), // sell too expensive 203 } 204 for _, o := range orders { 205 conf, err := tm.market.SubmitOrder(context.Background(), o) 206 assert.NotNil(t, conf) 207 assert.NoError(t, err) 208 } 209 lp := &types.LiquidityProvisionSubmission{ 210 MarketID: tm.market.GetID(), 211 CommitmentAmount: num.NewUint(15000), 212 Fee: num.DecimalFromFloat(0.01), 213 } 214 require.NoError(t, tm.market.SubmitLiquidityProvision(context.Background(), lp, "lpprov", vgcrypto.RandomHash())) 215 // now move to after the opening auction time 216 now = now.Add(40 * time.Second) 217 tm.now = now 218 tm.market.OnTick(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()), now) 219 assert.Equal(t, types.MarketStateActive, tm.market.State()) 220 221 addAccountWithAmount(tm, "someparty", 100000000) 222 tm.broker.EXPECT().Send(gomock.Any()).AnyTimes() 223 224 // expect error 225 o1 := getMarketOrder(tm, now, types.OrderTypeLimit, types.OrderTimeInForceGTC, "Order01", types.SideBuy, "someparty", 5, 5000) 226 o1conf, err := tm.market.SubmitOrder(context.Background(), o1) 227 assert.NotNil(t, o1conf) 228 assert.NoError(t, err) 229 }