code.vegaprotocol.io/vega@v0.79.0/core/integration/steps/amm_submission.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  	"context"
    20  	"fmt"
    21  
    22  	"code.vegaprotocol.io/vega/core/types"
    23  	"code.vegaprotocol.io/vega/libs/num"
    24  	"code.vegaprotocol.io/vega/libs/ptr"
    25  
    26  	"github.com/cucumber/godog"
    27  )
    28  
    29  func PartiesSubmitTheFollowingAMMs(exec Execution, table *godog.Table) error {
    30  	ctx := context.Background()
    31  	for _, r := range parseSubmitAMMTable(table) {
    32  		row := ammRow{
    33  			r: r,
    34  		}
    35  		fail, eStr := row.err()
    36  		if err := exec.SubmitAMM(ctx, row.toSubmission()); err != nil {
    37  			if !fail {
    38  				return err
    39  			}
    40  			if err.Error() != eStr {
    41  				return fmt.Errorf("expected error %s, instead got: %s (%v)", eStr, err.Error(), err)
    42  			}
    43  		}
    44  	}
    45  	return nil
    46  }
    47  
    48  func PartiesAmendTheFollowingAMMs(exec Execution, table *godog.Table) error {
    49  	ctx := context.Background()
    50  	for _, r := range parseAmendAMMTable(table) {
    51  		row := ammRow{
    52  			r:       r,
    53  			isAmend: true,
    54  		}
    55  		fail, eStr := row.err()
    56  		if err := exec.AmendAMM(ctx, row.toAmendment()); err != nil {
    57  			if !fail {
    58  				return err
    59  			}
    60  			if err.Error() != eStr {
    61  				return fmt.Errorf("expected error %s, instead got: %s (%v)", eStr, err.Error(), err)
    62  			}
    63  		}
    64  	}
    65  	return nil
    66  }
    67  
    68  func PartiesCancelTheFollowingAMMs(exec Execution, table *godog.Table) error {
    69  	ctx := context.Background()
    70  	for _, r := range parseCancelAMMTable(table) {
    71  		row := ammRow{
    72  			r: r,
    73  		}
    74  		fail, eStr := row.err()
    75  		if err := exec.CancelAMM(ctx, row.toCancel()); err != nil {
    76  			if !fail {
    77  				return err
    78  			}
    79  			if err.Error() != eStr {
    80  				return fmt.Errorf("expected error %s, instead got: %s (%v)", eStr, err.Error(), err)
    81  			}
    82  		}
    83  	}
    84  	return nil
    85  }
    86  
    87  func parseSubmitAMMTable(table *godog.Table) []RowWrapper {
    88  	return StrictParseTable(table, []string{
    89  		"party",        // str
    90  		"market id",    // str
    91  		"amount",       // uint
    92  		"slippage",     // dec
    93  		"base",         // uint
    94  		"proposed fee", // dec
    95  	}, []string{
    96  		"lower bound",    // uint
    97  		"upper bound",    // uint
    98  		"lower leverage", // dec
    99  		"upper leverage", // dec
   100  		"data source id",
   101  		"minimum price change trigger",
   102  		"error",
   103  	})
   104  }
   105  
   106  func parseAmendAMMTable(table *godog.Table) []RowWrapper {
   107  	return StrictParseTable(table, []string{
   108  		"party",     // str
   109  		"market id", // str
   110  		"slippage",  // dec
   111  	}, []string{
   112  		"proposed fee",   // dec
   113  		"amount",         // uint
   114  		"base",           // uint
   115  		"lower bound",    // uint
   116  		"upper bound",    // uint
   117  		"lower leverage", // dec
   118  		"upper leverage", // dec
   119  		"data source id",
   120  		"minimum price change trigger",
   121  		"error",
   122  	})
   123  }
   124  
   125  func parseCancelAMMTable(table *godog.Table) []RowWrapper {
   126  	return StrictParseTable(table, []string{
   127  		"party",
   128  		"market id",
   129  		"method",
   130  	}, []string{
   131  		"error",
   132  	})
   133  }
   134  
   135  type ammRow struct {
   136  	r       RowWrapper
   137  	isAmend bool
   138  }
   139  
   140  func (a ammRow) toSubmission() *types.SubmitAMM {
   141  	if !a.r.HasColumn("lower bound") && !a.r.HasColumn("upper bound") {
   142  		panic("required at least one upper bound and lower bound")
   143  	}
   144  
   145  	return &types.SubmitAMM{
   146  		AMMBaseCommand: types.AMMBaseCommand{
   147  			MarketID:                  a.marketID(),
   148  			Party:                     a.party(),
   149  			SlippageTolerance:         a.slippage(),
   150  			ProposedFee:               a.proposedFee(),
   151  			MinimumPriceChangeTrigger: a.minimumPriceChangeTrigger(),
   152  		},
   153  		CommitmentAmount: a.amount(),
   154  		Parameters: &types.ConcentratedLiquidityParameters{
   155  			Base:                 a.base(),
   156  			LowerBound:           a.lowerBound(),
   157  			UpperBound:           a.upperBound(),
   158  			LeverageAtLowerBound: a.lowerLeverage(),
   159  			LeverageAtUpperBound: a.upperLeverage(),
   160  			DataSourceID:         a.dataSourceID(),
   161  		},
   162  	}
   163  }
   164  
   165  func (a ammRow) toAmendment() *types.AmendAMM {
   166  	ret := &types.AmendAMM{
   167  		AMMBaseCommand: types.AMMBaseCommand{
   168  			MarketID:                  a.marketID(),
   169  			Party:                     a.party(),
   170  			SlippageTolerance:         a.slippage(),
   171  			ProposedFee:               a.proposedFee(),
   172  			MinimumPriceChangeTrigger: a.minimumPriceChangeTrigger(),
   173  		},
   174  	}
   175  	if a.r.HasColumn("amount") {
   176  		ret.CommitmentAmount = a.amount()
   177  	}
   178  	params := &types.ConcentratedLiquidityParameters{
   179  		DataSourceID: a.dataSourceID(),
   180  	}
   181  	paramSet := false
   182  	if a.r.HasColumn("base") {
   183  		params.Base = a.base()
   184  		paramSet = true
   185  	}
   186  	if a.r.HasColumn("lower bound") {
   187  		params.LowerBound = a.lowerBound()
   188  		paramSet = true
   189  	}
   190  	if a.r.HasColumn("upper bound") {
   191  		params.UpperBound = a.upperBound()
   192  		paramSet = true
   193  	}
   194  	if a.r.HasColumn("lower leverage") {
   195  		params.LeverageAtLowerBound = a.lowerLeverage()
   196  		paramSet = true
   197  	}
   198  	if a.r.HasColumn("upper leverage") {
   199  		params.LeverageAtUpperBound = a.upperLeverage()
   200  		paramSet = true
   201  	}
   202  	if paramSet {
   203  		ret.Parameters = params
   204  	}
   205  	return ret
   206  }
   207  
   208  func (a ammRow) toCancel() *types.CancelAMM {
   209  	return &types.CancelAMM{
   210  		MarketID: a.marketID(),
   211  		Party:    a.party(),
   212  		Method:   a.method(),
   213  	}
   214  }
   215  
   216  func (a ammRow) party() string {
   217  	return a.r.MustStr("party")
   218  }
   219  
   220  func (a ammRow) marketID() string {
   221  	return a.r.MustStr("market id")
   222  }
   223  
   224  func (a ammRow) proposedFee() num.Decimal {
   225  	if !a.isAmend {
   226  		return a.r.MustDecimal("proposed fee")
   227  	}
   228  
   229  	if a.r.HasColumn("proposed fee") {
   230  		return a.r.MustDecimal("proposed fee")
   231  	}
   232  	return num.DecimalZero()
   233  }
   234  
   235  func (a ammRow) amount() *num.Uint {
   236  	return a.r.MustUint("amount")
   237  }
   238  
   239  func (a ammRow) slippage() num.Decimal {
   240  	return a.r.MustDecimal("slippage")
   241  }
   242  
   243  func (a ammRow) base() *num.Uint {
   244  	return a.r.MustUint("base")
   245  }
   246  
   247  func (a ammRow) lowerBound() *num.Uint {
   248  	if !a.r.HasColumn("lower bound") {
   249  		return nil
   250  	}
   251  	return a.r.MustUint("lower bound")
   252  }
   253  
   254  func (a ammRow) upperBound() *num.Uint {
   255  	if !a.r.HasColumn("upper bound") {
   256  		return nil
   257  	}
   258  	return a.r.MustUint("upper bound")
   259  }
   260  
   261  func (a ammRow) dataSourceID() *string {
   262  	if !a.r.HasColumn("data source id") {
   263  		return nil
   264  	}
   265  	return ptr.From(a.r.Str("data source id"))
   266  }
   267  
   268  func (a ammRow) minimumPriceChangeTrigger() num.Decimal {
   269  	if !a.r.HasColumn("minimum price change trigger") {
   270  		return num.DecimalZero()
   271  	}
   272  	return a.r.MustDecimal("minimum price change trigger")
   273  }
   274  
   275  func (a ammRow) lowerLeverage() *num.Decimal {
   276  	if !a.r.HasColumn("lower leverage") {
   277  		return nil
   278  	}
   279  	return ptr.From(a.r.MustDecimal("lower leverage"))
   280  }
   281  
   282  func (a ammRow) upperLeverage() *num.Decimal {
   283  	if !a.r.HasColumn("upper leverage") {
   284  		return nil
   285  	}
   286  	return ptr.From(a.r.MustDecimal("upper leverage"))
   287  }
   288  
   289  func (a ammRow) method() types.AMMCancellationMethod {
   290  	if !a.r.HasColumn("method") {
   291  		return types.AMMCancellationMethodUnspecified
   292  	}
   293  	return a.r.MustAMMCancelationMethod("method")
   294  }
   295  
   296  func (a ammRow) err() (bool, string) {
   297  	if !a.r.HasColumn("error") {
   298  		return false, ""
   299  	}
   300  	str := a.r.MustStr("error")
   301  	return true, str
   302  }