code.vegaprotocol.io/vega@v0.79.0/datanode/sqlstore/referral_programs_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 sqlstore_test 17 18 import ( 19 "testing" 20 "time" 21 22 "code.vegaprotocol.io/vega/datanode/entities" 23 "code.vegaprotocol.io/vega/datanode/sqlstore" 24 "code.vegaprotocol.io/vega/libs/ptr" 25 "code.vegaprotocol.io/vega/protos/vega" 26 eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1" 27 28 "github.com/georgysavva/scany/pgxscan" 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/require" 31 ) 32 33 func setupReferralProgramTest(t *testing.T) (*sqlstore.Blocks, *sqlstore.ReferralPrograms) { 34 t.Helper() 35 36 bs := sqlstore.NewBlocks(connectionSource) 37 rs := sqlstore.NewReferralPrograms(connectionSource) 38 39 return bs, rs 40 } 41 42 func TestReferralPrograms_AddReferralProgram(t *testing.T) { 43 bs, rs := setupReferralProgramTest(t) 44 ctx := tempTransaction(t) 45 46 block := addTestBlock(t, ctx, bs) 47 block2 := addTestBlock(t, ctx, bs) 48 49 t.Run("AddReferralProgram should create a new referral program record", func(t *testing.T) { 50 endTime := block.VegaTime.Add(time.Hour) 51 endTime2 := block2.VegaTime.Add(time.Hour) 52 53 programs := []*eventspb.ReferralProgramStarted{ 54 { 55 Program: &vega.ReferralProgram{ 56 Version: 1, 57 Id: GenerateID(), 58 BenefitTiers: []*vega.BenefitTier{ 59 { 60 MinimumRunningNotionalTakerVolume: "1000", 61 MinimumEpochs: "10", 62 ReferralRewardFactor: "0.0001", 63 ReferralDiscountFactor: "0.0001", 64 ReferralRewardFactors: &vega.RewardFactors{ 65 InfrastructureRewardFactor: "0.00002", 66 LiquidityRewardFactor: "0.00004", 67 MakerRewardFactor: "0.00004", 68 }, 69 ReferralDiscountFactors: &vega.DiscountFactors{ 70 InfrastructureDiscountFactor: "0.00002", 71 LiquidityDiscountFactor: "0.00004", 72 MakerDiscountFactor: "0.00004", 73 }, 74 TierNumber: ptr.From(uint64(1)), 75 }, 76 { 77 MinimumRunningNotionalTakerVolume: "10000", 78 MinimumEpochs: "100", 79 ReferralRewardFactor: "0.001", 80 ReferralDiscountFactor: "0.001", 81 ReferralRewardFactors: &vega.RewardFactors{ 82 InfrastructureRewardFactor: "0.0002", 83 LiquidityRewardFactor: "0.0004", 84 MakerRewardFactor: "0.0004", 85 }, 86 ReferralDiscountFactors: &vega.DiscountFactors{ 87 InfrastructureDiscountFactor: "0.0002", 88 LiquidityDiscountFactor: "0.0004", 89 MakerDiscountFactor: "0.0004", 90 }, 91 TierNumber: ptr.From(uint64(2)), 92 }, 93 }, 94 EndOfProgramTimestamp: endTime.Unix(), 95 WindowLength: 100, 96 StakingTiers: []*vega.StakingTier{ 97 { 98 MinimumStakedTokens: "1000", 99 ReferralRewardMultiplier: "1.0", 100 }, 101 { 102 MinimumStakedTokens: "10000", 103 ReferralRewardMultiplier: "1.1", 104 }, 105 }, 106 }, 107 }, 108 { 109 Program: &vega.ReferralProgram{ 110 Version: 1, 111 Id: GenerateID(), 112 BenefitTiers: []*vega.BenefitTier{ 113 { 114 MinimumRunningNotionalTakerVolume: "2000", 115 MinimumEpochs: "20", 116 ReferralRewardFactor: "0.0002", 117 ReferralDiscountFactor: "0.0002", 118 ReferralRewardFactors: &vega.RewardFactors{ 119 InfrastructureRewardFactor: "0.00004", 120 LiquidityRewardFactor: "0.00008", 121 MakerRewardFactor: "0.00008", 122 }, 123 ReferralDiscountFactors: &vega.DiscountFactors{ 124 InfrastructureDiscountFactor: "0.00004", 125 LiquidityDiscountFactor: "0.00008", 126 MakerDiscountFactor: "0.00008", 127 }, 128 TierNumber: ptr.From(uint64(1)), 129 }, 130 { 131 MinimumRunningNotionalTakerVolume: "20000", 132 MinimumEpochs: "200", 133 ReferralRewardFactor: "0.002", 134 ReferralDiscountFactor: "0.002", 135 ReferralRewardFactors: &vega.RewardFactors{ 136 InfrastructureRewardFactor: "0.0004", 137 LiquidityRewardFactor: "0.0008", 138 MakerRewardFactor: "0.0008", 139 }, 140 ReferralDiscountFactors: &vega.DiscountFactors{ 141 InfrastructureDiscountFactor: "0.0004", 142 LiquidityDiscountFactor: "0.0008", 143 MakerDiscountFactor: "0.0008", 144 }, 145 TierNumber: ptr.From(uint64(2)), 146 }, 147 }, 148 EndOfProgramTimestamp: endTime2.Unix(), 149 WindowLength: 200, 150 StakingTiers: []*vega.StakingTier{ 151 { 152 MinimumStakedTokens: "1000", 153 ReferralRewardMultiplier: "1.0", 154 }, 155 { 156 MinimumStakedTokens: "10000", 157 ReferralRewardMultiplier: "1.1", 158 }, 159 }, 160 }, 161 }, 162 } 163 164 want := entities.ReferralProgramFromProto(programs[0].Program, block.VegaTime, 0) 165 err := rs.AddReferralProgram(ctx, want) 166 require.NoError(t, err) 167 168 var got []entities.ReferralProgram 169 err = pgxscan.Select(ctx, connectionSource, &got, "SELECT * FROM referral_programs") 170 require.NoError(t, err) 171 require.Len(t, got, 1) 172 assert.Equal(t, *want, got[0]) 173 174 want2 := entities.ReferralProgramFromProto(programs[1].Program, block2.VegaTime, 0) 175 err = rs.AddReferralProgram(ctx, want2) 176 require.NoError(t, err) 177 178 err = pgxscan.Select(ctx, connectionSource, &got, "SELECT * FROM referral_programs") 179 require.NoError(t, err) 180 require.Len(t, got, 2) 181 wantAll := []entities.ReferralProgram{*want, *want2} 182 assert.Equal(t, wantAll, got) 183 }) 184 } 185 186 func getReferralEvents(t *testing.T, endTime time.Time) (*eventspb.ReferralProgramStarted, 187 *eventspb.ReferralProgramUpdated, *eventspb.ReferralProgramEnded, 188 ) { 189 t.Helper() 190 191 started := eventspb.ReferralProgramStarted{ 192 Program: &vega.ReferralProgram{ 193 Version: 1, 194 Id: GenerateID(), 195 BenefitTiers: []*vega.BenefitTier{ 196 { 197 MinimumRunningNotionalTakerVolume: "1000", 198 MinimumEpochs: "10", 199 ReferralRewardFactor: "0.0001", 200 ReferralDiscountFactor: "0.0001", 201 ReferralRewardFactors: &vega.RewardFactors{ 202 InfrastructureRewardFactor: "0.00002", 203 LiquidityRewardFactor: "0.00004", 204 MakerRewardFactor: "0.00004", 205 }, 206 ReferralDiscountFactors: &vega.DiscountFactors{ 207 InfrastructureDiscountFactor: "0.00002", 208 LiquidityDiscountFactor: "0.00004", 209 MakerDiscountFactor: "0.00004", 210 }, 211 TierNumber: ptr.From(uint64(1)), 212 }, 213 { 214 MinimumRunningNotionalTakerVolume: "10000", 215 MinimumEpochs: "100", 216 ReferralRewardFactor: "0.001", 217 ReferralDiscountFactor: "0.001", 218 ReferralRewardFactors: &vega.RewardFactors{ 219 InfrastructureRewardFactor: "0.0002", 220 LiquidityRewardFactor: "0.0004", 221 MakerRewardFactor: "0.0004", 222 }, 223 ReferralDiscountFactors: &vega.DiscountFactors{ 224 InfrastructureDiscountFactor: "0.0002", 225 LiquidityDiscountFactor: "0.0004", 226 MakerDiscountFactor: "0.0004", 227 }, 228 TierNumber: ptr.From(uint64(2)), 229 }, 230 }, 231 EndOfProgramTimestamp: endTime.Unix(), 232 WindowLength: 100, 233 StakingTiers: []*vega.StakingTier{ 234 { 235 MinimumStakedTokens: "1000", 236 ReferralRewardMultiplier: "1.0", 237 }, 238 { 239 MinimumStakedTokens: "10000", 240 ReferralRewardMultiplier: "1.1", 241 }, 242 }, 243 }, 244 StartedAt: endTime.Add(-1 * time.Hour).UnixNano(), 245 AtEpoch: 40, 246 } 247 248 updated := eventspb.ReferralProgramUpdated{ 249 Program: &vega.ReferralProgram{ 250 Version: 2, 251 Id: started.Program.Id, 252 BenefitTiers: []*vega.BenefitTier{ 253 { 254 MinimumRunningNotionalTakerVolume: "2000", 255 MinimumEpochs: "20", 256 ReferralRewardFactor: "0.0002", 257 ReferralDiscountFactor: "0.0002", 258 ReferralRewardFactors: &vega.RewardFactors{ 259 InfrastructureRewardFactor: "0.0004", 260 LiquidityRewardFactor: "0.0008", 261 MakerRewardFactor: "0.0008", 262 }, 263 ReferralDiscountFactors: &vega.DiscountFactors{ 264 InfrastructureDiscountFactor: "0.0004", 265 LiquidityDiscountFactor: "0.0008", 266 MakerDiscountFactor: "0.0008", 267 }, 268 TierNumber: ptr.From(uint64(1)), 269 }, 270 { 271 MinimumRunningNotionalTakerVolume: "20000", 272 MinimumEpochs: "200", 273 ReferralRewardFactor: "0.002", 274 ReferralDiscountFactor: "0.002", 275 ReferralRewardFactors: &vega.RewardFactors{ 276 InfrastructureRewardFactor: "0.004", 277 LiquidityRewardFactor: "0.008", 278 MakerRewardFactor: "0.008", 279 }, 280 ReferralDiscountFactors: &vega.DiscountFactors{ 281 InfrastructureDiscountFactor: "0.004", 282 LiquidityDiscountFactor: "0.008", 283 MakerDiscountFactor: "0.008", 284 }, 285 TierNumber: ptr.From(uint64(2)), 286 }, 287 }, 288 EndOfProgramTimestamp: endTime.Unix(), 289 WindowLength: 200, 290 StakingTiers: []*vega.StakingTier{ 291 { 292 MinimumStakedTokens: "1000", 293 ReferralRewardMultiplier: "1.0", 294 }, 295 { 296 MinimumStakedTokens: "10000", 297 ReferralRewardMultiplier: "1.1", 298 }, 299 }, 300 }, 301 UpdatedAt: endTime.Add(-30 * time.Minute).UnixNano(), 302 AtEpoch: 41, 303 } 304 305 ended := eventspb.ReferralProgramEnded{ 306 Version: 2, 307 Id: started.Program.Id, 308 EndedAt: endTime.UnixNano(), 309 AtEpoch: 42, 310 } 311 312 return &started, &updated, &ended 313 } 314 315 func TestReferralPrograms_UpdateReferralProgram(t *testing.T) { 316 bs, rs := setupReferralProgramTest(t) 317 ctx := tempTransaction(t) 318 319 block := addTestBlock(t, ctx, bs) 320 endTime := block.VegaTime.Add(time.Hour) 321 started, updated, _ := getReferralEvents(t, endTime) 322 323 var want, wantUpdated *entities.ReferralProgram 324 t.Run("UpdateReferralProgram should create a new referral program record with the updated data", func(t *testing.T) { 325 want = entities.ReferralProgramFromProto(started.Program, block.VegaTime, 0) 326 err := rs.AddReferralProgram(ctx, want) 327 require.NoError(t, err) 328 329 var got []entities.ReferralProgram 330 err = pgxscan.Select(ctx, connectionSource, &got, "SELECT * FROM referral_programs") 331 require.NoError(t, err) 332 333 require.Len(t, got, 1) 334 assert.Equal(t, *want, got[0]) 335 336 block = addTestBlock(t, ctx, bs) 337 wantUpdated = entities.ReferralProgramFromProto(updated.Program, block.VegaTime, 0) 338 err = rs.UpdateReferralProgram(ctx, wantUpdated) 339 require.NoError(t, err) 340 341 err = pgxscan.Select(ctx, connectionSource, &got, "SELECT * FROM referral_programs") 342 require.NoError(t, err) 343 344 require.Len(t, got, 2) 345 346 wantAll := []entities.ReferralProgram{*want, *wantUpdated} 347 assert.Equal(t, wantAll, got) 348 }) 349 350 t.Run("The current_referral view should list the updated referral program record", func(t *testing.T) { 351 var got []entities.ReferralProgram 352 err := pgxscan.Select(ctx, connectionSource, &got, "SELECT * FROM current_referral_program") 353 require.NoError(t, err) 354 require.Len(t, got, 1) 355 assert.Equal(t, *wantUpdated, got[0]) 356 }) 357 } 358 359 func TestReferralPrograms_EndReferralProgram(t *testing.T) { 360 bs, rs := setupReferralProgramTest(t) 361 ctx := tempTransaction(t) 362 363 t.Run("EndReferralProgram should create a new referral program record with the data from the current referral program and set the ended_at timestamp", func(t *testing.T) { 364 block := addTestBlock(t, ctx, bs) 365 endTime := block.VegaTime.Add(time.Hour) 366 startedEvent, updatedEvent, endedEvent := getReferralEvents(t, endTime) 367 368 started := entities.ReferralProgramFromProto(startedEvent.Program, block.VegaTime, 1) 369 err := rs.AddReferralProgram(ctx, started) 370 require.NoError(t, err) 371 372 block = addTestBlock(t, ctx, bs) 373 updated := entities.ReferralProgramFromProto(updatedEvent.Program, block.VegaTime, 2) 374 err = rs.UpdateReferralProgram(ctx, updated) 375 require.NoError(t, err) 376 377 block = addTestBlock(t, ctx, bs) 378 err = rs.EndReferralProgram(ctx, endedEvent.Version, endTime, block.VegaTime, 3) 379 require.NoError(t, err) 380 381 ended := entities.ReferralProgramFromProto(updatedEvent.Program, block.VegaTime, 3) 382 ended.Version = endedEvent.Version 383 ended.EndedAt = &endTime 384 385 var got []entities.ReferralProgram 386 err = pgxscan.Select(ctx, connectionSource, &got, "SELECT * FROM referral_programs order by vega_time") 387 require.NoError(t, err) 388 require.Len(t, got, 3) 389 wantAll := []entities.ReferralProgram{*started, *updated, *ended} 390 assert.Equal(t, wantAll, got) 391 392 err = pgxscan.Select(ctx, connectionSource, &got, "SELECT * FROM current_referral_program") 393 require.NoError(t, err) 394 require.Len(t, got, 1) 395 assert.Equal(t, *ended, got[0]) 396 }) 397 } 398 399 func TestReferralPrograms_GetCurrentReferralProgram(t *testing.T) { 400 bs, rs := setupReferralProgramTest(t) 401 ctx := tempTransaction(t) 402 403 t.Run("GetCurrentReferralProgram should return the current referral program information", func(t *testing.T) { 404 block := addTestBlock(t, ctx, bs) 405 endTime := block.VegaTime.Add(time.Hour) 406 startedEvent, updatedEvent, endedEvent := getReferralEvents(t, endTime) 407 408 started := entities.ReferralProgramFromProto(startedEvent.Program, block.VegaTime, 1) 409 err := rs.AddReferralProgram(ctx, started) 410 require.NoError(t, err) 411 412 got, err := rs.GetCurrentReferralProgram(ctx) 413 require.NoError(t, err) 414 assert.Equal(t, *started, got) 415 416 block = addTestBlock(t, ctx, bs) 417 updated := entities.ReferralProgramFromProto(updatedEvent.Program, block.VegaTime, 2) 418 err = rs.UpdateReferralProgram(ctx, updated) 419 require.NoError(t, err) 420 421 got, err = rs.GetCurrentReferralProgram(ctx) 422 require.NoError(t, err) 423 assert.Equal(t, *updated, got) 424 425 block = addTestBlock(t, ctx, bs) 426 err = rs.EndReferralProgram(ctx, endedEvent.Version, endTime, block.VegaTime, 3) 427 require.NoError(t, err) 428 429 updatedProgram := entities.ReferralProgramFromProto(updatedEvent.Program, block.VegaTime, 3) 430 updatedProgram.Version = endedEvent.Version 431 updatedProgram.EndedAt = &endTime 432 433 got, err = rs.GetCurrentReferralProgram(ctx) 434 require.NoError(t, err) 435 assert.Equal(t, *updatedProgram, got) 436 }) 437 } 438 439 func TestReferralPrograms_StartAndEndInSameBlock(t *testing.T) { 440 bs, rs := setupReferralProgramTest(t) 441 ctx := tempTransaction(t) 442 443 t.Run("Data node should allow a referral program to be started and ended in the same block", func(t *testing.T) { 444 block := addTestBlock(t, ctx, bs) 445 endTime := block.VegaTime 446 startedEvent, updatedEvent, endedEvent := getReferralEvents(t, endTime) 447 448 started := entities.ReferralProgramFromProto(startedEvent.Program, block.VegaTime, 1) 449 err := rs.AddReferralProgram(ctx, started) 450 require.NoError(t, err) 451 452 got, err := rs.GetCurrentReferralProgram(ctx) 453 require.NoError(t, err) 454 assert.Equal(t, *started, got) 455 456 updated := entities.ReferralProgramFromProto(updatedEvent.Program, block.VegaTime, 2) 457 err = rs.UpdateReferralProgram(ctx, updated) 458 require.NoError(t, err) 459 460 got, err = rs.GetCurrentReferralProgram(ctx) 461 require.NoError(t, err) 462 assert.Equal(t, *updated, got) 463 464 err = rs.EndReferralProgram(ctx, endedEvent.Version, endTime, block.VegaTime, 3) 465 require.NoError(t, err) 466 467 ended := entities.ReferralProgramFromProto(updatedEvent.Program, block.VegaTime, 3) 468 ended.Version = endedEvent.Version 469 ended.EndedAt = &endTime 470 471 got, err = rs.GetCurrentReferralProgram(ctx) 472 require.NoError(t, err) 473 assert.Equal(t, *ended, got) 474 }) 475 }