code.vegaprotocol.io/vega@v0.79.0/core/execution/spot/market_iceberg_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 spot_test 17 18 import ( 19 "context" 20 "testing" 21 "time" 22 23 "code.vegaprotocol.io/vega/core/events" 24 "code.vegaprotocol.io/vega/core/execution/common" 25 "code.vegaprotocol.io/vega/core/types" 26 vegacontext "code.vegaprotocol.io/vega/libs/context" 27 "code.vegaprotocol.io/vega/libs/crypto" 28 vgcrypto "code.vegaprotocol.io/vega/libs/crypto" 29 "code.vegaprotocol.io/vega/libs/num" 30 31 "github.com/stretchr/testify/require" 32 ) 33 34 func TestMarketSubmitCancelIceberg(t *testing.T) { 35 party1 := "party1" 36 now := time.Unix(100000, 0) 37 ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()) 38 tm := newTestMarket(t, defaultPriceMonitorSettings, &types.AuctionDuration{Duration: 1}, now) 39 defer tm.ctrl.Finish() 40 tm.market.StartOpeningAuction(ctx) 41 42 addAccountWithAmount(tm, party1, 10000000, tm.quoteAsset) 43 iceberg := &types.Order{ 44 Type: types.OrderTypeLimit, 45 TimeInForce: types.OrderTimeInForceGTC, 46 Status: types.OrderStatusActive, 47 ID: "someid", 48 Side: types.SideBuy, 49 Party: party1, 50 MarketID: tm.market.GetID(), 51 Size: 100, 52 Price: num.NewUint(10), 53 Remaining: 100, 54 CreatedAt: now.UnixNano(), 55 Reference: "party1-buy-order", 56 Version: common.InitialOrderVersion, 57 IcebergOrder: &types.IcebergOrder{ 58 PeakSize: 10, 59 MinimumVisibleSize: 5, 60 }, 61 } 62 63 // submit order 64 oid := crypto.RandomHash() 65 _, err := tm.market.SubmitOrder(context.Background(), iceberg.IntoSubmission(), party1, oid) 66 require.NoError(t, err) 67 68 tm.now = tm.now.Add(time.Second) 69 tm.market.OnTick(ctx, tm.now) 70 require.Equal(t, types.MarketStatePending, tm.market.GetMarketState()) 71 haBalance1, err := tm.collateralEngine.GetPartyHoldingAccount("party1", tm.quoteAsset) 72 require.NoError(t, err) 73 require.Equal(t, "1000", haBalance1.Balance.String()) 74 75 // now cancel the order and check potential buy returns to 0 76 tm.events = tm.events[:0] 77 _, err = tm.market.CancelOrder(context.Background(), iceberg.Party, oid, oid) 78 require.NoError(t, err) 79 tm.market.BlockEnd(vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash())) 80 81 haBalance2, err := tm.collateralEngine.GetPartyHoldingAccount("party1", tm.quoteAsset) 82 require.NoError(t, err) 83 require.Equal(t, "0", haBalance2.Balance.String()) 84 } 85 86 func TestMarketAmendIceberg(t *testing.T) { 87 party1 := "party1" 88 now := time.Unix(100000, 0) 89 ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()) 90 tm := newTestMarket(t, defaultPriceMonitorSettings, &types.AuctionDuration{Duration: 1}, now) 91 defer tm.ctrl.Finish() 92 tm.market.StartOpeningAuction(ctx) 93 94 addAccountWithAmount(tm, party1, 10000000, tm.quoteAsset) 95 iceberg := &types.Order{ 96 Type: types.OrderTypeLimit, 97 TimeInForce: types.OrderTimeInForceGTC, 98 Status: types.OrderStatusActive, 99 ID: "someid", 100 Side: types.SideBuy, 101 Party: party1, 102 MarketID: tm.market.GetID(), 103 Size: 100, 104 Price: num.NewUint(100), 105 Remaining: 100, 106 CreatedAt: now.UnixNano(), 107 Reference: "party1-buy-order", 108 Version: common.InitialOrderVersion, 109 IcebergOrder: &types.IcebergOrder{ 110 PeakSize: 10, 111 MinimumVisibleSize: 5, 112 }, 113 } 114 115 // submit order 116 oid := crypto.RandomHash() 117 _, err := tm.market.SubmitOrder(context.Background(), iceberg.IntoSubmission(), party1, oid) 118 require.NoError(t, err) 119 120 tm.now = tm.now.Add(time.Second) 121 tm.market.OnTick(ctx, tm.now) 122 require.Equal(t, types.MarketStatePending, tm.market.GetMarketState()) 123 124 haBalance1, err := tm.collateralEngine.GetPartyHoldingAccount("party1", tm.quoteAsset) 125 require.NoError(t, err) 126 require.Equal(t, "10000", haBalance1.Balance.String()) 127 128 gaBalance1, err := tm.collateralEngine.GetPartyGeneralAccount("party1", tm.quoteAsset) 129 require.NoError(t, err) 130 require.Equal(t, "9990000", gaBalance1.Balance.String()) 131 132 // now reduce the size of the iceberg so that only the reserved amount is reduced 133 amendedOrder := &types.OrderAmendment{ 134 OrderID: oid, 135 Price: nil, 136 SizeDelta: -50, 137 TimeInForce: types.OrderTimeInForceGTC, 138 } 139 140 tm.eventCount = 0 141 tm.events = tm.events[:0] 142 _, err = tm.market.AmendOrder(context.Background(), amendedOrder, party1, vgcrypto.RandomHash()) 143 require.NoError(t, err) 144 145 haBalance2, err := tm.collateralEngine.GetPartyHoldingAccount("party1", tm.quoteAsset) 146 require.NoError(t, err) 147 require.Equal(t, "5000", haBalance2.Balance.String()) 148 149 gaBalance2, err := tm.collateralEngine.GetPartyGeneralAccount("party1", tm.quoteAsset) 150 require.NoError(t, err) 151 require.Equal(t, "9995000", gaBalance2.Balance.String()) 152 153 amended := requireOrderEvent(t, tm.events) 154 require.Equal(t, uint64(50), amended.Size) 155 require.Equal(t, uint64(10), amended.Remaining) 156 require.Equal(t, uint64(40), amended.IcebergOrder.ReservedRemaining) 157 158 // now increase the size delta and check that reserved remaining is increased, but remaining is the same 159 amendedOrder.SizeDelta = 70 160 tm.eventCount = 0 161 tm.events = tm.events[:0] 162 _, err = tm.market.AmendOrder(context.Background(), amendedOrder, party1, vgcrypto.RandomHash()) 163 require.NoError(t, err) 164 amended = requireOrderEvent(t, tm.events) 165 require.Equal(t, uint64(120), amended.Size) 166 require.Equal(t, uint64(10), amended.Remaining) 167 require.Equal(t, uint64(110), amended.IcebergOrder.ReservedRemaining) 168 169 // now reduce the size such that reserved is reduce to 0 and some remaining is removed too 170 amendedOrder.SizeDelta = -115 171 tm.eventCount = 0 172 tm.events = tm.events[:0] 173 _, err = tm.market.AmendOrder(context.Background(), amendedOrder, party1, vgcrypto.RandomHash()) 174 require.NoError(t, err) 175 amended = requireOrderEvent(t, tm.events) 176 require.Equal(t, uint64(5), amended.Size) 177 require.Equal(t, uint64(5), amended.Remaining) 178 require.Equal(t, uint64(0), amended.IcebergOrder.ReservedRemaining) 179 } 180 181 func TestMarketAmendIcebergToNoReserve(t *testing.T) { 182 party1 := "party1" 183 now := time.Unix(100000, 0) 184 ctx := vegacontext.WithTraceID(context.Background(), vgcrypto.RandomHash()) 185 tm := newTestMarket(t, defaultPriceMonitorSettings, &types.AuctionDuration{Duration: 1}, now) 186 defer tm.ctrl.Finish() 187 tm.market.StartOpeningAuction(ctx) 188 189 addAccountWithAmount(tm, party1, 10000000, tm.quoteAsset) 190 191 iceberg := &types.Order{ 192 Type: types.OrderTypeLimit, 193 TimeInForce: types.OrderTimeInForceGTC, 194 Status: types.OrderStatusActive, 195 ID: "someid", 196 Side: types.SideBuy, 197 Party: party1, 198 MarketID: tm.market.GetID(), 199 Size: 100, 200 Price: num.NewUint(100), 201 Remaining: 100, 202 CreatedAt: now.UnixNano(), 203 Reference: "party1-buy-order", 204 Version: common.InitialOrderVersion, 205 IcebergOrder: &types.IcebergOrder{ 206 PeakSize: 100, 207 MinimumVisibleSize: 5, 208 }, 209 } 210 211 // submit order 212 oid := crypto.RandomHash() 213 _, err := tm.market.SubmitOrder(context.Background(), iceberg.IntoSubmission(), "party1", oid) 214 require.NoError(t, err) 215 216 tm.now = tm.now.Add(time.Second) 217 tm.market.OnTick(ctx, tm.now) 218 require.Equal(t, types.MarketStatePending, tm.market.GetMarketState()) 219 220 // now reduce the size of the iceberg so that only the reserved amount is reduced 221 amendedOrder := &types.OrderAmendment{ 222 OrderID: oid, 223 Price: nil, 224 SizeDelta: -75, 225 TimeInForce: types.OrderTimeInForceGTC, 226 } 227 228 tm.eventCount = 0 229 tm.events = tm.events[:0] 230 _, err = tm.market.AmendOrder(context.Background(), amendedOrder, party1, vgcrypto.RandomHash()) 231 require.NoError(t, err) 232 amended := requireOrderEvent(t, tm.events) 233 require.Equal(t, uint64(25), amended.Size) 234 require.Equal(t, uint64(25), amended.Remaining) 235 require.Equal(t, uint64(0), amended.IcebergOrder.ReservedRemaining) 236 } 237 238 func requireOrderEvent(t *testing.T, evts []events.Event) *types.Order { 239 t.Helper() 240 for _, e := range evts { 241 switch evt := e.(type) { 242 case *events.Order: 243 o, err := types.OrderFromProto(evt.Order()) 244 require.NoError(t, err) 245 return o 246 } 247 } 248 require.Fail(t, "did not find order event") 249 return nil 250 }