code.vegaprotocol.io/vega@v0.79.0/core/governance/engine_update_referral_program_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 governance_test 17 18 import ( 19 "testing" 20 "time" 21 22 "code.vegaprotocol.io/vega/core/events" 23 "code.vegaprotocol.io/vega/core/netparams" 24 "code.vegaprotocol.io/vega/core/types" 25 "code.vegaprotocol.io/vega/libs/num" 26 vgrand "code.vegaprotocol.io/vega/libs/rand" 27 vgtest "code.vegaprotocol.io/vega/libs/test" 28 29 "github.com/golang/mock/gomock" 30 "github.com/stretchr/testify/require" 31 ) 32 33 func TestProposalForUpdateReferralProgram(t *testing.T) { 34 t.Run("Submitting a proposal for referral program update succeeds", testSubmittingProposalForReferralProgramUpdateSucceeds) 35 t.Run("Submitting a proposal for referral program update with too many tiers fails", testSubmittingProposalForReferralProgramUpdateWithTooManyTiersFails) 36 t.Run("Submitting a proposal for referral program update with too high reward factor fails", testSubmittingProposalForReferralProgramUpdateWithTooHighRewardFactorFails) 37 t.Run("Submitting a proposal for referral program update with too high discount factor fails", testSubmittingProposalForReferralProgramUpdateWithTooHighDiscountFactorFails) 38 t.Run("Submitting a proposal for referral program that ends before it enacted fails", testSubmittingProposalForReferralProgramUpdateEndsBeforeEnactsFails) 39 } 40 41 func testSubmittingProposalForReferralProgramUpdateSucceeds(t *testing.T) { 42 now := time.Now() 43 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64()) 44 eng := getTestEngine(t, now) 45 46 // setup 47 eng.broker.EXPECT().Send(gomock.Any()).Times(3) 48 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinClose, "48h") 49 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinEnact, "48h") 50 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinProposerBalance, "1000") 51 52 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralTiers, "2")).Times(1) 53 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralTiers, "2")) 54 55 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralRewardFactor, "0.010")).Times(1) 56 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralRewardFactor, "0.010")) 57 58 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralDiscountFactor, "0.010")).Times(1) 59 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralDiscountFactor, "0.010")) 60 61 // given 62 proposer := vgrand.RandomStr(5) 63 proposal := eng.newProposalForReferralProgramUpdate(proposer, now, &types.ReferralProgramChanges{ 64 EndOfProgramTimestamp: now.Add(4 * 48 * time.Hour), 65 WindowLength: 15, 66 BenefitTiers: []*types.BenefitTier{ 67 { 68 MinimumEpochs: num.NewUint(1), 69 MinimumRunningNotionalTakerVolume: num.NewUint(10000), 70 ReferralRewardFactors: types.Factors{ 71 Infra: num.DecimalFromFloat(0.001), 72 Maker: num.DecimalFromFloat(0.001), 73 Liquidity: num.DecimalFromFloat(0.001), 74 }, 75 ReferralDiscountFactors: types.Factors{ 76 Infra: num.DecimalFromFloat(0.001), 77 Maker: num.DecimalFromFloat(0.001), 78 Liquidity: num.DecimalFromFloat(0.001), 79 }, 80 }, { 81 MinimumEpochs: num.NewUint(7), 82 MinimumRunningNotionalTakerVolume: num.NewUint(20000), 83 ReferralRewardFactors: types.Factors{ 84 Infra: num.DecimalFromFloat(0.005), 85 Maker: num.DecimalFromFloat(0.005), 86 Liquidity: num.DecimalFromFloat(0.005), 87 }, 88 ReferralDiscountFactors: types.Factors{ 89 Infra: num.DecimalFromFloat(0.005), 90 Maker: num.DecimalFromFloat(0.005), 91 Liquidity: num.DecimalFromFloat(0.005), 92 }, 93 }, 94 }, 95 }) 96 97 // setup 98 eng.ensureTokenBalanceForParty(t, proposer, 1000) 99 100 // expect 101 eng.expectOpenProposalEvent(t, proposer, proposal.ID) 102 103 // when 104 toSubmit, err := eng.submitProposal(t, proposal) 105 106 // then 107 require.NoError(t, err) 108 require.NotNil(t, toSubmit) 109 } 110 111 // testSubmittingProposalForReferralProgramUpdateWithTooManyTiersFails covers 0095-HVMR-002. 112 func testSubmittingProposalForReferralProgramUpdateWithTooManyTiersFails(t *testing.T) { 113 now := time.Now() 114 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64()) 115 eng := getTestEngine(t, now) 116 117 // setup 118 eng.broker.EXPECT().Send(gomock.Any()).Times(3) 119 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinClose, "48h") 120 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinEnact, "48h") 121 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinProposerBalance, "1000") 122 123 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralTiers, "1")).Times(1) 124 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralTiers, "1")) 125 126 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralRewardFactor, "0.010")).Times(1) 127 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralRewardFactor, "0.010")) 128 129 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralDiscountFactor, "0.010")).Times(1) 130 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralDiscountFactor, "0.010")) 131 132 // given 133 proposer := vgrand.RandomStr(5) 134 proposal := eng.newProposalForReferralProgramUpdate(proposer, now, &types.ReferralProgramChanges{ 135 EndOfProgramTimestamp: now.Add(4 * 48 * time.Hour), 136 WindowLength: 15, 137 BenefitTiers: []*types.BenefitTier{ 138 { 139 MinimumEpochs: num.NewUint(1), 140 MinimumRunningNotionalTakerVolume: num.NewUint(10000), 141 ReferralRewardFactors: types.Factors{ 142 Infra: num.DecimalFromFloat(0.001), 143 Maker: num.DecimalFromFloat(0.001), 144 Liquidity: num.DecimalFromFloat(0.001), 145 }, 146 ReferralDiscountFactors: types.Factors{ 147 Infra: num.DecimalFromFloat(0.001), 148 Maker: num.DecimalFromFloat(0.001), 149 Liquidity: num.DecimalFromFloat(0.001), 150 }, 151 }, { 152 MinimumEpochs: num.NewUint(7), 153 MinimumRunningNotionalTakerVolume: num.NewUint(20000), 154 ReferralRewardFactors: types.Factors{ 155 Infra: num.DecimalFromFloat(0.005), 156 Maker: num.DecimalFromFloat(0.005), 157 Liquidity: num.DecimalFromFloat(0.005), 158 }, 159 ReferralDiscountFactors: types.Factors{ 160 Infra: num.DecimalFromFloat(0.005), 161 Maker: num.DecimalFromFloat(0.005), 162 Liquidity: num.DecimalFromFloat(0.005), 163 }, 164 }, 165 }, 166 }) 167 168 // setup 169 eng.ensureTokenBalanceForParty(t, proposer, 1000) 170 171 // expect 172 eng.expectRejectedProposalEvent(t, proposer, proposal.ID, types.ProposalErrorInvalidReferralProgram) 173 174 // when 175 toSubmit, err := eng.submitProposal(t, proposal) 176 177 // then 178 require.Error(t, err) 179 require.Nil(t, toSubmit) 180 } 181 182 func testSubmittingProposalForReferralProgramUpdateWithTooHighRewardFactorFails(t *testing.T) { 183 now := time.Now() 184 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64()) 185 eng := getTestEngine(t, now) 186 187 // setup 188 eng.broker.EXPECT().Send(gomock.Any()).Times(3) 189 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinClose, "48h") 190 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinEnact, "48h") 191 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinProposerBalance, "1000") 192 193 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralTiers, "2")).Times(1) 194 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralTiers, "2")) 195 196 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralRewardFactor, "0.010")).Times(1) 197 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralRewardFactor, "0.010")) 198 199 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralDiscountFactor, "0.010")).Times(1) 200 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralDiscountFactor, "0.010")) 201 202 // given 203 proposer := vgrand.RandomStr(5) 204 proposal := eng.newProposalForReferralProgramUpdate(proposer, now, &types.ReferralProgramChanges{ 205 EndOfProgramTimestamp: now.Add(4 * 48 * time.Hour), 206 WindowLength: 15, 207 BenefitTiers: []*types.BenefitTier{ 208 { 209 MinimumEpochs: num.NewUint(1), 210 MinimumRunningNotionalTakerVolume: num.NewUint(10000), 211 ReferralRewardFactors: types.Factors{ 212 Infra: num.DecimalFromFloat(0.001), 213 Maker: num.DecimalFromFloat(0.001), 214 Liquidity: num.DecimalFromFloat(0.001), 215 }, 216 ReferralDiscountFactors: types.Factors{ 217 Infra: num.DecimalFromFloat(0.001), 218 Maker: num.DecimalFromFloat(0.001), 219 Liquidity: num.DecimalFromFloat(0.001), 220 }, 221 }, { 222 MinimumEpochs: num.NewUint(7), 223 MinimumRunningNotionalTakerVolume: num.NewUint(20000), 224 ReferralRewardFactors: types.Factors{ 225 Infra: num.DecimalFromFloat(0.015), 226 Maker: num.DecimalFromFloat(0.015), 227 Liquidity: num.DecimalFromFloat(0.015), 228 }, 229 ReferralDiscountFactors: types.Factors{ 230 Infra: num.DecimalFromFloat(0.005), 231 Maker: num.DecimalFromFloat(0.005), 232 Liquidity: num.DecimalFromFloat(0.005), 233 }, 234 }, 235 }, 236 }) 237 238 // setup 239 eng.ensureTokenBalanceForParty(t, proposer, 1000) 240 241 // expect 242 eng.expectRejectedProposalEvent(t, proposer, proposal.ID, types.ProposalErrorInvalidReferralProgram) 243 244 // when 245 toSubmit, err := eng.submitProposal(t, proposal) 246 247 // then 248 require.EqualError(t, 249 err, 250 "tier 2 defines a referral reward infrastructure factor higher than the maximum allowed by the network parameter \"referralProgram.maxReferralRewardFactor\": maximum is 0.01, but got 0.015", 251 ) 252 require.Nil(t, toSubmit) 253 } 254 255 func testSubmittingProposalForReferralProgramUpdateWithTooHighDiscountFactorFails(t *testing.T) { 256 now := time.Now() 257 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64()) 258 eng := getTestEngine(t, now) 259 260 // setup 261 eng.broker.EXPECT().Send(gomock.Any()).Times(3) 262 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinClose, "48h") 263 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinEnact, "48h") 264 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinProposerBalance, "1000") 265 266 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralTiers, "2")).Times(1) 267 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralTiers, "2")) 268 269 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralRewardFactor, "0.010")).Times(1) 270 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralRewardFactor, "0.010")) 271 272 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralDiscountFactor, "0.010")).Times(1) 273 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralDiscountFactor, "0.010")) 274 275 // given 276 proposer := vgrand.RandomStr(5) 277 proposal := eng.newProposalForReferralProgramUpdate(proposer, now, &types.ReferralProgramChanges{ 278 EndOfProgramTimestamp: now.Add(4 * 48 * time.Hour), 279 WindowLength: 15, 280 BenefitTiers: []*types.BenefitTier{ 281 { 282 MinimumEpochs: num.NewUint(1), 283 MinimumRunningNotionalTakerVolume: num.NewUint(10000), 284 ReferralRewardFactors: types.Factors{ 285 Infra: num.DecimalFromFloat(0.001), 286 Maker: num.DecimalFromFloat(0.001), 287 Liquidity: num.DecimalFromFloat(0.001), 288 }, 289 ReferralDiscountFactors: types.Factors{ 290 Infra: num.DecimalFromFloat(0.001), 291 Maker: num.DecimalFromFloat(0.001), 292 Liquidity: num.DecimalFromFloat(0.001), 293 }, 294 }, { 295 MinimumEpochs: num.NewUint(7), 296 MinimumRunningNotionalTakerVolume: num.NewUint(20000), 297 ReferralRewardFactors: types.Factors{ 298 Infra: num.DecimalFromFloat(0.01), 299 Maker: num.DecimalFromFloat(0.01), 300 Liquidity: num.DecimalFromFloat(0.01), 301 }, 302 ReferralDiscountFactors: types.Factors{ 303 Infra: num.DecimalFromFloat(0.015), 304 Maker: num.DecimalFromFloat(0.015), 305 Liquidity: num.DecimalFromFloat(0.015), 306 }, 307 }, 308 }, 309 }) 310 311 // setup 312 eng.ensureTokenBalanceForParty(t, proposer, 1000) 313 314 // expect 315 eng.expectRejectedProposalEvent(t, proposer, proposal.ID, types.ProposalErrorInvalidReferralProgram) 316 317 // when 318 toSubmit, err := eng.submitProposal(t, proposal) 319 320 // then 321 require.EqualError(t, 322 err, 323 "tier 2 defines a referral discount infrastructure factor higher than the maximum allowed by the network parameter \"referralProgram.maxReferralDiscountFactor\": maximum is 0.01, but got 0.015", 324 ) 325 require.Nil(t, toSubmit) 326 } 327 328 // testSubmittingProposalForReferralProgramUpdateEndsBeforeEnactsFails covers 0095-HVMR-001. 329 func testSubmittingProposalForReferralProgramUpdateEndsBeforeEnactsFails(t *testing.T) { 330 now := time.Now() 331 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64()) 332 eng := getTestEngine(t, now) 333 334 // setup 335 eng.broker.EXPECT().Send(gomock.Any()).Times(3) 336 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinClose, "48h") 337 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinEnact, "48h") 338 eng.netp.Update(ctx, netparams.GovernanceProposalReferralProgramMinProposerBalance, "1000") 339 340 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralTiers, "2")).Times(1) 341 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralTiers, "2")) 342 343 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralRewardFactor, "0.010")).Times(1) 344 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralRewardFactor, "0.010")) 345 346 eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.ReferralProgramMaxReferralDiscountFactor, "0.010")).Times(1) 347 require.NoError(t, eng.netp.Update(ctx, netparams.ReferralProgramMaxReferralDiscountFactor, "0.010")) 348 349 // given 350 proposer := vgrand.RandomStr(5) 351 rp := &types.ProposalTermsUpdateReferralProgram{ 352 UpdateReferralProgram: &types.UpdateReferralProgram{ 353 Changes: &types.ReferralProgramChanges{ 354 EndOfProgramTimestamp: time.Time{}, // we will set this later 355 WindowLength: 15, 356 BenefitTiers: []*types.BenefitTier{ 357 { 358 MinimumEpochs: num.NewUint(1), 359 MinimumRunningNotionalTakerVolume: num.NewUint(10000), 360 ReferralRewardFactors: types.Factors{ 361 Infra: num.DecimalFromFloat(0.001), 362 Maker: num.DecimalFromFloat(0.001), 363 Liquidity: num.DecimalFromFloat(0.001), 364 }, 365 ReferralDiscountFactors: types.Factors{ 366 Infra: num.DecimalFromFloat(0.001), 367 Maker: num.DecimalFromFloat(0.001), 368 Liquidity: num.DecimalFromFloat(0.001), 369 }, 370 }, { 371 MinimumEpochs: num.NewUint(7), 372 MinimumRunningNotionalTakerVolume: num.NewUint(20000), 373 ReferralRewardFactors: types.Factors{ 374 Infra: num.DecimalFromFloat(0.01), 375 Maker: num.DecimalFromFloat(0.01), 376 Liquidity: num.DecimalFromFloat(0.01), 377 }, 378 ReferralDiscountFactors: types.Factors{ 379 Infra: num.DecimalFromFloat(0.015), 380 Maker: num.DecimalFromFloat(0.015), 381 Liquidity: num.DecimalFromFloat(0.015), 382 }, 383 }, 384 }, 385 }, 386 }, 387 } 388 proposal := eng.newProposalForReferralProgramUpdate(proposer, now, rp.UpdateReferralProgram.Changes) 389 rp.UpdateReferralProgram.Changes.EndOfProgramTimestamp = time.Unix(proposal.Terms.EnactmentTimestamp, 0).Add(-time.Second) // set to end before enacted 390 proposal.Terms.Change = rp 391 392 // setup 393 eng.ensureTokenBalanceForParty(t, proposer, 1000) 394 395 // expect 396 eng.expectRejectedProposalEvent(t, proposer, proposal.ID, types.ProposalErrorInvalidReferralProgram) 397 398 // when 399 toSubmit, err := eng.submitProposal(t, proposal) 400 401 // then 402 require.EqualError(t, 403 err, 404 "the proposal must be enacted before the referral program ends", 405 ) 406 require.Nil(t, toSubmit) 407 }