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, ¬ionalVolume{ 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 }