code.vegaprotocol.io/vega@v0.79.0/core/execution/future/auction.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 17 18 import ( 19 "context" 20 "time" 21 22 "code.vegaprotocol.io/vega/core/execution/common" 23 "code.vegaprotocol.io/vega/core/types" 24 "code.vegaprotocol.io/vega/libs/num" 25 "code.vegaprotocol.io/vega/logging" 26 ) 27 28 func (m *Market) checkAuction(ctx context.Context, now time.Time, idgen common.IDGenerator) { 29 if !m.as.InAuction() { 30 // new block, check bond balance, top up if needed 31 m.checkBondBalance(ctx) 32 return 33 } 34 35 if m.mkt.State == types.MarketStateSuspendedViaGovernance { 36 if endTS := m.as.ExpiresAt(); endTS != nil && endTS.Before(now) { 37 m.as.ExtendAuctionSuspension(types.AuctionDuration{Duration: int64(m.minDuration.Seconds())}) 38 return 39 } 40 } 41 42 // here we are in auction, we'll want to check 43 // the triggers if we are leaving 44 defer func() { 45 m.triggerStopOrders(ctx, idgen) 46 }() 47 indicativeUncrossingPrice := num.UintZero() 48 49 checkExceeded := m.mkt.State == types.MarketStatePending 50 51 // as soon as we have an indicative uncrossing price in opening auction it needs to be passed into the price monitoring engine so statevar calculation can start 52 isOpening := m.as.IsOpeningAuction() 53 if isOpening && !m.pMonitor.Initialised() { 54 indicativeUncrossingPrice = m.matching.OrderBook.GetIndicativePrice() 55 if !indicativeUncrossingPrice.IsZero() { 56 // pass the first uncrossing trades to price engine so state variables depending on it can be initialised 57 m.pMonitor.ResetPriceHistory(indicativeUncrossingPrice) 58 m.OnOpeningAuctionFirstUncrossingPrice() 59 } 60 } 61 62 if endTS := m.as.ExpiresAt(); endTS == nil || !endTS.Before(now) { 63 if isOpening && checkExceeded && m.as.ExceededMaxOpening(now) { 64 // cancel the market, exceeded opening auction 65 m.log.Debug("Market was cancelled because it failed to leave opening auction in time", logging.MarketID(m.GetID())) 66 m.terminateMarket(ctx, types.MarketStateCancelled, nil) 67 } 68 return 69 } 70 if indicativeUncrossingPrice.IsZero() { 71 indicativeUncrossingPrice = m.matching.OrderBook.GetIndicativePrice() 72 } 73 74 // opening auction 75 if isOpening { 76 if indicativeUncrossingPrice.IsZero() { 77 if checkExceeded && m.as.ExceededMaxOpening(now) { 78 m.log.Debug("Market was cancelled because it failed to leave opening auction in time", logging.MarketID(m.GetID())) 79 m.terminateMarket(ctx, types.MarketStateCancelled, nil) 80 } 81 return 82 } 83 84 // first check liquidity - before we mark auction as ready to leave 85 m.checkBondBalance(ctx) 86 if checkExceeded && m.as.ExceededMaxOpening(now) { 87 // cancel the market, exceeded opening auction 88 m.log.Debug("Market was cancelled because it failed to leave opening auction in time", logging.MarketID(m.GetID())) 89 m.terminateMarket(ctx, types.MarketStateCancelled, nil) 90 return 91 } 92 if e := m.as.AuctionExtended(ctx, now); e != nil { 93 m.broker.Send(e) 94 return 95 } 96 // opening auction requirements satisfied at this point, other requirements still need to be checked downstream though 97 m.as.SetReadyToLeave() 98 99 // if we don't have yet consensus for the floating point parameters, stay in the opening auction 100 if !m.CanLeaveOpeningAuction() { 101 m.log.Info("cannot leave opening auction - waiting for floating point to complete the first round") 102 return 103 } 104 m.log.Info("leaving opening auction for market", logging.String("market-id", m.mkt.ID)) 105 m.leaveAuction(ctx, now) 106 107 m.equityShares.OpeningAuctionEnded() 108 // start the market fee window 109 m.feeSplitter.TimeWindowStart(now) 110 111 // reset SLA epoch 112 m.liquidity.OnEpochStart(ctx, 113 m.timeService.GetTimeNow(), 114 m.getCurrentMarkPrice(), 115 m.midPrice(), 116 m.getTargetStake(), 117 m.positionFactor, 118 ) 119 return 120 } 121 // NOTE: This is a fix for the snapshot restores in case we're restoring a liquidity auction 122 // from a snapshot (or protocol upgrade) with state form before the liquidity monitoring was still 123 // in place. This can be removed once we've deployed the version without liquidity monitoring. 124 // Liquidity auctions are no longer a thing, we know we're not in opening auction here 125 // if we're not in price auction, we should just let the liquidity auction expire 126 if m.as.Trigger() == types.AuctionTriggerLiquidityTargetNotMet || m.as.Trigger() == types.AuctionTriggerUnableToDeployLPOrders { 127 m.as.SetReadyToLeave() 128 } 129 130 if m.as.Trigger() == types.AuctionTriggerLongBlock || m.as.ExtensionTrigger() == types.AuctionTriggerLongBlock { 131 if endTS := m.as.ExpiresAt(); endTS != nil && endTS.Before(now) { 132 m.as.SetReadyToLeave() 133 } 134 } 135 136 // price and liquidity auctions 137 isPrice := m.as.IsPriceAuction() || m.as.IsPriceExtension() 138 if !isPrice { 139 m.checkBondBalance(ctx) 140 } 141 if isPrice || m.as.CanLeave() { 142 m.pMonitor.CheckPrice(ctx, m.as, indicativeUncrossingPrice, true, true) 143 } 144 end := m.as.CanLeave() 145 if isPrice && end { 146 m.checkBondBalance(ctx) 147 } 148 if evt := m.as.AuctionExtended(ctx, m.timeService.GetTimeNow()); evt != nil { 149 m.broker.Send(evt) 150 end = false 151 } 152 // price monitoring engine and liquidity monitoring engine both indicated auction can end 153 if end { 154 // can we leave based on the book state? 155 m.leaveAuction(ctx, now) 156 } 157 158 // This is where FBA handling will go 159 }