Skip to content

Commit

Permalink
feat: AMMs can specify a spread around their fair-price
Browse files Browse the repository at this point in the history
  • Loading branch information
wwestgarth committed Oct 28, 2024
1 parent e2230d9 commit b583dca
Show file tree
Hide file tree
Showing 41 changed files with 4,370 additions and 4,178 deletions.
12 changes: 10 additions & 2 deletions commands/amend_amm.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,17 @@ func checkAmendAMM(cmd *commandspb.AmendAMM) Errors {

if cmd.MinimumPriceChangeTrigger != nil {
if minPriceChange, err := num.DecimalFromString(*cmd.MinimumPriceChangeTrigger); err != nil {
errs.AddForProperty("submit_amm.mimimum_price_change_trigger", ErrIsNotValid)
errs.AddForProperty("amend_amm.mimimum_price_change_trigger", ErrIsNotValid)
} else if minPriceChange.LessThan(num.DecimalZero()) {
errs.AddForProperty("submit_amm.proposed_fee", ErrMustBePositiveOrZero)
errs.AddForProperty("amend_amm.mimimum_price_change_trigger", ErrMustBePositiveOrZero)
}
}

if cmd.Spread != nil {
if spread, err := num.DecimalFromString(*cmd.Spread); err != nil {
errs.AddForProperty("amend_amm.spread", ErrIsNotValid)
} else if spread.LessThan(num.DecimalZero()) {
errs.AddForProperty("amend_amm.spread", ErrMustBePositiveOrZero)
}
}

Expand Down
8 changes: 8 additions & 0 deletions commands/submit_amm.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ func checkSubmitAMM(cmd *commandspb.SubmitAMM) Errors {
}
}

if cmd.Spread != nil {
if spread, err := num.DecimalFromString(*cmd.Spread); err != nil {
errs.AddForProperty("submit_amm.spread", ErrIsNotValid)
} else if spread.LessThan(num.DecimalZero()) {
errs.AddForProperty("submit_amm.spread", ErrMustBePositiveOrZero)
}
}

