Skip to content

Commit 227afa8

Browse files
authored
Merge pull request #11490 from vegaprotocol/another-stagnet-panic
fix: ensure AMM best bid/ask is capped at boundaries to we not not ov…
2 parents 6e72490 + c7fac85 commit 227afa8

2 files changed

Lines changed: 52 additions & 4 deletions

File tree

core/execution/amm/engine.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ func (e *Engine) BestPricesAndVolumes() (*num.Uint, uint64, *num.Uint, uint64) {
328328
fp := pool.BestPrice(nil)
329329

330330
// get the volume on the buy side by simulating an incoming sell order
331-
bid := num.UintZero().Sub(fp, pool.oneTick)
331+
bid := num.Max(pool.lower.low, num.UintZero().Sub(fp, pool.oneTick))
332332
volume := pool.TradableVolumeInRange(types.SideSell, fp.Clone(), bid)
333333

334334
if volume != 0 {
@@ -341,7 +341,7 @@ func (e *Engine) BestPricesAndVolumes() (*num.Uint, uint64, *num.Uint, uint64) {
341341
}
342342

343343
// get the volume on the sell side by simulating an incoming buy order
344-
ask := num.UintZero().Add(fp, pool.oneTick)
344+
ask := num.Min(pool.upper.high, num.UintZero().Add(fp, pool.oneTick))
345345
volume = pool.TradableVolumeInRange(types.SideBuy, fp.Clone(), ask)
346346
if volume != 0 {
347347
if bestAsk == nil || ask.LT(bestAsk) {

core/execution/amm/engine_test.go

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,49 @@ func testBestPricesAndVolume(t *testing.T) {
426426
assert.Equal(t, avolume, avAt)
427427
}
428428

429+
func TestBestPricesAndVolumeNearBound(t *testing.T) {
430+
tst := getTestEngineWithFactors(t, num.DecimalFromInt64(100), num.DecimalFromFloat(10))
431+
432+
// create three pools
433+
party, subAccount := getParty(t, tst)
434+
submit := getPoolSubmission(t, party, tst.marketID)
435+
436+
expectSubaccountCreation(t, tst, party, subAccount)
437+
whenAMMIsSubmitted(t, tst, submit)
438+
439+
tst.pos.EXPECT().GetPositionsByParty(gomock.Any()).Times(5).Return(
440+
[]events.MarketPosition{&marketPosition{size: 0, averageEntry: num.NewUint(0)}},
441+
)
442+
443+
bid, bvolume, ask, avolume := tst.engine.BestPricesAndVolumes()
444+
assert.Equal(t, "199900", bid.String())
445+
assert.Equal(t, "200100", ask.String())
446+
assert.Equal(t, 1250, int(bvolume))
447+
assert.Equal(t, 1192, int(avolume))
448+
449+
// lets move its position so that the fair price is within one tick of the AMMs upper boundary
450+
tst.pos.EXPECT().GetPositionsByParty(gomock.Any()).Times(5).Return(
451+
[]events.MarketPosition{&marketPosition{size: -222000, averageEntry: num.NewUint(0)}},
452+
)
453+
454+
bid, bvolume, ask, avolume = tst.engine.BestPricesAndVolumes()
455+
assert.Equal(t, "219890", bid.String())
456+
assert.Equal(t, "220000", ask.String()) // make sure we are capped to the boundary and not 220090
457+
assert.Equal(t, 1034, int(bvolume))
458+
assert.Equal(t, 103, int(avolume))
459+
460+
// lets move its position so that the fair price is within one tick of the AMMs upper boundary
461+
tst.pos.EXPECT().GetPositionsByParty(gomock.Any()).Times(5).Return(
462+
[]events.MarketPosition{&marketPosition{size: 270400, averageEntry: num.NewUint(0)}},
463+
)
464+
465+
bid, bvolume, ask, avolume = tst.engine.BestPricesAndVolumes()
466+
assert.Equal(t, "180000", bid.String()) // make sure we are capped to the boundary and not 179904
467+
assert.Equal(t, "180104", ask.String())
468+
assert.Equal(t, 58, int(bvolume))
469+
assert.Equal(t, 1463, int(avolume))
470+
}
471+
429472
func testClosingReduceOnlyPool(t *testing.T) {
430473
ctx := context.Background()
431474
tst := getTestEngine(t)
@@ -709,7 +752,7 @@ type tstEngine struct {
709752
assetID string
710753
}
711754

712-
func getTestEngine(t *testing.T) *tstEngine {
755+
func getTestEngineWithFactors(t *testing.T, priceFactor, positionFactor num.Decimal) *tstEngine {
713756
t.Helper()
714757
ctrl := gomock.NewController(t)
715758
col := mocks.NewMockCollateral(ctrl)
@@ -730,7 +773,7 @@ func getTestEngine(t *testing.T) *tstEngine {
730773
parties := cmocks.NewMockParties(ctrl)
731774
parties.EXPECT().AssignDeriveKey(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
732775

733-
eng := New(logging.NewTestLogger(), broker, col, marketID, assetID, pos, num.DecimalOne(), num.DecimalOne(), mat, parties)
776+
eng := New(logging.NewTestLogger(), broker, col, marketID, assetID, pos, priceFactor, positionFactor, mat, parties)
734777

735778
// do an ontick to initialise the idgen
736779
ctx := vgcontext.WithTraceID(context.Background(), vgcrypto.RandomHash())
@@ -748,6 +791,11 @@ func getTestEngine(t *testing.T) *tstEngine {
748791
}
749792
}
750793

794+
func getTestEngine(t *testing.T) *tstEngine {
795+
t.Helper()
796+
return getTestEngineWithFactors(t, num.DecimalOne(), num.DecimalOne())
797+
}
798+
751799
func getAccount(balance uint64) *types.Account {
752800
return &types.Account{
753801
Balance: num.NewUint(balance),

0 commit comments

Comments
 (0)