code.vegaprotocol.io/vega@v0.79.0/datanode/sqlstore/volume_discount_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 setupVolumeDiscountProgramTest(t *testing.T) (*sqlstore.Blocks, *sqlstore.VolumeDiscountPrograms) {
    34  	t.Helper()
    35  
    36  	bs := sqlstore.NewBlocks(connectionSource)
    37  	rs := sqlstore.NewVolumeDiscountPrograms(connectionSource)
    38  
    39  	return bs, rs
    40  }
    41  
    42  func TestVolumeDiscountPrograms_AddVolumeDiscountProgram(t *testing.T) {
    43  	bs, rs := setupVolumeDiscountProgramTest(t)
    44  	ctx := tempTransaction(t)
    45  
    46  	block := addTestBlock(t, ctx, bs)
    47  	block2 := addTestBlock(t, ctx, bs)
    48  
    49  	t.Run("AddVolumeDiscountProgram 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.VolumeDiscountProgramStarted{
    54  			{
    55  				Program: &vega.VolumeDiscountProgram{
    56  					Version: 1,
    57  					Id:      GenerateID(),
    58  					BenefitTiers: []*vega.VolumeBenefitTier{
    59  						{
    60  							MinimumRunningNotionalTakerVolume: "1000",
    61  							VolumeDiscountFactor:              "0.01",
    62  							VolumeDiscountFactors: &vega.DiscountFactors{
    63  								InfrastructureDiscountFactor: "0.004",
    64  								LiquidityDiscountFactor:      "0.002",
    65  								MakerDiscountFactor:          "0.004",
    66  							},
    67  							TierNumber: ptr.From(uint64(1)),
    68  						},
    69  						{
    70  							MinimumRunningNotionalTakerVolume: "10000",
    71  							VolumeDiscountFactor:              "0.1",
    72  							VolumeDiscountFactors: &vega.DiscountFactors{
    73  								InfrastructureDiscountFactor: "0.04",
    74  								LiquidityDiscountFactor:      "0.02",
    75  								MakerDiscountFactor:          "0.04",
    76  							},
    77  							TierNumber: ptr.From(uint64(2)),
    78  						},
    79  					},
    80  					EndOfProgramTimestamp: endTime.Unix(),
    81  					WindowLength:          100,
    82  				},
    83  			},
    84  			{
    85  				Program: &vega.VolumeDiscountProgram{
    86  					Version: 1,
    87  					Id:      GenerateID(),
    88  					BenefitTiers: []*vega.VolumeBenefitTier{
    89  						{
    90  							MinimumRunningNotionalTakerVolume: "2000",
    91  							VolumeDiscountFactor:              "0.02",
    92  							VolumeDiscountFactors: &vega.DiscountFactors{
    93  								InfrastructureDiscountFactor: "0.008",
    94  								LiquidityDiscountFactor:      "0.002",
    95  								MakerDiscountFactor:          "0.004",
    96  							},
    97  							TierNumber: ptr.From(uint64(1)),
    98  						},
    99  						{
   100  							MinimumRunningNotionalTakerVolume: "20000",
   101  							VolumeDiscountFactor:              "0.2",
   102  							VolumeDiscountFactors: &vega.DiscountFactors{
   103  								InfrastructureDiscountFactor: "0.08",
   104  								LiquidityDiscountFactor:      "0.04",
   105  								MakerDiscountFactor:          "0.08",
   106  							},
   107  							TierNumber: ptr.From(uint64(2)),
   108  						},
   109  					},
   110  					EndOfProgramTimestamp: endTime2.Unix(),
   111  					WindowLength:          200,
   112  				},
   113  			},
   114  		}
   115  
   116  		want := entities.VolumeDiscountProgramFromProto(programs[0].Program, block.VegaTime, 0)
   117  		err := rs.AddVolumeDiscountProgram(ctx, want)
   118  		require.NoError(t, err)
   119  
   120  		var got []entities.VolumeDiscountProgram
   121  		require.NoError(t, pgxscan.Select(ctx, connectionSource, &got, "SELECT * FROM volume_discount_programs"))
   122  		require.Len(t, got, 1)
   123  		assert.Equal(t, *want, got[0])
   124  
   125  		want2 := entities.VolumeDiscountProgramFromProto(programs[1].Program, block2.VegaTime, 0)
   126  		err = rs.AddVolumeDiscountProgram(ctx, want2)
   127  		require.NoError(t, err)
   128  
   129  		err = pgxscan.Select(ctx, connectionSource, &got, "SELECT * FROM volume_discount_programs")
   130  		require.NoError(t, err)
   131  		require.Len(t, got, 2)
   132  		wantAll := []entities.VolumeDiscountProgram{*want, *want2}
   133  		assert.Equal(t, wantAll, got)
   134  	})
   135  }
   136  
   137  func getVolumeDiscountEvents(t *testing.T, endTime time.Time) (*eventspb.VolumeDiscountProgramStarted,
   138  	*eventspb.VolumeDiscountProgramUpdated, *eventspb.VolumeDiscountProgramEnded,
   139  ) {
   140  	t.Helper()
   141  
   142  	started := eventspb.VolumeDiscountProgramStarted{
   143  		Program: &vega.VolumeDiscountProgram{
   144  			Version: 1,
   145  			Id:      GenerateID(),
   146  			BenefitTiers: []*vega.VolumeBenefitTier{
   147  				{
   148  					MinimumRunningNotionalTakerVolume: "1000",
   149  					VolumeDiscountFactor:              "0.01",
   150  					VolumeDiscountFactors: &vega.DiscountFactors{
   151  						InfrastructureDiscountFactor: "0.004",
   152  						LiquidityDiscountFactor:      "0.002",
   153  						MakerDiscountFactor:          "0.004",
   154  					},
   155  					TierNumber: ptr.From(uint64(1)),
   156  				},
   157  				{
   158  					MinimumRunningNotionalTakerVolume: "10000",
   159  					VolumeDiscountFactor:              "0.1",
   160  					VolumeDiscountFactors: &vega.DiscountFactors{
   161  						InfrastructureDiscountFactor: "0.04",
   162  						LiquidityDiscountFactor:      "0.02",
   163  						MakerDiscountFactor:          "0.04",
   164  					},
   165  					TierNumber: ptr.From(uint64(2)),
   166  				},
   167  			},
   168  			EndOfProgramTimestamp: endTime.Unix(),
   169  			WindowLength:          100,
   170  		},
   171  		StartedAt: endTime.Add(-1 * time.Hour).UnixNano(),
   172  		AtEpoch:   1,
   173  	}
   174  
   175  	updated := eventspb.VolumeDiscountProgramUpdated{
   176  		Program: &vega.VolumeDiscountProgram{
   177  			Version: 2,
   178  			Id:      GenerateID(),
   179  			BenefitTiers: []*vega.VolumeBenefitTier{
   180  				{
   181  					MinimumRunningNotionalTakerVolume: "2000",
   182  					VolumeDiscountFactor:              "0.02",
   183  					VolumeDiscountFactors: &vega.DiscountFactors{
   184  						InfrastructureDiscountFactor: "0.008",
   185  						LiquidityDiscountFactor:      "0.004",
   186  						MakerDiscountFactor:          "0.008",
   187  					},
   188  					TierNumber: ptr.From(uint64(1)),
   189  				},
   190  				{
   191  					MinimumRunningNotionalTakerVolume: "20000",
   192  					VolumeDiscountFactor:              "0.2",
   193  					VolumeDiscountFactors: &vega.DiscountFactors{
   194  						InfrastructureDiscountFactor: "0.08",
   195  						LiquidityDiscountFactor:      "0.04",
   196  						MakerDiscountFactor:          "0.08",
   197  					},
   198  					TierNumber: ptr.From(uint64(2)),
   199  				},
   200  			},
   201  			EndOfProgramTimestamp: endTime.Unix(),
   202  			WindowLength:          200,
   203  		},
   204  		UpdatedAt: endTime.Add(-30 * time.Minute).UnixNano(),
   205  		AtEpoch:   2,
   206  	}
   207  
   208  	ended := eventspb.VolumeDiscountProgramEnded{
   209  		Version: 2,
   210  		Id:      updated.Program.Id,
   211  		EndedAt: endTime.UnixNano(),
   212  		AtEpoch: 3,
   213  	}
   214  
   215  	return &started, &updated, &ended
   216  }
   217  
   218  func TestVolumeDiscountPrograms_UpdateVolumeDiscountProgram(t *testing.T) {
   219  	bs, rs := setupVolumeDiscountProgramTest(t)
   220  	ctx := tempTransaction(t)
   221  
   222  	block := addTestBlock(t, ctx, bs)
   223  	endTime := block.VegaTime.Add(time.Hour)
   224  	started, updated, _ := getVolumeDiscountEvents(t, endTime)
   225  
   226  	var want, wantUpdated *entities.VolumeDiscountProgram
   227  	t.Run("UpdateVolumeDiscountProgram should create a new referral program record with the updated data", func(t *testing.T) {
   228  		want = entities.VolumeDiscountProgramFromProto(started.Program, block.VegaTime, 0)
   229  		err := rs.AddVolumeDiscountProgram(ctx, want)
   230  		require.NoError(t, err)
   231  
   232  		var got []entities.VolumeDiscountProgram
   233  		err = pgxscan.Select(ctx, connectionSource, &got, "SELECT * FROM volume_discount_programs")
   234  		require.NoError(t, err)
   235  
   236  		require.Len(t, got, 1)
   237  		assert.Equal(t, *want, got[0])
   238  
   239  		block = addTestBlock(t, ctx, bs)
   240  		wantUpdated = entities.VolumeDiscountProgramFromProto(updated.Program, block.VegaTime, 0)
   241  		err = rs.UpdateVolumeDiscountProgram(ctx, wantUpdated)
   242  		require.NoError(t, err)
   243  
   244  		err = pgxscan.Select(ctx, connectionSource, &got, "SELECT * FROM volume_discount_programs")
   245  		require.NoError(t, err)
   246  
   247  		require.Len(t, got, 2)
   248  
   249  		wantAll := []entities.VolumeDiscountProgram{*want, *wantUpdated}
   250  		assert.Equal(t, wantAll, got)
   251  	})
   252  
   253  	t.Run("The current_referral view should list the updated referral program record", func(t *testing.T) {
   254  		var got []entities.VolumeDiscountProgram
   255  		err := pgxscan.Select(ctx, connectionSource, &got, "SELECT * FROM current_volume_discount_program")
   256  		require.NoError(t, err)
   257  		require.Len(t, got, 1)
   258  		assert.Equal(t, *wantUpdated, got[0])
   259  	})
   260  }
   261  
   262  func TestVolumeDiscountPrograms_EndVolumeDiscountProgram(t *testing.T) {
   263  	bs, rs := setupVolumeDiscountProgramTest(t)
   264  	ctx := tempTransaction(t)
   265  
   266  	t.Run("EndVolumeDiscountProgram 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) {
   267  		block := addTestBlock(t, ctx, bs)
   268  		endTime := block.VegaTime.Add(time.Hour)
   269  		startedEvent, updatedEvent, endedEvent := getVolumeDiscountEvents(t, endTime)
   270  
   271  		started := entities.VolumeDiscountProgramFromProto(startedEvent.Program, block.VegaTime, 1)
   272  		err := rs.AddVolumeDiscountProgram(ctx, started)
   273  		require.NoError(t, err)
   274  
   275  		block = addTestBlock(t, ctx, bs)
   276  		updated := entities.VolumeDiscountProgramFromProto(updatedEvent.Program, block.VegaTime, 2)
   277  		err = rs.UpdateVolumeDiscountProgram(ctx, updated)
   278  		require.NoError(t, err)
   279  
   280  		block = addTestBlock(t, ctx, bs)
   281  		err = rs.EndVolumeDiscountProgram(ctx, endedEvent.Version, endTime, block.VegaTime, 3)
   282  		require.NoError(t, err)
   283  
   284  		ended := entities.VolumeDiscountProgramFromProto(updatedEvent.Program, block.VegaTime, 3)
   285  		ended.Version = endedEvent.Version
   286  		ended.EndedAt = &endTime
   287  
   288  		var got []entities.VolumeDiscountProgram
   289  		err = pgxscan.Select(ctx, connectionSource, &got, "SELECT * FROM volume_discount_programs order by vega_time")
   290  		require.NoError(t, err)
   291  		require.Len(t, got, 3)
   292  		wantAll := []entities.VolumeDiscountProgram{*started, *updated, *ended}
   293  		assert.Equal(t, wantAll, got)
   294  
   295  		err = pgxscan.Select(ctx, connectionSource, &got, "SELECT * FROM current_volume_discount_program")
   296  		require.NoError(t, err)
   297  		require.Len(t, got, 1)
   298  		assert.Equal(t, *ended, got[0])
   299  	})
   300  }
   301  
   302  func TestVolumeDiscountPrograms_GetCurrentVolumeDiscountProgram(t *testing.T) {
   303  	bs, rs := setupVolumeDiscountProgramTest(t)
   304  	ctx := tempTransaction(t)
   305  
   306  	t.Run("GetCurrentVolumeDiscountProgram should return the current referral program information", func(t *testing.T) {
   307  		block := addTestBlock(t, ctx, bs)
   308  		endTime := block.VegaTime.Add(time.Hour)
   309  		startedEvent, updatedEvent, endedEvent := getVolumeDiscountEvents(t, endTime)
   310  
   311  		started := entities.VolumeDiscountProgramFromProto(startedEvent.Program, block.VegaTime, 1)
   312  		err := rs.AddVolumeDiscountProgram(ctx, started)
   313  		require.NoError(t, err)
   314  
   315  		got, err := rs.GetCurrentVolumeDiscountProgram(ctx)
   316  		require.NoError(t, err)
   317  		assert.Equal(t, *started, got)
   318  
   319  		block = addTestBlock(t, ctx, bs)
   320  		updated := entities.VolumeDiscountProgramFromProto(updatedEvent.Program, block.VegaTime, 2)
   321  		err = rs.UpdateVolumeDiscountProgram(ctx, updated)
   322  		require.NoError(t, err)
   323  
   324  		got, err = rs.GetCurrentVolumeDiscountProgram(ctx)
   325  		require.NoError(t, err)
   326  		assert.Equal(t, *updated, got)
   327  
   328  		block = addTestBlock(t, ctx, bs)
   329  		err = rs.EndVolumeDiscountProgram(ctx, endedEvent.Version, endTime, block.VegaTime, 3)
   330  		require.NoError(t, err)
   331  
   332  		ended := entities.VolumeDiscountProgramFromProto(updatedEvent.Program, block.VegaTime, 3)
   333  		ended.Version = endedEvent.Version
   334  		ended.EndedAt = &endTime
   335  
   336  		got, err = rs.GetCurrentVolumeDiscountProgram(ctx)
   337  		require.NoError(t, err)
   338  		assert.Equal(t, *ended, got)
   339  	})
   340  }