code.vegaprotocol.io/vega@v0.79.0/datanode/sqlstore/paid_liquidity_fee_stats_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  	"context"
    20  	"testing"
    21  	"time"
    22  
    23  	"code.vegaprotocol.io/vega/datanode/entities"
    24  	vgtesting "code.vegaprotocol.io/vega/datanode/libs/testing"
    25  	"code.vegaprotocol.io/vega/datanode/sqlstore"
    26  	"code.vegaprotocol.io/vega/datanode/sqlstore/helpers"
    27  	eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1"
    28  
    29  	"github.com/georgysavva/scany/pgxscan"
    30  	"github.com/stretchr/testify/assert"
    31  	"github.com/stretchr/testify/require"
    32  )
    33  
    34  func TestPaidLiquidityFeesStats_Add(t *testing.T) {
    35  	t.Run("Should add the stats for the epoch if they do not exist", testAddPaidLiquidityFeesStatsEpochIfNotExists)
    36  	t.Run("Should not return an error if the epoch already exists for the market/asset/vega_time", testAddPaidLiquidityFeesStatsEpochExists)
    37  }
    38  
    39  type paidLiquidityFeesStatsTestStores struct {
    40  	bs *sqlstore.Blocks
    41  	ms *sqlstore.Markets
    42  	ps *sqlstore.Parties
    43  	as *sqlstore.Assets
    44  	ls *sqlstore.PaidLiquidityFeesStats
    45  }
    46  
    47  func setupPaidLiquidityFeesStatsStores(t *testing.T) *paidLiquidityFeesStatsTestStores {
    48  	t.Helper()
    49  	bs := sqlstore.NewBlocks(connectionSource)
    50  	ms := sqlstore.NewMarkets(connectionSource)
    51  	ps := sqlstore.NewParties(connectionSource)
    52  	as := sqlstore.NewAssets(connectionSource)
    53  	ls := sqlstore.NewPaidLiquidityFeesStats(connectionSource)
    54  
    55  	return &paidLiquidityFeesStatsTestStores{
    56  		bs: bs,
    57  		ms: ms,
    58  		ps: ps,
    59  		as: as,
    60  		ls: ls,
    61  	}
    62  }
    63  
    64  func testAddPaidLiquidityFeesStatsEpochIfNotExists(t *testing.T) {
    65  	stores := setupPaidLiquidityFeesStatsStores(t)
    66  	ctx := tempTransaction(t)
    67  	block := addTestBlock(t, ctx, stores.bs)
    68  	market := helpers.AddTestMarket(t, ctx, stores.ms, block)
    69  	asset := addTestAsset(t, ctx, stores.as, block)
    70  
    71  	want := entities.PaidLiquidityFeesStats{
    72  		MarketID:      market.ID,
    73  		AssetID:       asset.ID,
    74  		EpochSeq:      100,
    75  		TotalFeesPaid: "100",
    76  		FeesPerParty: []*eventspb.PartyAmount{
    77  			{Party: "party-1", Amount: "50"},
    78  			{Party: "party-2", Amount: "50"},
    79  			{Party: "party-3", Amount: "50"},
    80  		},
    81  		VegaTime: time.Now(),
    82  	}
    83  
    84  	err := stores.ls.Add(ctx, &want)
    85  	require.NoError(t, err)
    86  
    87  	// Check that the stats were added
    88  	var got entities.PaidLiquidityFeesStats
    89  	err = pgxscan.Get(ctx, connectionSource, &got,
    90  		`SELECT market_id, asset_id, epoch_seq, total_fees_paid, fees_paid_per_party as fees_per_party
    91  		FROM paid_liquidity_fees WHERE market_id = $1 AND asset_id = $2 AND epoch_seq = $3`,
    92  		market.ID, asset.ID, want.EpochSeq,
    93  	)
    94  	require.NoError(t, err)
    95  	vgtesting.AssertProtoEqual(t, want.ToProto(), got.ToProto())
    96  }
    97  
    98  func testAddPaidLiquidityFeesStatsEpochExists(t *testing.T) {
    99  	stores := setupPaidLiquidityFeesStatsStores(t)
   100  	ctx := tempTransaction(t)
   101  	block := addTestBlock(t, ctx, stores.bs)
   102  	market := helpers.AddTestMarket(t, ctx, stores.ms, block)
   103  	asset := addTestAsset(t, ctx, stores.as, block)
   104  
   105  	want := entities.PaidLiquidityFeesStats{
   106  		MarketID:      market.ID,
   107  		AssetID:       asset.ID,
   108  		EpochSeq:      100,
   109  		TotalFeesPaid: "100",
   110  		FeesPerParty: []*eventspb.PartyAmount{
   111  			{Party: "party-1", Amount: "50"},
   112  			{Party: "party-2", Amount: "50"},
   113  			{Party: "party-3", Amount: "50"},
   114  		},
   115  		VegaTime: time.Now(),
   116  	}
   117  
   118  	err := stores.ls.Add(ctx, &want)
   119  	require.NoError(t, err)
   120  
   121  	// now try to insert again and make sure we get an error
   122  	err = stores.ls.Add(ctx, &want)
   123  	require.NoError(t, err)
   124  }
   125  
   126  func TestPaidLiquidityFeesStats_List(t *testing.T) {
   127  	t.Run("Should return the stats for the market and epoch requested", testListPaidLiquidityFeesStatsForMarketAndEpoch)
   128  	t.Run("Should return the stats for the asset and epoch requested", testListPaidLiquidityFeesStatsForAssetAndEpoch)
   129  	t.Run("Should return the latest stats for the market requested", testListPaidLiquidityFeesStatsForMarketLatest)
   130  	t.Run("Should return the latest stats for the asset requested", testListPaidLiquidityFeesStatsForAssetLatest)
   131  	t.Run("Should return the stats for the party and epoch requested", testListPaidLiquidityFeesStatsForPartyAndEpoch)
   132  	t.Run("Should return the latest stats for the party", testListPaidLiquidityFeesStatsForPartyLatest)
   133  }
   134  
   135  func setupPaidLiquidityFeesStats(t *testing.T, ctx context.Context, ls *sqlstore.PaidLiquidityFeesStats) []entities.PaidLiquidityFeesStats {
   136  	t.Helper()
   137  	stats := []entities.PaidLiquidityFeesStats{
   138  		{
   139  			MarketID:      entities.MarketID("deadbeef01"),
   140  			AssetID:       entities.AssetID("deadbaad01"),
   141  			EpochSeq:      1,
   142  			TotalFeesPaid: "1000000",
   143  			FeesPerParty: []*eventspb.PartyAmount{
   144  				{
   145  					Party:  "cafed00d01",
   146  					Amount: "500000",
   147  				},
   148  				{
   149  					Party:  "cafed00d02",
   150  					Amount: "500000",
   151  				},
   152  			},
   153  		},
   154  		{
   155  			MarketID:      entities.MarketID("deadbeef01"),
   156  			AssetID:       entities.AssetID("deadbaad01"),
   157  			EpochSeq:      2,
   158  			TotalFeesPaid: "1200000",
   159  			FeesPerParty: []*eventspb.PartyAmount{
   160  				{
   161  					Party:  "cafed00d01",
   162  					Amount: "600000",
   163  				},
   164  				{
   165  					Party:  "cafed00d02",
   166  					Amount: "600000",
   167  				},
   168  			},
   169  		},
   170  		{
   171  			MarketID:      entities.MarketID("deadbeef01"),
   172  			AssetID:       entities.AssetID("deadbaad01"),
   173  			EpochSeq:      3,
   174  			TotalFeesPaid: "1400000",
   175  			FeesPerParty: []*eventspb.PartyAmount{
   176  				{
   177  					Party:  "cafed00d01",
   178  					Amount: "700000",
   179  				},
   180  				{
   181  					Party:  "cafed00d02",
   182  					Amount: "700000",
   183  				},
   184  			},
   185  		},
   186  		{
   187  			MarketID:      entities.MarketID("deadbeef02"),
   188  			AssetID:       entities.AssetID("deadbaad02"),
   189  			EpochSeq:      1,
   190  			TotalFeesPaid: "1200000",
   191  			FeesPerParty: []*eventspb.PartyAmount{
   192  				{
   193  					Party:  "cafed00d01",
   194  					Amount: "700000",
   195  				},
   196  				{
   197  					Party:  "cafed00d02",
   198  					Amount: "500000",
   199  				},
   200  			},
   201  		},
   202  		{
   203  			MarketID:      entities.MarketID("deadbeef02"),
   204  			AssetID:       entities.AssetID("deadbaad02"),
   205  			EpochSeq:      2,
   206  			TotalFeesPaid: "1000000",
   207  			FeesPerParty: []*eventspb.PartyAmount{
   208  				{
   209  					Party:  "cafed00d01",
   210  					Amount: "500000",
   211  				},
   212  				{
   213  					Party:  "cafed00d02",
   214  					Amount: "500000",
   215  				},
   216  			},
   217  		},
   218  		{
   219  			MarketID:      entities.MarketID("deadbeef02"),
   220  			AssetID:       entities.AssetID("deadbaad02"),
   221  			EpochSeq:      3,
   222  			TotalFeesPaid: "5000000",
   223  			FeesPerParty: []*eventspb.PartyAmount{
   224  				{
   225  					Party:  "cafed00d01",
   226  					Amount: "25000",
   227  				},
   228  				{
   229  					Party:  "cafed00d02",
   230  					Amount: "25000",
   231  				},
   232  			},
   233  		},
   234  	}
   235  
   236  	for _, stat := range stats {
   237  		err := ls.Add(ctx, &stat)
   238  		require.NoError(t, err)
   239  	}
   240  
   241  	return stats
   242  }
   243  
   244  func testListPaidLiquidityFeesStatsForMarketAndEpoch(t *testing.T) {
   245  	stores := setupPaidLiquidityFeesStatsStores(t)
   246  	ctx := tempTransaction(t)
   247  	stats := setupPaidLiquidityFeesStats(t, ctx, stores.ls)
   248  
   249  	pagination := entities.DefaultCursorPagination(true)
   250  
   251  	// get the stats for the first market and epoch
   252  	want := stats[0:1]
   253  	got, _, err := stores.ls.List(ctx, &want[0].MarketID, nil, &want[0].EpochSeq, nil, pagination, nil, nil)
   254  	require.NoError(t, err)
   255  
   256  	assert.Len(t, got, len(want))
   257  	vgtesting.AssertProtoEqual(t, want[0].ToProto(), got[0].ToProto())
   258  
   259  	// get the stats for the second market and epoch
   260  	want = stats[3:4]
   261  	got, _, err = stores.ls.List(ctx, &want[0].MarketID, nil, &want[0].EpochSeq, nil, pagination, nil, nil)
   262  	require.NoError(t, err)
   263  
   264  	assert.Len(t, got, len(want))
   265  	vgtesting.AssertProtoEqual(t, want[0].ToProto(), got[0].ToProto())
   266  }
   267  
   268  func testListPaidLiquidityFeesStatsForAssetAndEpoch(t *testing.T) {
   269  	stores := setupPaidLiquidityFeesStatsStores(t)
   270  	ctx := tempTransaction(t)
   271  	stats := setupPaidLiquidityFeesStats(t, ctx, stores.ls)
   272  
   273  	pagination := entities.DefaultCursorPagination(true)
   274  
   275  	// get the stats for the first market and epoch
   276  	want := stats[1:2]
   277  	got, _, err := stores.ls.List(ctx, nil, &want[0].AssetID, &want[0].EpochSeq, nil, pagination, nil, nil)
   278  	require.NoError(t, err)
   279  
   280  	assert.Len(t, got, len(want))
   281  	vgtesting.AssertProtoEqual(t, want[0].ToProto(), got[0].ToProto())
   282  
   283  	// get the stats for the second market and epoch
   284  	want = stats[4:5]
   285  	got, _, err = stores.ls.List(ctx, nil, &want[0].AssetID, &want[0].EpochSeq, nil, pagination, nil, nil)
   286  	require.NoError(t, err)
   287  
   288  	assert.Len(t, got, len(want))
   289  	vgtesting.AssertProtoEqual(t, want[0].ToProto(), got[0].ToProto())
   290  }
   291  
   292  func testListPaidLiquidityFeesStatsForMarketLatest(t *testing.T) {
   293  	stores := setupPaidLiquidityFeesStatsStores(t)
   294  	ctx := tempTransaction(t)
   295  	stats := setupPaidLiquidityFeesStats(t, ctx, stores.ls)
   296  
   297  	pagination := entities.DefaultCursorPagination(true)
   298  
   299  	// get the stats for the first market and epoch
   300  	want := stats[2:3]
   301  	got, _, err := stores.ls.List(ctx, &want[0].MarketID, nil, nil, nil, pagination, nil, nil)
   302  	require.NoError(t, err)
   303  
   304  	assert.Len(t, got, len(want))
   305  	vgtesting.AssertProtoEqual(t, want[0].ToProto(), got[0].ToProto())
   306  
   307  	// get the stats for the second market and epoch
   308  	want = stats[5:6]
   309  	got, _, err = stores.ls.List(ctx, &want[0].MarketID, nil, nil, nil, pagination, nil, nil)
   310  	require.NoError(t, err)
   311  
   312  	assert.Len(t, got, len(want))
   313  	vgtesting.AssertProtoEqual(t, want[0].ToProto(), got[0].ToProto())
   314  }
   315  
   316  func testListPaidLiquidityFeesStatsForAssetLatest(t *testing.T) {
   317  	stores := setupPaidLiquidityFeesStatsStores(t)
   318  	ctx := tempTransaction(t)
   319  	stats := setupPaidLiquidityFeesStats(t, ctx, stores.ls)
   320  
   321  	pagination := entities.DefaultCursorPagination(true)
   322  
   323  	// get the stats for the first market and epoch
   324  	want := stats[2:3]
   325  	got, _, err := stores.ls.List(ctx, nil, &want[0].AssetID, nil, nil, pagination, nil, nil)
   326  	require.NoError(t, err)
   327  
   328  	assert.Len(t, got, len(want))
   329  	vgtesting.AssertProtoEqual(t, want[0].ToProto(), got[0].ToProto())
   330  
   331  	// get the stats for the second market and epoch
   332  	want = stats[5:6]
   333  	got, _, err = stores.ls.List(ctx, nil, &want[0].AssetID, nil, nil, pagination, nil, nil)
   334  	require.NoError(t, err)
   335  
   336  	assert.Len(t, got, len(want))
   337  	vgtesting.AssertProtoEqual(t, want[0].ToProto(), got[0].ToProto())
   338  }
   339  
   340  func testListPaidLiquidityFeesStatsForPartyAndEpoch(t *testing.T) {
   341  	stores := setupPaidLiquidityFeesStatsStores(t)
   342  	ctx := tempTransaction(t)
   343  	stats := setupPaidLiquidityFeesStats(t, ctx, stores.ls)
   344  
   345  	pagination := entities.DefaultCursorPagination(true)
   346  
   347  	// get the stats for the first market and epoch
   348  	want := append(stats[3:4], stats[0:1]...)
   349  	want[0].FeesPerParty = want[0].FeesPerParty[:1]
   350  	want[1].FeesPerParty = want[1].FeesPerParty[:1]
   351  
   352  	got, _, err := stores.ls.List(ctx, nil, nil, &want[0].EpochSeq, []string{want[0].FeesPerParty[0].Party}, pagination, nil, nil)
   353  	require.NoError(t, err)
   354  
   355  	assert.Len(t, got, len(want))
   356  	vgtesting.AssertProtoEqual(t, want[0].ToProto(), got[0].ToProto())
   357  	vgtesting.AssertProtoEqual(t, want[1].ToProto(), got[1].ToProto())
   358  }
   359  
   360  func testListPaidLiquidityFeesStatsForPartyLatest(t *testing.T) {
   361  	stores := setupPaidLiquidityFeesStatsStores(t)
   362  	ctx := tempTransaction(t)
   363  	stats := setupPaidLiquidityFeesStats(t, ctx, stores.ls)
   364  
   365  	pagination := entities.DefaultCursorPagination(true)
   366  
   367  	// get the stats for the first market and epoch
   368  	want := append(stats[5:6], stats[2:3]...)
   369  	want[0].FeesPerParty = want[0].FeesPerParty[:1]
   370  	want[1].FeesPerParty = want[1].FeesPerParty[:1]
   371  
   372  	got, _, err := stores.ls.List(ctx, nil, nil, nil, []string{want[0].FeesPerParty[0].Party}, pagination, nil, nil)
   373  	require.NoError(t, err)
   374  
   375  	assert.Len(t, got, len(want))
   376  	vgtesting.AssertProtoEqual(t, want[0].ToProto(), got[0].ToProto())
   377  	vgtesting.AssertProtoEqual(t, want[1].ToProto(), got[1].ToProto())
   378  }