Skip to content

Commit 48fe5f1

Browse files
committed
fix: validate settlement data when performing binary settlements
Signed-off-by: Elias Van Ootegem <elias@vega.xyz>
1 parent 5c8a349 commit 48fe5f1

File tree

2 files changed

+37
-4
lines changed

2 files changed

+37
-4
lines changed

core/execution/common/errors.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,6 @@ var (
8888
ErrInvalidOrderPrice = errors.New("invalid order price")
8989
// ErrIsolatedMarginFullyCollateralised is returned when a party tries to switch margin modes on a fully collateralised market.
9090
ErrIsolatedMarginFullyCollateralised = errors.New("isolated margin not permitted on fully collateralised markets")
91+
// ErrSettlementDataOutOfRange is returned when a capped future receives settlement data that is outside of the acceptable range (either > max price, or neither 0 nor max for binary settlements).
92+
ErrSettlementDataOutOfRange = errors.New("settlement data is outside of the price cap")
9193
)

core/execution/future/market.go

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4648,16 +4648,21 @@ func (m *Market) terminateMarket(ctx context.Context, finalState types.MarketSta
46484648

46494649
m.broker.Send(events.NewMarketUpdatedEvent(ctx, *m.mkt))
46504650
var err error
4651-
if settlementDataInAsset != nil {
4651+
if settlementDataInAsset != nil && m.validateSettlementData(settlementDataInAsset) {
46524652
m.settlementDataWithLock(ctx, finalState, settlementDataInAsset)
46534653
} else if m.settlementDataInMarket != nil {
46544654
// because we need to be able to perform the MTM settlement, only update market state now
46554655
settlementDataInAsset, err = m.tradableInstrument.Instrument.Product.ScaleSettlementDataToDecimalPlaces(m.settlementDataInMarket, m.assetDP)
46564656
if err != nil {
46574657
m.log.Error(err.Error())
4658-
} else {
4659-
m.settlementDataWithLock(ctx, finalState, settlementDataInAsset)
4658+
return
4659+
}
4660+
if !m.validateSettlementData(settlementDataInAsset) {
4661+
m.log.Warn("invalid settlement data", logging.MarketID(m.GetID()))
4662+
m.settlementDataInMarket = nil
4663+
return
46604664
}
4665+
m.settlementDataWithLock(ctx, finalState, settlementDataInAsset)
46614666
} else {
46624667
m.log.Debug("no settlement data", logging.MarketID(m.GetID()))
46634668
}
@@ -4710,6 +4715,13 @@ func (m *Market) settlementData(ctx context.Context, settlementData *num.Numeric
47104715
return
47114716
}
47124717

4718+
// validate the settlement data
4719+
if !m.validateSettlementData(settlementDataInAsset) {
4720+
m.log.Warn("settlement data for capped market is invalid", logging.MarketID(m.GetID()))
4721+
// reset settlement data, it's not valid
4722+
m.settlementDataInMarket = nil
4723+
return
4724+
}
47134725
m.settlementDataWithLock(ctx, types.MarketStateSettled, settlementDataInAsset)
47144726
}
47154727

@@ -4795,13 +4807,31 @@ func (m *Market) settlementDataPerp(ctx context.Context, settlementData *num.Num
47954807
m.checkForReferenceMoves(ctx, orderUpdates, false)
47964808
}
47974809

4810+
func (m *Market) validateSettlementData(data *num.Uint) bool {
4811+
if m.closed {
4812+
return false
4813+
}
4814+
// not capped, accept the data
4815+
if m.fCap == nil {
4816+
return true
4817+
}
4818+
// data > max
4819+
if m.capMax.LT(data) {
4820+
return false
4821+
}
4822+
// binary capped market: reject if data is not zero and not == max price.
4823+
if m.fCap.Binary && !data.IsZero() && !data.EQ(m.capMax) {
4824+
return false
4825+
}
4826+
return true
4827+
}
4828+
47984829
// NB this must be called with the lock already acquired.
47994830
func (m *Market) settlementDataWithLock(ctx context.Context, finalState types.MarketState, settlementDataInAsset *num.Uint) {
48004831
if m.closed {
48014832
return
48024833
}
48034834
if m.capMax != nil && m.capMax.LT(settlementDataInAsset) {
4804-
// we cannot perform the final settlement because the settlement price is out of the [0, max_price] range
48054835
return
48064836
}
48074837
if m.fCap != nil && m.fCap.Binary {
@@ -4833,6 +4863,7 @@ func (m *Market) settlementDataWithLock(ctx context.Context, finalState types.Ma
48334863
m.broker.Send(events.NewMarketDataEvent(ctx, m.GetMarketData()))
48344864
m.broker.Send(events.NewMarketSettled(ctx, m.GetID(), m.timeService.GetTimeNow().UnixNano(), m.lastTradedPrice, m.positionFactor))
48354865
}
4866+
return
48364867
}
48374868

48384869
func (m *Market) canTrade() bool {

0 commit comments

Comments
 (0)