code.vegaprotocol.io/vega@v0.79.0/core/integration/steps/volume_rebate_program.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  	"time"
    21  
    22  	"code.vegaprotocol.io/vega/core/integration/stubs"
    23  	"code.vegaprotocol.io/vega/core/types"
    24  	"code.vegaprotocol.io/vega/core/volumerebate"
    25  	"code.vegaprotocol.io/vega/libs/num"
    26  
    27  	"github.com/cucumber/godog"
    28  )
    29  
    30  func VolumeRebateProgramTiers(
    31  	tiers map[string][]*types.VolumeRebateBenefitTier,
    32  	volumeRebateTierName string,
    33  	table *godog.Table,
    34  ) error {
    35  	rows := parseVolumeRebateTiersTable(table)
    36  	vbts := make([]*types.VolumeRebateBenefitTier, 0, len(rows))
    37  	for _, r := range rows {
    38  		row := volumeRebateTiersRow{row: r}
    39  		p := &types.VolumeRebateBenefitTier{
    40  			MinimumPartyMakerVolumeFraction: row.fraction(),
    41  			AdditionalMakerRebate:           row.rebate(),
    42  		}
    43  
    44  		vbts = append(vbts, p)
    45  	}
    46  	tiers[volumeRebateTierName] = vbts
    47  	return nil
    48  }
    49  
    50  func parseVolumeRebateTiersTable(table *godog.Table) []RowWrapper {
    51  	return StrictParseTable(table, []string{
    52  		"fraction",
    53  		"rebate",
    54  	}, []string{})
    55  }
    56  
    57  type volumeRebateTiersRow struct {
    58  	row RowWrapper
    59  }
    60  
    61  func (r volumeRebateTiersRow) fraction() num.Decimal {
    62  	return r.row.MustDecimal("fraction")
    63  }
    64  
    65  func (r volumeRebateTiersRow) rebate() num.Decimal {
    66  	return r.row.MustDecimal("rebate")
    67  }
    68  
    69  func VolumeRebateProgram(
    70  	vde *volumerebate.Engine,
    71  	tiers map[string][]*types.VolumeRebateBenefitTier,
    72  	ts *stubs.TimeStub,
    73  	table *godog.Table,
    74  ) error {
    75  	rows := parseVolumeRebateTable(table)
    76  	vdp := types.VolumeRebateProgram{}
    77  
    78  	for _, r := range rows {
    79  		row := volumeRebateRow{row: r}
    80  		vdp.ID = row.id()
    81  		vdp.WindowLength = row.windowLength()
    82  		vdp.EndOfProgramTimestamp = row.closingTS(ts.GetTimeNow())
    83  		tierName := row.tiers()
    84  		if tier := tiers[tierName]; tier != nil {
    85  			vdp.VolumeRebateBenefitTiers = tier
    86  		}
    87  		vde.UpdateProgram(&vdp)
    88  	}
    89  	return nil
    90  }
    91  
    92  func parseVolumeRebateTable(table *godog.Table) []RowWrapper {
    93  	return StrictParseTable(table, []string{
    94  		"id",
    95  		"tiers",
    96  		"closing timestamp",
    97  		"window length",
    98  	}, []string{
    99  		"closing delta",
   100  	})
   101  }
   102  
   103  type volumeRebateRow struct {
   104  	row RowWrapper
   105  }
   106  
   107  func (r volumeRebateRow) id() string {
   108  	return r.row.MustStr("id")
   109  }
   110  
   111  func (r volumeRebateRow) tiers() string {
   112  	return r.row.MustStr("tiers")
   113  }
   114  
   115  func (r volumeRebateRow) closingTimestamp() int64 {
   116  	return r.row.MustI64("closing timestamp")
   117  }
   118  
   119  func (r volumeRebateRow) closingTS(now time.Time) time.Time {
   120  	if delta, ok := r.closingDelta(); ok {
   121  		return now.Add(delta)
   122  	}
   123  	ts := r.closingTimestamp()
   124  	if ts == 0 {
   125  		return time.Time{}
   126  	}
   127  	return time.Unix(ts, 0)
   128  }
   129  
   130  func (r volumeRebateRow) closingDelta() (time.Duration, bool) {
   131  	if r.row.HasColumn("closing delta") {
   132  		return r.row.MustDurationStr("closing delta"), true
   133  	}
   134  	return 0, false
   135  }
   136  
   137  func (r volumeRebateRow) windowLength() uint64 {
   138  	return r.row.MustU64("window length")
   139  }
   140  
   141  func PartyHasTheFollowingRebate(party, RebateFactor string, vde *volumerebate.Engine) error {
   142  	df := vde.VolumeRebateFactorForParty(types.PartyID(party))
   143  	df2, _ := num.DecimalFromString(RebateFactor)
   144  	if !df.Equal(df2) {
   145  		return fmt.Errorf("%s has the Rebate of %s when we expected %s", party, df, df2)
   146  	}
   147  	return nil
   148  }
   149  
   150  func PartyHasTheFollowingMakerVolumeFraction(party, fraction string, vde *volumerebate.Engine) error {
   151  	tn := vde.MakerVolumeFractionForParty(types.PartyID(party))
   152  	tn2, _ := num.DecimalFromString(fraction)
   153  	if !tn.Equal(tn2) {
   154  		return fmt.Errorf("%s has the maker volume fraction of %s when we expected %s", party, tn, tn2)
   155  	}
   156  	return nil
   157  }
   158  
   159  func AMMHasTheFollowingMakerVolumeFraction(exec Execution, vde *volumerebate.Engine, alias, value string) error {
   160  	id, ok := exec.GetAMMSubAccountID(alias)
   161  	if !ok {
   162  		return fmt.Errorf("unknown vAMM alias %s", alias)
   163  	}
   164  	// from this point, it's the same as for a normal party
   165  	return PartyHasTheFollowingMakerVolumeFraction(id, value, vde)
   166  }
   167  
   168  func AMMHasTheFollowingRebate(exec Execution, vde *volumerebate.Engine, alias, factor string) error {
   169  	id, ok := exec.GetAMMSubAccountID(alias)
   170  	if !ok {
   171  		return fmt.Errorf("unknown vAMM alias %s", alias)
   172  	}
   173  	return PartyHasTheFollowingRebate(id, factor, vde)
   174  }