code.vegaprotocol.io/vega@v0.79.0/core/referral/notional_volumes.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 referral
    17  
    18  import (
    19  	"code.vegaprotocol.io/vega/core/types"
    20  	"code.vegaprotocol.io/vega/libs/num"
    21  )
    22  
    23  type runningVolumes struct {
    24  	// maxPartyNotionalVolumeByQuantumPerEpoch limits the volume in quantum units
    25  	// which is eligible each epoch for referral program mechanisms.
    26  	maxPartyNotionalVolumeByQuantumPerEpoch *num.Uint
    27  
    28  	// runningVolumesBySet tracks the running notional volume by referralSets.
    29  	runningVolumesBySet map[types.ReferralSetID][]*notionalVolume
    30  }
    31  
    32  type notionalVolume struct {
    33  	epoch uint64
    34  	value *num.Uint
    35  }
    36  
    37  func (vs *runningVolumes) Add(epoch uint64, setID types.ReferralSetID, volume *num.Uint) {
    38  	volumeToAdd := volume
    39  	if volume.GT(vs.maxPartyNotionalVolumeByQuantumPerEpoch) {
    40  		volumeToAdd = vs.maxPartyNotionalVolumeByQuantumPerEpoch
    41  	}
    42  
    43  	runningVolumeForSet, isTracked := vs.runningVolumesBySet[setID]
    44  	if !isTracked {
    45  		vs.runningVolumesBySet[setID] = []*notionalVolume{
    46  			{
    47  				epoch: epoch,
    48  				value: volumeToAdd.Clone(),
    49  			},
    50  		}
    51  		return
    52  	}
    53  
    54  	notionalVolumeForEpoch := runningVolumeForSet[len(runningVolumeForSet)-1]
    55  	if notionalVolumeForEpoch.epoch == epoch {
    56  		notionalVolumeForEpoch.value.AddSum(volumeToAdd)
    57  		return
    58  	}
    59  
    60  	// If we end up here, it means this set is tracked but this epoch is not.
    61  	vs.runningVolumesBySet[setID] = append(runningVolumeForSet, &notionalVolume{
    62  		epoch: epoch,
    63  		value: volumeToAdd.Clone(),
    64  	})
    65  }
    66  
    67  func (vs *runningVolumes) RunningSetVolumeForWindow(setID types.ReferralSetID, window uint64) *num.Uint {
    68  	runningVolumeSet, isTracked := vs.runningVolumesBySet[setID]
    69  	if !isTracked {
    70  		return num.UintZero()
    71  	}
    72  
    73  	trackedEpochsCount := uint64(len(runningVolumeSet))
    74  	startIndex := uint64(0)
    75  	if trackedEpochsCount > window {
    76  		startIndex = trackedEpochsCount - window
    77  	}
    78  
    79  	runningVolumeForWindow := num.UintZero()
    80  	for i := startIndex; i < trackedEpochsCount; i++ {
    81  		runningVolumeForWindow.AddSum(runningVolumeSet[i].value)
    82  	}
    83  
    84  	return runningVolumeForWindow
    85  }
    86  
    87  func (vs *runningVolumes) RemovePriorEpoch(epoch uint64) {
    88  	for setID, volumes := range vs.runningVolumesBySet {
    89  		removeBeforeIndex := len(volumes) - 1
    90  		for i := len(volumes) - 1; i >= 0; i-- {
    91  			if volumes[i].epoch < epoch {
    92  				break
    93  			}
    94  			removeBeforeIndex -= 1
    95  		}
    96  
    97  		if removeBeforeIndex == len(volumes)-1 {
    98  			vs.runningVolumesBySet[setID] = []*notionalVolume{}
    99  		} else if removeBeforeIndex >= 0 {
   100  			vs.runningVolumesBySet[setID] = volumes[removeBeforeIndex:]
   101  		}
   102  	}
   103  }
   104  
   105  func newRunningVolumes() *runningVolumes {
   106  	return &runningVolumes{
   107  		maxPartyNotionalVolumeByQuantumPerEpoch: num.UintZero(),
   108  		runningVolumesBySet:                     map[types.ReferralSetID][]*notionalVolume{},
   109  	}
   110  }