Skip to content

Commit

Permalink
Merge pull request #11316 from vegaprotocol/10539-amm-auction-uncrossing
Browse files Browse the repository at this point in the history
feat: implement auction uncrossing for AMMs
  • Loading branch information
jeremyletang authored May 28, 2024
2 parents 0659753 + 839c15f commit 335f714
Show file tree
Hide file tree
Showing 30 changed files with 2,013 additions and 739 deletions.
33 changes: 23 additions & 10 deletions commands/amend_amm.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package commands

import (
"errors"
"math/big"

"code.vegaprotocol.io/vega/libs/num"
Expand Down Expand Up @@ -69,31 +70,44 @@ func checkAmendAMM(cmd *commandspb.AmendAMM) Errors {

if cmd.ConcentratedLiquidityParameters != nil {
hasUpdate = true
if amount, _ := big.NewInt(0).SetString(cmd.ConcentratedLiquidityParameters.Base, 10); amount == nil {
var base, lowerBound, upperBound *big.Int
if base, _ = big.NewInt(0).SetString(cmd.ConcentratedLiquidityParameters.Base, 10); base == nil {
errs.FinalAddForProperty("amend_amm.concentrated_liquidity_parameters.base", ErrIsNotValidNumber)
} else if amount.Cmp(big.NewInt(0)) <= 0 {
} else if base.Cmp(big.NewInt(0)) <= 0 {
errs.AddForProperty("amend_amm.concentrated_liquidity_parameters.base", ErrMustBePositive)
}

var haveLower, haveUpper bool
if cmd.ConcentratedLiquidityParameters.LowerBound != nil {
hasUpdate = true
if amount, _ := big.NewInt(0).SetString(*cmd.ConcentratedLiquidityParameters.LowerBound, 10); amount == nil {
haveLower = true
if lowerBound, _ = big.NewInt(0).SetString(*cmd.ConcentratedLiquidityParameters.LowerBound, 10); lowerBound == nil {
errs.FinalAddForProperty("amend_amm.concentrated_liquidity_parameters.lower_bound", ErrIsNotValidNumber)
} else if amount.Cmp(big.NewInt(0)) <= 0 {
} else if lowerBound.Cmp(big.NewInt(0)) <= 0 {
errs.AddForProperty("amend_amm.concentrated_liquidity_parameters.lower_bound", ErrMustBePositive)
}
}
if cmd.ConcentratedLiquidityParameters.UpperBound != nil {
hasUpdate = true
if amount, _ := big.NewInt(0).SetString(*cmd.ConcentratedLiquidityParameters.UpperBound, 10); amount == nil {
haveUpper = true
if upperBound, _ = big.NewInt(0).SetString(*cmd.ConcentratedLiquidityParameters.UpperBound, 10); upperBound == nil {
errs.FinalAddForProperty("amend_amm.concentrated_liquidity_parameters.upper_bound", ErrIsNotValidNumber)
} else if amount.Cmp(big.NewInt(0)) <= 0 {
} else if upperBound.Cmp(big.NewInt(0)) <= 0 {
errs.AddForProperty("amend_amm.concentrated_liquidity_parameters.upper_bound", ErrMustBePositive)
}
}

if !haveLower && !haveUpper {
errs.AddForProperty("amend_amm.concentrated_liquidity_parameters.lower_bound", errors.New("lower_bound and upper_bound cannot both be empty"))
}

if base != nil && lowerBound != nil && base.Cmp(lowerBound) <= 0 {
errs.AddForProperty("amend_amm.concentrated_liquidity_parameters.base", errors.New("should be a bigger value than lower_bound"))
}

if base != nil && upperBound != nil && base.Cmp(upperBound) >= 0 {
errs.AddForProperty("amend_amm.concentrated_liquidity_parameters.base", errors.New("should be a smaller value than upper_bound"))
}

if cmd.ConcentratedLiquidityParameters.LeverageAtUpperBound != nil {
hasUpdate = true
if leverage, err := num.DecimalFromString(*cmd.ConcentratedLiquidityParameters.LeverageAtUpperBound); err != nil {
errs.AddForProperty("amend_amm.concentrated_liquidity_parameters.leverage_at_upper_bound", ErrIsNotValidNumber)
} else if leverage.LessThan(num.DecimalZero()) {
Expand All @@ -102,7 +116,6 @@ func checkAmendAMM(cmd *commandspb.AmendAMM) Errors {
}

if cmd.ConcentratedLiquidityParameters.LeverageAtLowerBound != nil {
hasUpdate = true
if leverage, err := num.DecimalFromString(*cmd.ConcentratedLiquidityParameters.LeverageAtLowerBound); err != nil {
errs.AddForProperty("amend_amm.concentrated_liquidity_parameters.leverage_at_lower_bound", ErrIsNotValidNumber)
} else if leverage.LessThan(num.DecimalZero()) {
Expand Down
37 changes: 37 additions & 0 deletions commands/amend_amm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,43 @@ func TestCheckAmendAMM(t *testing.T) {
},
errStr: "* (no updates provided)",
},
{
submission: commandspb.AmendAMM{
MarketId: "e9982447fb4128f9968f9981612c5ea85d19b62058ec2636efc812dcbbc745ca",
SlippageTolerance: "0.09",
CommitmentAmount: ptr.From("10000"),
ConcentratedLiquidityParameters: &commandspb.AmendAMM_ConcentratedLiquidityParameters{
Base: "20000",
},
},
errStr: "amend_amm.concentrated_liquidity_parameters.lower_bound (lower_bound and upper_bound cannot both be empty)",
},
{
submission: commandspb.AmendAMM{
MarketId: "e9982447fb4128f9968f9981612c5ea85d19b62058ec2636efc812dcbbc745ca",
SlippageTolerance: "0.09",
CommitmentAmount: ptr.From("10000"),
ConcentratedLiquidityParameters: &commandspb.AmendAMM_ConcentratedLiquidityParameters{
LowerBound: ptr.From("10000"),
Base: "20000",
UpperBound: ptr.From("15000"),
},
},
errStr: "amend_amm.concentrated_liquidity_parameters.base (should be a smaller value than upper_bound)",
},
{
submission: commandspb.AmendAMM{
MarketId: "e9982447fb4128f9968f9981612c5ea85d19b62058ec2636efc812dcbbc745ca",
SlippageTolerance: "0.09",
CommitmentAmount: ptr.From("10000"),
ConcentratedLiquidityParameters: &commandspb.AmendAMM_ConcentratedLiquidityParameters{
LowerBound: ptr.From("25000"),
Base: "20000",
UpperBound: ptr.From("30000"),
},
},
errStr: "amend_amm.concentrated_liquidity_parameters.base (should be a bigger value than lower_bound)",
},
{
submission: commandspb.AmendAMM{
MarketId: "e9982447fb4128f9968f9981612c5ea85d19b62058ec2636efc812dcbbc745ca",
Expand Down
98 changes: 75 additions & 23 deletions core/execution/amm/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ type Engine struct {
ammParties map[string]string

minCommitmentQuantum *num.Uint
maxCalculationLevels *num.Uint
}

func New(
Expand Down Expand Up @@ -247,6 +248,14 @@ func (e *Engine) OnMinCommitmentQuantumUpdate(ctx context.Context, c *num.Uint)
e.minCommitmentQuantum = c.Clone()
}

func (e *Engine) OnMaxCalculationLevelsUpdate(ctx context.Context, c *num.Uint) {
e.maxCalculationLevels = c.Clone()

for _, p := range e.poolsCpy {
p.maxCalculationLevels = e.maxCalculationLevels.Clone()
}
}

// OnMTM is called whenever core does an MTM and is a signal that any pool's that are closing and have 0 position can be fully removed.
func (e *Engine) OnMTM(ctx context.Context) {
rm := []string{}
Expand Down Expand Up @@ -444,23 +453,11 @@ func (e *Engine) submit(active []*Pool, agg *types.Order, inner, outer *num.Uint
logging.String("side", types.OtherSide(agg.Side).String()),
)

// construct the orders
o := &types.Order{
ID: e.idgen.NextID(),
MarketID: p.market,
Party: p.AMMParty,
Size: volume,
Remaining: volume,
Price: price,
Side: types.OtherSide(agg.Side),
TimeInForce: types.OrderTimeInForceFOK,
Type: types.OrderTypeMarket,
CreatedAt: agg.CreatedAt,
Status: types.OrderStatusFilled,
Reference: "vamm-" + p.AMMParty,
GeneratedOffbook: true,
}
o.OriginalPrice, _ = num.UintFromDecimal(o.Price.ToDecimal().Div(e.priceFactor))
// construct an order
o := p.makeOrder(volume, price, types.OtherSide(agg.Side), e.idgen)

// fill in extra details
o.CreatedAt = agg.CreatedAt

orders = append(orders, o)
p.updateEphemeralPosition(o)
Expand Down Expand Up @@ -507,6 +504,11 @@ func (e *Engine) partition(agg *types.Order, inner, outer *num.Uint) ([]*Pool, [
continue
}

// stop early trying to trade with itself, can happens during auction uncrossing
if agg.Party == p.AMMParty {
continue
}

// not active in range if its the pool's curves are wholly outside of [inner, outer]
if (inner != nil && p.upper.high.LT(inner)) || (outer != nil && p.lower.low.GT(outer)) {
continue
Expand Down Expand Up @@ -652,6 +654,7 @@ func (e *Engine) Create(
slippage,
e.priceFactor,
e.positionFactor,
e.maxCalculationLevels,
)
if err != nil {
e.broker.Send(
Expand All @@ -665,10 +668,10 @@ func (e *Engine) Create(
return nil, err
}

e.log.Debug("AMM created for market",
e.log.Debug("AMM created",
logging.String("owner", submit.Party),
logging.String("marketID", e.marketID),
logging.String("poolID", pool.ID),
logging.String("marketID", e.marketID),
)
return pool, nil
}
Expand All @@ -677,17 +680,19 @@ func (e *Engine) Create(
func (e *Engine) Confirm(
ctx context.Context,
pool *Pool,
) error {
e.log.Debug("AMM added for market",
) {
e.log.Debug("AMM confirmed",
logging.String("owner", pool.owner),
logging.String("marketID", e.marketID),
logging.String("poolID", pool.ID),
)

pool.status = types.AMMPoolStatusActive
pool.maxCalculationLevels = e.maxCalculationLevels

e.add(pool)
e.sendUpdate(ctx, pool)
e.parties.AssignDeriveKey(types.PartyID(pool.owner), pool.AMMParty)
return nil
}

// Amend takes the details of an amendment to an AMM and returns a copy of that pool with the updated curves along with the current pool.
Expand Down Expand Up @@ -717,7 +722,11 @@ func (e *Engine) Amend(
if err != nil {
return nil, nil, err
}

e.log.Debug("AMM amended",
logging.String("owner", amend.Party),
logging.String("marketID", e.marketID),
logging.String("poolID", pool.ID),
)
return updated, pool, nil
}

Expand Down Expand Up @@ -746,6 +755,11 @@ func (e *Engine) CancelAMM(

pool.status = types.AMMPoolStatusCancelled
e.remove(ctx, cancel.Party)
e.log.Debug("AMM cancelled",
logging.String("owner", cancel.Party),
logging.String("poolID", pool.ID),
logging.String("marketID", e.marketID),
)
return closeout, nil
}

Expand Down Expand Up @@ -907,6 +921,36 @@ func (e *Engine) GetAMMPoolsBySubAccount() map[string]common.AMMPool {
return ret
}

// OrderbookShape expands all registered AMM's into orders between the given prices. If `ammParty` is supplied then just the pool
// with that party id is expanded.
func (e *Engine) OrderbookShape(st, nd *num.Uint, ammParty *string) ([]*types.Order, []*types.Order) {
if ammParty == nil {
// no party give, expand all registered
buys, sells := []*types.Order{}, []*types.Order{}
for _, p := range e.poolsCpy {
b, s := p.OrderbookShape(st, nd, e.idgen)
buys = append(buys, b...)
sells = append(sells, s...)
}
return buys, sells
}

// asked to expand just one AMM, lets find it, first amm-party -> owning party
owner, ok := e.ammParties[*ammParty]
if !ok {
return nil, nil
}

// now owning party -> pool
p, ok := e.pools[owner]
if !ok {
return nil, nil
}

// expand it
return p.OrderbookShape(st, nd, e.idgen)
}

func (e *Engine) GetAllSubAccounts() []string {
ret := make([]string, 0, len(e.ammParties))
for _, subAccount := range e.ammParties {
Expand All @@ -915,6 +959,14 @@ func (e *Engine) GetAllSubAccounts() []string {
return ret
}

// GetAMMParty returns the AMM's key given the owners key.
func (e *Engine) GetAMMParty(party string) (string, error) {
if p, ok := e.pools[party]; ok {
return p.AMMParty, nil
}
return "", ErrNoPoolMatchingParty
}

func (e *Engine) add(p *Pool) {
e.pools[p.owner] = p
e.poolsCpy = append(e.poolsCpy, p)
Expand Down
2 changes: 1 addition & 1 deletion core/execution/amm/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ func whenAMMIsSubmitted(t *testing.T, tst *tstEngine, submission *types.SubmitAM
ctx := context.Background()
pool, err := tst.engine.Create(ctx, submission, vgcrypto.RandomHash(), riskFactors, scalingFactors, slippage)
require.NoError(t, err)
require.NoError(t, tst.engine.Confirm(ctx, pool))
tst.engine.Confirm(ctx, pool)
}

func getParty(t *testing.T, tst *tstEngine) (string, string) {
Expand Down
Loading

0 comments on commit 335f714

Please sign in to comment.