code.vegaprotocol.io/vega@v0.79.0/core/liquidity/target/spot/engine_test.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 spot_test 17 18 import ( 19 "testing" 20 "time" 21 22 "code.vegaprotocol.io/vega/core/liquidity/target/spot" 23 "code.vegaprotocol.io/vega/core/types" 24 "code.vegaprotocol.io/vega/libs/num" 25 26 "github.com/stretchr/testify/require" 27 ) 28 29 var ( 30 now = time.Date(2020, 10, 30, 9, 0, 0, 0, time.UTC) 31 marketID = "market-1" 32 ) 33 34 func TestConstructor(t *testing.T) { 35 params := types.TargetStakeParameters{TimeWindow: 3600, ScalingFactor: num.DecimalFromFloat(10)} 36 engine := spot.NewEngine(params, marketID, num.DecimalFromFloat(1)) 37 38 require.NotNil(t, engine) 39 } 40 41 func TestTotalStake(t *testing.T) { 42 params := types.TargetStakeParameters{TimeWindow: 3600, ScalingFactor: num.DecimalFromFloat(10)} 43 engine := spot.NewEngine(params, marketID, num.DecimalFromFloat(1)) 44 err := engine.RecordTotalStake(9, now) 45 require.NoError(t, err) 46 err = engine.RecordTotalStake(0, now) 47 require.NoError(t, err) 48 err = engine.RecordTotalStake(11, now.Add(time.Nanosecond)) 49 require.NoError(t, err) 50 err = engine.RecordTotalStake(12, now.Add(time.Nanosecond)) 51 require.NoError(t, err) 52 err = engine.RecordTotalStake(13, now.Add(-2*time.Nanosecond)) 53 require.Error(t, err) 54 } 55 56 func TestGetTargetStake_NoRecordedTotalStake(t *testing.T) { 57 params := types.TargetStakeParameters{TimeWindow: 3600, ScalingFactor: num.DecimalFromFloat(10)} 58 engine := spot.NewEngine(params, marketID, num.DecimalFromFloat(1)) 59 targetStake := engine.GetTargetStake(now) 60 require.Equal(t, num.UintZero(), targetStake) 61 } 62 63 func TestGetTargetStake_VerifyMaxOI(t *testing.T) { 64 tWindow := 60 * time.Minute 65 scalingFactor := num.DecimalFromFloat(0.25) 66 params := types.TargetStakeParameters{TimeWindow: int64(tWindow.Seconds()), ScalingFactor: scalingFactor} 67 expectedTargetStake := func(oi uint64) *num.Uint { 68 mp := num.NewUint(oi).ToDecimal().Mul(scalingFactor) 69 ump, _ := num.UintFromDecimal(mp) 70 return ump 71 } 72 73 engine := spot.NewEngine(params, marketID, num.DecimalFromFloat(1)) 74 75 // Max in current time 76 var maxOI uint64 = 23 77 err := engine.RecordTotalStake(maxOI, now) 78 require.NoError(t, err) 79 actualTargetStake1 := engine.GetTargetStake(now) 80 actualTargetStake2 := engine.GetTargetStake(now.Add(time.Minute)) 81 82 exp := expectedTargetStake(maxOI) 83 require.Equal(t, exp, actualTargetStake1) 84 require.Equal(t, exp, actualTargetStake2) 85 // Max in past 86 now = now.Add(time.Nanosecond) 87 err = engine.RecordTotalStake(maxOI-1, now) 88 require.NoError(t, err) 89 actualTargetStake1 = engine.GetTargetStake(now) 90 actualTargetStake2 = engine.GetTargetStake(now.Add(time.Minute)) 91 92 exp = expectedTargetStake(maxOI) 93 require.Equal(t, exp, actualTargetStake1) 94 require.Equal(t, exp, actualTargetStake2) 95 96 // Max in current time 97 now = now.Add(time.Second) 98 maxOI = 10 * maxOI 99 err = engine.RecordTotalStake(maxOI, now) 100 require.NoError(t, err) 101 actualTargetStake1 = engine.GetTargetStake(now) 102 actualTargetStake2 = engine.GetTargetStake(now.Add(time.Minute)) 103 104 exp = expectedTargetStake(maxOI) 105 require.Equal(t, exp, actualTargetStake1) 106 require.Equal(t, exp, actualTargetStake2) 107 108 // Max in past, move time beyond window, don't update OI, max OI should be the last recorded value 109 now = now.Add(time.Minute) 110 var lastRecordedValue uint64 = 1 111 err = engine.RecordTotalStake(lastRecordedValue, now) 112 require.NoError(t, err) 113 now = now.Add(3 * tWindow) 114 actualTargetStake1 = engine.GetTargetStake(now) 115 actualTargetStake2 = engine.GetTargetStake(now.Add(time.Minute)) 116 117 exp = expectedTargetStake(lastRecordedValue) 118 require.Equal(t, exp, actualTargetStake1) 119 require.Equal(t, exp, actualTargetStake2) 120 121 // Max in past with smaller value after it, move time beyond window so that the current max gets dropped, now target stake should be based on next value 122 now = now.Add(time.Minute) 123 var penultimateValue uint64 = 1000 124 err = engine.RecordTotalStake(penultimateValue, now) 125 require.NoError(t, err) 126 // Half a time window 127 now = now.Add(30 * time.Minute) 128 lastRecordedValue = 5 129 err = engine.RecordTotalStake(lastRecordedValue, now) 130 require.NoError(t, err) 131 // Move entire time window and a bit 132 now = now.Add(61 * time.Minute) 133 actualTargetStake1 = engine.GetTargetStake(now) 134 actualTargetStake2 = engine.GetTargetStake(now.Add(time.Minute)) 135 136 exp = expectedTargetStake(lastRecordedValue) 137 require.Equal(t, exp, actualTargetStake1) 138 require.Equal(t, exp, actualTargetStake2) 139 140 // Max in past with OI of 0 value after it, move time beyond window so that the current max gets dropped, now target stake should be 0 141 now = now.Add(time.Minute) 142 penultimateValue = 1000 143 err = engine.RecordTotalStake(penultimateValue, now) 144 require.NoError(t, err) 145 // Half a time window 146 now = now.Add(30 * time.Minute) 147 lastRecordedValueIsZero := uint64(0) 148 err = engine.RecordTotalStake(lastRecordedValueIsZero, now) 149 require.NoError(t, err) 150 // Move entire time window and a bit 151 now = now.Add(61 * time.Minute) 152 actualTargetStake1 = engine.GetTargetStake(now) 153 actualTargetStake2 = engine.GetTargetStake(now.Add(time.Minute)) 154 155 exp = expectedTargetStake(lastRecordedValueIsZero) 156 require.Equal(t, exp, actualTargetStake1) 157 require.Equal(t, exp, actualTargetStake2) 158 }