if cmd.ConcentratedLiquidityParameters == nil {
errs.FinalAddForProperty("submit_amm.concentrated_liquidity_parameters", ErrIsRequired)
} else {
Expand Down
2 changes: 2 additions & 0 deletions core/events/amm_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func NewAMMPoolEvent(
lowerCurve *AMMCurve,
upperCurve *AMMCurve,
minimumPriceChangeTrigger num.Decimal,
spread num.Decimal,
) *AMMPool {
return &AMMPool{
Base: newBase(ctx, AMMPoolEvent),
Expand All @@ -71,6 +72,7 @@ func NewAMMPoolEvent(
LowerCurve: lowerCurve.ToProtoEvent(),
UpperCurve: upperCurve.ToProtoEvent(),
MinimumPriceChangeTrigger: minimumPriceChangeTrigger.String(),
Spread: spread.String(),
},
}
}
Expand Down
9 changes: 4 additions & 5 deletions core/execution/amm/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ func (e *Engine) GetVolumeAtPrice(price *num.Uint, side types.Side) uint64 {
vol := uint64(0)
for _, pool := range e.poolsCpy {
// get the pool's current price
best, ok := pool.BestPrice(types.OtherSide(side))
best, ok, _ := pool.BestPrice(types.OtherSide(side))
if !ok {
continue
}
Expand Down Expand Up @@ -382,8 +382,8 @@ func (e *Engine) submit(active []*Pool, agg *types.Order, inner, outer *num.Uint
for _, p := range active {
p.setEphemeralPosition()

price, ok := p.BestPrice(types.OtherSide(agg.Side))
if !ok {
price, volume := p.BestPriceAndVolume(types.OtherSide(agg.Side))
if volume == 0 {
continue
}

Expand Down Expand Up @@ -696,8 +696,6 @@ func (e *Engine) Create(
e.positionFactor,
e.maxCalculationLevels,
e.allowedEmptyAMMLevels,
submit.SlippageTolerance,
submit.MinimumPriceChangeTrigger,
)
if err != nil {
return nil, err
Expand Down Expand Up @@ -874,6 +872,7 @@ func (e *Engine) sendUpdate(ctx context.Context, pool *Pool) {
TheoreticalPosition: pool.upper.pv,
},
pool.MinimumPriceChangeTrigger,
pool.spread,
),
)
}
Expand Down
24 changes: 12 additions & 12 deletions core/execution/amm/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ func testSubmitOrderAtBestPrice(t *testing.T) {
ensurePosition(t, tst.pos, 0, num.NewUint(0))
orders := tst.engine.SubmitOrder(agg, num.NewUint(2000), num.NewUint(2001))
require.Len(t, orders, 1)
assert.Equal(t, "2000", orders[0].Price.String())
assert.Equal(t, "2001", orders[0].Price.String())
assert.Equal(t, 11927, int(orders[0].Size))

bb, _, ba, _ := tst.engine.BestPricesAndVolumes()
Expand Down Expand Up @@ -360,7 +360,7 @@ func testSubmitOrderProRata(t *testing.T) {
orders := tst.engine.SubmitOrder(agg, num.NewUint(2010), num.NewUint(2020))
require.Len(t, orders, 3)
for _, o := range orders {
assert.Equal(t, "2000", o.Price.String())
assert.Equal(t, "2001", o.Price.String())
assert.Equal(t, uint64(222), o.Size)
}
}
Expand Down Expand Up @@ -402,9 +402,9 @@ func testSubmitOrderAcrossAMMBoundary(t *testing.T) {
require.Len(t, orders, 6)

// first round, three orders moving all pool's to the upper boundary of the shortest
assert.Equal(t, "2049", orders[0].Price.String())
assert.Equal(t, "2049", orders[1].Price.String())
assert.Equal(t, "2049", orders[2].Price.String())
assert.Equal(t, "2048", orders[0].Price.String())
assert.Equal(t, "2048", orders[1].Price.String())
assert.Equal(t, "2048", orders[2].Price.String())

// second round, 2 orders moving all pool's to the upper boundary of the second shortest
assert.Equal(t, "2124", orders[3].Price.String())
Expand Down Expand Up @@ -452,9 +452,9 @@ func testSubmitOrderAcrossAMMBoundarySell(t *testing.T) {
require.Len(t, orders, 6)

// first round, three orders moving all pool's to the upper boundary of the shortest
assert.Equal(t, "1949", orders[0].Price.String())
assert.Equal(t, "1949", orders[1].Price.String())
assert.Equal(t, "1949", orders[2].Price.String())
assert.Equal(t, "1948", orders[0].Price.String())
assert.Equal(t, "1948", orders[1].Price.String())
assert.Equal(t, "1948", orders[2].Price.String())

// second round, 2 orders moving all pool's to the upper boundary of the second shortest
assert.Equal(t, "1874", orders[3].Price.String())
Expand Down Expand Up @@ -503,7 +503,7 @@ func TestBestPricesAndVolumeNearBound(t *testing.T) {
expectSubaccountCreation(t, tst, party, subAccount)
whenAMMIsSubmitted(t, tst, submit)

tst.pos.EXPECT().GetPositionsByParty(gomock.Any()).Times(10).Return(
tst.pos.EXPECT().GetPositionsByParty(gomock.Any()).Times(8).Return(
[]events.MarketPosition{&marketPosition{size: 0, averageEntry: num.NewUint(0)}},
)

Expand All @@ -514,7 +514,7 @@ func TestBestPricesAndVolumeNearBound(t *testing.T) {
assert.Equal(t, 1192, int(avolume))

// lets move its position so that the fair price is within one tick of the AMMs upper boundary
tst.pos.EXPECT().GetPositionsByParty(gomock.Any()).Times(10).Return(
tst.pos.EXPECT().GetPositionsByParty(gomock.Any()).Times(8).Return(
[]events.MarketPosition{&marketPosition{size: -222000, averageEntry: num.NewUint(0)}},
)

Expand All @@ -525,7 +525,7 @@ func TestBestPricesAndVolumeNearBound(t *testing.T) {
assert.Equal(t, 104, int(avolume))

// lets move its position so that the fair price is within one tick of the AMMs upper boundary
tst.pos.EXPECT().GetPositionsByParty(gomock.Any()).Times(10).Return(
tst.pos.EXPECT().GetPositionsByParty(gomock.Any()).Times(8).Return(
[]events.MarketPosition{&marketPosition{size: 270400, averageEntry: num.NewUint(0)}},
)

Expand Down Expand Up @@ -746,7 +746,7 @@ func testAMMSnapshot(t *testing.T) {
orders := tst.engine.SubmitOrder(agg, num.NewUint(2010), num.NewUint(2020))
require.Len(t, orders, 3)
for _, o := range orders {
assert.Equal(t, "2000", o.Price.String())
assert.Equal(t, "2001", o.Price.String())
assert.Equal(t, uint64(222), o.Size)
}

Expand Down
Loading

0 comments on commit b583dca

Please sign in to comment.