code.vegaprotocol.io/vega@v0.79.0/core/integration/steps/amm_events.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 steps
    17  
    18  import (
    19  	"fmt"
    20  
    21  	"code.vegaprotocol.io/vega/core/events"
    22  	"code.vegaprotocol.io/vega/core/integration/stubs"
    23  	"code.vegaprotocol.io/vega/core/types"
    24  	"code.vegaprotocol.io/vega/libs/ptr"
    25  	"code.vegaprotocol.io/vega/logging"
    26  
    27  	"github.com/cucumber/godog"
    28  )
    29  
    30  func AMMPoolStatusShouldBe(broker *stubs.BrokerStub, table *godog.Table) error {
    31  	recent := broker.GetLastAMMPoolEvents()
    32  	for _, r := range parseAMMEventTable(table) {
    33  		row := ammEvtRow{
    34  			r: r,
    35  		}
    36  		mID, pID := row.market(), row.party()
    37  		mmap, ok := recent[mID]
    38  		if !ok {
    39  			return fmt.Errorf("no AMM events found for market %s", mID)
    40  		}
    41  		pEvt, ok := mmap[pID]
    42  		if !ok {
    43  			return fmt.Errorf("no AMM events found for party %s in market %s", pID, mID)
    44  		}
    45  		if err := row.matchesEvt(pEvt); err != nil {
    46  			return err
    47  		}
    48  	}
    49  	return nil
    50  }
    51  
    52  func ExpectToSeeAMMEvents(broker *stubs.BrokerStub, table *godog.Table) error {
    53  	evtMap := broker.GetAMMPoolEventMap()
    54  	for _, r := range parseAMMEventTable(table) {
    55  		row := ammEvtRow{
    56  			r: r,
    57  		}
    58  		mID, pID := row.market(), row.party()
    59  		mmap, ok := evtMap[mID]
    60  		if !ok {
    61  			return fmt.Errorf("no AMM events found for market %s", mID)
    62  		}
    63  		pEvts, ok := mmap[pID]
    64  		if !ok {
    65  			return fmt.Errorf("no AMM events found for party %s in market %s", pID, mID)
    66  		}
    67  		var err error
    68  		for _, e := range pEvts {
    69  			if err = row.matchesEvt(e); err == nil {
    70  				break
    71  			}
    72  		}
    73  		if err != nil {
    74  			return fmt.Errorf("expected AMM event for party %s on market %s not found, last AMM pool event mismatch: %v", pID, mID, err)
    75  		}
    76  	}
    77  	return nil
    78  }
    79  
    80  func SetAMMPartyAlias(broker *stubs.BrokerStub, exec Execution, table *godog.Table) error {
    81  	// get the most recent event by market and party
    82  	recent := broker.GetLastAMMPoolEvents()
    83  	for _, r := range parseAMMAccountAlias(table) {
    84  		row := ammEvtRow{
    85  			r: r,
    86  		}
    87  		mID, pID := row.market(), row.party()
    88  		mmap, ok := recent[mID]
    89  		if !ok {
    90  			return fmt.Errorf("no AMM events found for market %s", mID)
    91  		}
    92  		pEvt, ok := mmap[pID]
    93  		if !ok {
    94  			return fmt.Errorf("no AMM event found for party %s in market %s", pID, mID)
    95  		}
    96  		pid := pEvt.AMMPool().AmmPartyId
    97  		exec.SetAMMSubAccountIDAlias(row.alias(), pid)
    98  	}
    99  	return nil
   100  }
   101  
   102  type ammEvtRow struct {
   103  	r RowWrapper
   104  }
   105  
   106  func parseAMMAccountAlias(table *godog.Table) []RowWrapper {
   107  	return StrictParseTable(table, []string{
   108  		"party",
   109  		"market id",
   110  		"alias",
   111  	}, nil)
   112  }
   113  
   114  func parseAMMEventTable(table *godog.Table) []RowWrapper {
   115  	return StrictParseTable(table, []string{
   116  		"party",
   117  		"market id",
   118  		"amount",
   119  		"status",
   120  	}, []string{
   121  		"reason",
   122  		"base",
   123  		"lower bound",
   124  		"upper bound",
   125  		"lower leverage",
   126  		"upper leverage",
   127  	})
   128  }
   129  
   130  func DebugAMMPoolEvents(broker *stubs.BrokerStub, log *logging.Logger) error {
   131  	evts := broker.GetAMMPoolEvents()
   132  	logEvents(log, evts)
   133  	return nil
   134  }
   135  
   136  func DebugAMMPoolEventsForPartyMarket(broker *stubs.BrokerStub, log *logging.Logger, party, market *string) error {
   137  	if party == nil && market == nil {
   138  		return DebugAMMPoolEvents(broker, log)
   139  	}
   140  	if market == nil {
   141  		logEvents(log, broker.GetAMMPoolEventsByParty(*party))
   142  		return nil
   143  	}
   144  	if party == nil {
   145  		logEvents(log, broker.GetAMMPoolEventsByMarket(*market))
   146  		return nil
   147  	}
   148  	logEvents(log, broker.GetAMMPoolEventsByPartyAndMarket(*party, *market))
   149  	return nil
   150  }
   151  
   152  func logEvents(log *logging.Logger, evts []*events.AMMPool) {
   153  	for _, e := range evts {
   154  		pool := e.AMMPool()
   155  		if pool.Parameters == nil {
   156  			log.Info(fmt.Sprintf("AMM Party: %s on Market: %s - Amount: %s - no parameters", pool.PartyId, pool.MarketId, pool.Commitment))
   157  			continue
   158  		}
   159  
   160  		var lowerLeverage, upperLeverage, lowerBound, upperBound string
   161  		if pool.Parameters.LeverageAtLowerBound != nil {
   162  			lowerLeverage = *pool.Parameters.LeverageAtLowerBound
   163  		}
   164  		if pool.Parameters.LeverageAtUpperBound != nil {
   165  			upperLeverage = *pool.Parameters.LeverageAtUpperBound
   166  		}
   167  
   168  		if pool.Parameters.UpperBound != nil {
   169  			upperBound = *pool.Parameters.UpperBound
   170  		}
   171  		if pool.Parameters.LowerBound != nil {
   172  			lowerBound = *pool.Parameters.LowerBound
   173  		}
   174  
   175  		log.Info(fmt.Sprintf(
   176  			"AMM Party: %s on Market: %s - Amount: %s\nStatus: %s, Reason: %s\n Base: %s, Bounds: %s-%s, Leverages: %s-%s",
   177  			pool.PartyId, pool.MarketId, pool.Commitment,
   178  			pool.Status.String(), pool.StatusReason.String(),
   179  			pool.Parameters.Base, lowerBound, upperBound,
   180  			lowerLeverage, upperLeverage,
   181  		))
   182  	}
   183  }
   184  
   185  func (a ammEvtRow) matchesEvt(e *events.AMMPool) error {
   186  	pool := e.AMMPool()
   187  
   188  	if pool.PartyId != a.party() || pool.MarketId != a.market() || pool.Commitment != a.r.MustStr("amount") || pool.Status != a.status() {
   189  		return fmt.Errorf(
   190  			"expected party %s, market %s, amount %s, status %s - instead got %s, %s, %s, %s",
   191  			a.party(), a.market(), a.r.MustStr("amount"), a.status().String(),
   192  			pool.PartyId, pool.MarketId, pool.Commitment, pool.Status.String(),
   193  		)
   194  	}
   195  	got := make([]any, 0, 10)
   196  	got = append(got, pool.PartyId, pool.MarketId, pool.Commitment, pool.Status.String())
   197  	eFmt := "mismatch for %s, %s, %s, %s"
   198  	if psr, check := a.reason(); check {
   199  		if pool.StatusReason != psr {
   200  			got = append(got, psr.String, pool.StatusReason.String())
   201  			return fmt.Errorf(eFmt+" expected reason %s - instead got %s", got...)
   202  		}
   203  		got = append(got, psr.String())
   204  		eFmt = eFmt + ", %s"
   205  	}
   206  
   207  	checks := map[string]string{
   208  		"base":           pool.Parameters.Base,
   209  		"lower bound":    ptr.UnBox(pool.Parameters.LowerBound),
   210  		"upper bound":    ptr.UnBox(pool.Parameters.UpperBound),
   211  		"lower leverage": ptr.UnBox(pool.Parameters.LeverageAtLowerBound),
   212  		"upper leverage": ptr.UnBox(pool.Parameters.LeverageAtUpperBound),
   213  	}
   214  
   215  	for name, val := range checks {
   216  		if !a.r.HasColumn(name) {
   217  			if val != "" {
   218  				got = append(got, name, "", val)
   219  				return fmt.Errorf(eFmt+" expected %s %s - instead got %s", got...)
   220  			}
   221  			continue
   222  		}
   223  		if exp := a.r.MustStr(name); val != exp {
   224  			got = append(got, name, exp, val)
   225  			return fmt.Errorf(eFmt+" expected %s %s - instead got %s", got...)
   226  		}
   227  		got = append(got, val)
   228  		eFmt = eFmt + ", %s"
   229  	}
   230  	return nil
   231  }
   232  
   233  func (a ammEvtRow) party() string {
   234  	return a.r.MustStr("party")
   235  }
   236  
   237  func (a ammEvtRow) market() string {
   238  	return a.r.MustStr("market id")
   239  }
   240  
   241  func (a ammEvtRow) status() types.AMMPoolStatus {
   242  	return a.r.MustAMMPoolStatus("status")
   243  }
   244  
   245  func (a ammEvtRow) reason() (types.AMMStatusReason, bool) {
   246  	if !a.r.HasColumn("reason") {
   247  		return types.AMMStatusReasonUnspecified, false
   248  	}
   249  	sr := a.r.MustPoolStatusReason("reason")
   250  	return sr, true
   251  }
   252  
   253  func (a ammEvtRow) alias() string {
   254  	return a.r.MustStr("alias")
   255  }