code.vegaprotocol.io/vega@v0.79.0/core/governance/engine_update_discount_volume_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 TestProposalForUpdateDiscountVolumeProgram(t *testing.T) {
    34  	t.Run("Submitting a proposal for referral program update succeeds", testSubmittingProposalForVolumeDiscountProgramUpdateSucceeds)
    35  	t.Run("Submitting a proposal for referral program update with too many tiers fails", testSubmittingProposalForVolumeDiscountProgramUpdateWithTooManyTiersFails)
    36  	t.Run("Submitting a proposal for referral program update with too high discount factor fails", testSubmittingProposalForVolumeDiscountProgramUpdateWithTooHighDiscountFactorFails)
    37  }
    38  
    39  func testSubmittingProposalForVolumeDiscountProgramUpdateSucceeds(t *testing.T) {
    40  	now := time.Now()
    41  	ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64())
    42  	eng := getTestEngine(t, now)
    43  
    44  	// setup
    45  	eng.broker.EXPECT().Send(gomock.Any()).Times(3)
    46  	eng.netp.Update(ctx, netparams.GovernanceProposalVolumeDiscountProgramMinClose, "48h")
    47  	eng.netp.Update(ctx, netparams.GovernanceProposalVolumeDiscountProgramMinEnact, "48h")
    48  	eng.netp.Update(ctx, netparams.GovernanceProposalVolumeDiscountProgramMinProposerBalance, "1000")
    49  
    50  	eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.VolumeDiscountProgramMaxBenefitTiers, "2")).Times(1)
    51  	require.NoError(t, eng.netp.Update(ctx, netparams.VolumeDiscountProgramMaxBenefitTiers, "2"))
    52  
    53  	eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.VolumeDiscountProgramMaxVolumeDiscountFactor, "0.010")).Times(1)
    54  	require.NoError(t, eng.netp.Update(ctx, netparams.VolumeDiscountProgramMaxVolumeDiscountFactor, "0.010"))
    55  
    56  	// given
    57  	proposer := vgrand.RandomStr(5)
    58  	proposal := eng.newProposalForVolumeDiscountProgramUpdate(proposer, now, &types.VolumeDiscountProgramChanges{
    59  		EndOfProgramTimestamp: now.Add(4 * 48 * time.Hour),
    60  		WindowLength:          15,
    61  		VolumeBenefitTiers: []*types.VolumeBenefitTier{
    62  			{
    63  				MinimumRunningNotionalTakerVolume: num.NewUint(10000),
    64  				VolumeDiscountFactors: types.Factors{
    65  					Infra:     num.DecimalFromFloat(0.001),
    66  					Maker:     num.DecimalFromFloat(0.001),
    67  					Liquidity: num.DecimalFromFloat(0.001),
    68  				},
    69  			}, {
    70  				MinimumRunningNotionalTakerVolume: num.NewUint(20000),
    71  				VolumeDiscountFactors: types.Factors{
    72  					Infra:     num.DecimalFromFloat(0.005),
    73  					Maker:     num.DecimalFromFloat(0.005),
    74  					Liquidity: num.DecimalFromFloat(0.005),
    75  				},
    76  			},
    77  		},
    78  	})
    79  
    80  	// setup
    81  	eng.ensureTokenBalanceForParty(t, proposer, 1000)
    82  
    83  	// expect
    84  	eng.expectOpenProposalEvent(t, proposer, proposal.ID)
    85  
    86  	// when
    87  	toSubmit, err := eng.submitProposal(t, proposal)
    88  
    89  	// then
    90  	require.NoError(t, err)
    91  	require.NotNil(t, toSubmit)
    92  }
    93  
    94  func testSubmittingProposalForVolumeDiscountProgramUpdateWithTooManyTiersFails(t *testing.T) {
    95  	now := time.Now()
    96  	ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64())
    97  	eng := getTestEngine(t, now)
    98  
    99  	// setup
   100  	eng.broker.EXPECT().Send(gomock.Any()).Times(3)
   101  	eng.netp.Update(ctx, netparams.GovernanceProposalVolumeDiscountProgramMinClose, "48h")
   102  	eng.netp.Update(ctx, netparams.GovernanceProposalVolumeDiscountProgramMinEnact, "48h")
   103  	eng.netp.Update(ctx, netparams.GovernanceProposalVolumeDiscountProgramMinProposerBalance, "1000")
   104  
   105  	eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.VolumeDiscountProgramMaxBenefitTiers, "1")).Times(1)
   106  	require.NoError(t, eng.netp.Update(ctx, netparams.VolumeDiscountProgramMaxBenefitTiers, "1"))
   107  
   108  	eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.VolumeDiscountProgramMaxVolumeDiscountFactor, "0.010")).Times(1)
   109  	require.NoError(t, eng.netp.Update(ctx, netparams.VolumeDiscountProgramMaxVolumeDiscountFactor, "0.010"))
   110  
   111  	// given
   112  	proposer := vgrand.RandomStr(5)
   113  	proposal := eng.newProposalForVolumeDiscountProgramUpdate(proposer, now, &types.VolumeDiscountProgramChanges{
   114  		EndOfProgramTimestamp: now.Add(4 * 48 * time.Hour),
   115  		WindowLength:          15,
   116  		VolumeBenefitTiers: []*types.VolumeBenefitTier{
   117  			{
   118  				MinimumRunningNotionalTakerVolume: num.NewUint(10000),
   119  				VolumeDiscountFactors: types.Factors{
   120  					Infra:     num.DecimalFromFloat(0.001),
   121  					Maker:     num.DecimalFromFloat(0.001),
   122  					Liquidity: num.DecimalFromFloat(0.001),
   123  				},
   124  			}, {
   125  				MinimumRunningNotionalTakerVolume: num.NewUint(20000),
   126  				VolumeDiscountFactors: types.Factors{
   127  					Infra:     num.DecimalFromFloat(0.005),
   128  					Maker:     num.DecimalFromFloat(0.005),
   129  					Liquidity: num.DecimalFromFloat(0.005),
   130  				},
   131  			},
   132  		},
   133  	})
   134  
   135  	// setup
   136  	eng.ensureTokenBalanceForParty(t, proposer, 1000)
   137  
   138  	// expect
   139  	eng.expectRejectedProposalEvent(t, proposer, proposal.ID, types.ProposalErrorInvalidVolumeDiscountProgram)
   140  
   141  	// when
   142  	toSubmit, err := eng.submitProposal(t, proposal)
   143  
   144  	// then
   145  	require.Error(t, err)
   146  	require.Nil(t, toSubmit)
   147  }
   148  
   149  func testSubmittingProposalForVolumeDiscountProgramUpdateWithTooHighDiscountFactorFails(t *testing.T) {
   150  	now := time.Now()
   151  	ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64())
   152  	eng := getTestEngine(t, now)
   153  
   154  	// setup
   155  	eng.broker.EXPECT().Send(gomock.Any()).Times(3)
   156  	eng.netp.Update(ctx, netparams.GovernanceProposalVolumeDiscountProgramMinClose, "48h")
   157  	eng.netp.Update(ctx, netparams.GovernanceProposalVolumeDiscountProgramMinEnact, "48h")
   158  	eng.netp.Update(ctx, netparams.GovernanceProposalVolumeDiscountProgramMinProposerBalance, "1000")
   159  
   160  	eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.VolumeDiscountProgramMaxBenefitTiers, "2")).Times(1)
   161  	require.NoError(t, eng.netp.Update(ctx, netparams.VolumeDiscountProgramMaxBenefitTiers, "2"))
   162  
   163  	eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.VolumeDiscountProgramMaxVolumeDiscountFactor, "0.010")).Times(1)
   164  	require.NoError(t, eng.netp.Update(ctx, netparams.VolumeDiscountProgramMaxVolumeDiscountFactor, "0.010"))
   165  
   166  	// given
   167  	proposer := vgrand.RandomStr(5)
   168  	proposal := eng.newProposalForVolumeDiscountProgramUpdate(proposer, now, &types.VolumeDiscountProgramChanges{
   169  		EndOfProgramTimestamp: now.Add(4 * 48 * time.Hour),
   170  		WindowLength:          15,
   171  		VolumeBenefitTiers: []*types.VolumeBenefitTier{
   172  			{
   173  				MinimumRunningNotionalTakerVolume: num.NewUint(10000),
   174  				VolumeDiscountFactors: types.Factors{
   175  					Infra:     num.DecimalFromFloat(0.001),
   176  					Maker:     num.DecimalFromFloat(0.001),
   177  					Liquidity: num.DecimalFromFloat(0.001),
   178  				},
   179  			}, {
   180  				MinimumRunningNotionalTakerVolume: num.NewUint(20000),
   181  				VolumeDiscountFactors: types.Factors{
   182  					Infra:     num.DecimalFromFloat(0.015),
   183  					Maker:     num.DecimalFromFloat(0.015),
   184  					Liquidity: num.DecimalFromFloat(0.015),
   185  				},
   186  			},
   187  		},
   188  	})
   189  
   190  	// setup
   191  	eng.ensureTokenBalanceForParty(t, proposer, 1000)
   192  
   193  	// expect
   194  	eng.expectRejectedProposalEvent(t, proposer, proposal.ID, types.ProposalErrorInvalidVolumeDiscountProgram)
   195  
   196  	// when
   197  	toSubmit, err := eng.submitProposal(t, proposal)
   198  
   199  	// then
   200  	require.EqualError(t,
   201  		err,
   202  		"tier 2 defines a volume discount infrastructure factor higher than the maximum allowed by the network parameter \"volumeDiscountProgram.maxVolumeDiscountFactor\": maximum is 0.01, but got 0.015",
   203  	)
   204  	require.Nil(t, toSubmit)
   205  }