code.vegaprotocol.io/vega@v0.79.0/core/banking/fee_discount_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 banking_test
    17  
    18  import (
    19  	"context"
    20  	"testing"
    21  
    22  	"code.vegaprotocol.io/vega/core/assets"
    23  	"code.vegaprotocol.io/vega/core/assets/builtin"
    24  	"code.vegaprotocol.io/vega/core/types"
    25  	"code.vegaprotocol.io/vega/libs/num"
    26  	proto "code.vegaprotocol.io/vega/protos/vega"
    27  
    28  	"github.com/golang/mock/gomock"
    29  	"github.com/stretchr/testify/assert"
    30  )
    31  
    32  func TestBankingTransactionFeeDiscount(t *testing.T) {
    33  	party := "party-1"
    34  	asset := assets.NewAsset(builtin.New("vega", &types.AssetDetails{
    35  		Name:    "vega",
    36  		Symbol:  "vega",
    37  		Quantum: num.DecimalFromFloat(10),
    38  	}))
    39  	assetID := asset.Type().ID
    40  
    41  	t.Run("decay amount", func(t *testing.T) {
    42  		eng := getTestEngine(t)
    43  
    44  		ctx := context.Background()
    45  		eng.broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
    46  		eng.broker.EXPECT().Send(gomock.Any()).AnyTimes()
    47  		eng.assets.EXPECT().Get(gomock.Any()).Return(asset, nil).AnyTimes()
    48  
    49  		eng.OnTransferFeeDiscountDecayFractionUpdate(context.Background(), num.DecimalFromFloat(0.5))
    50  		eng.OnTransferFeeDiscountMinimumTrackedAmountUpdate(context.Background(), num.DecimalFromFloat(1))
    51  
    52  		asset2 := "asset-2"
    53  		party2 := "party-2"
    54  
    55  		assert.Equal(t, "0", eng.AvailableFeeDiscount(assetID, party).String())
    56  		assert.Equal(t, "0", eng.AvailableFeeDiscount(asset2, party2).String())
    57  		eng.RegisterTradingFees(ctx, assetID, map[string]*num.Uint{party: num.NewUint(25)})
    58  		eng.RegisterTradingFees(ctx, assetID, map[string]*num.Uint{party: num.NewUint(25)})
    59  		eng.RegisterTradingFees(ctx, asset2, map[string]*num.Uint{party2: num.NewUint(20)})
    60  		eng.OnEpoch(ctx, types.Epoch{Action: proto.EpochAction_EPOCH_ACTION_END})
    61  		assert.Equal(t, "50", eng.AvailableFeeDiscount(assetID, party).String())
    62  		assert.Equal(t, "20", eng.AvailableFeeDiscount(asset2, party2).String())
    63  		eng.RegisterTradingFees(ctx, assetID, nil)
    64  		eng.OnEpoch(ctx, types.Epoch{Action: proto.EpochAction_EPOCH_ACTION_END})
    65  		// decay by half
    66  		assert.Equal(t, "25", eng.AvailableFeeDiscount(assetID, party).String())
    67  		assert.Equal(t, "10", eng.AvailableFeeDiscount(asset2, party2).String())
    68  		eng.RegisterTradingFees(ctx, assetID, nil)
    69  		eng.OnEpoch(ctx, types.Epoch{Action: proto.EpochAction_EPOCH_ACTION_END})
    70  		// decay by half
    71  		assert.Equal(t, "12", eng.AvailableFeeDiscount(assetID, party).String())
    72  		assert.Equal(t, "0", eng.AvailableFeeDiscount(asset2, party2).String())
    73  		eng.RegisterTradingFees(ctx, assetID, nil)
    74  		eng.OnEpoch(ctx, types.Epoch{Action: proto.EpochAction_EPOCH_ACTION_END})
    75  
    76  		// decay by half but it's 0 because decayed amount (6) is less then
    77  		// asset quantum x TransferFeeDiscountMinimumTrackedAmount (10 x 1)
    78  		assert.Equal(t, "0", eng.AvailableFeeDiscount(assetID, party).String())
    79  	})
    80  
    81  	t.Run("apply fee discount", func(t *testing.T) {
    82  		eng := getTestEngine(t)
    83  
    84  		ctx := context.Background()
    85  		eng.broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
    86  		eng.broker.EXPECT().Send(gomock.Any()).AnyTimes()
    87  		eng.assets.EXPECT().Get(gomock.Any()).Return(asset, nil).AnyTimes()
    88  
    89  		eng.OnTransferFeeDiscountDecayFractionUpdate(context.Background(), num.DecimalFromFloat(0.5))
    90  
    91  		assert.Equal(t, "0", eng.AvailableFeeDiscount(assetID, party).String())
    92  
    93  		// expect the whole fee to be paid
    94  		discountedFee, discount := eng.ApplyFeeDiscount(ctx, assetID, party, num.NewUint(5))
    95  		assert.Equal(t, "5", discountedFee.String())
    96  		assert.Equal(t, "0", discount.String())
    97  		eng.RegisterTradingFees(ctx, assetID, map[string]*num.Uint{party: num.NewUint(10)})
    98  		// move to another epoch
    99  		eng.OnEpoch(ctx, types.Epoch{Action: proto.EpochAction_EPOCH_ACTION_END})
   100  
   101  		assert.Equal(t, "10", eng.AvailableFeeDiscount(assetID, party).String())
   102  
   103  		// expect discount of 10 to be applied
   104  		discountedFee, discount = eng.ApplyFeeDiscount(ctx, assetID, party, num.NewUint(15))
   105  		assert.Equal(t, "5", discountedFee.String())
   106  		assert.Equal(t, "10", discount.String())
   107  		eng.RegisterTradingFees(ctx, assetID, map[string]*num.Uint{party: num.NewUint(20)})
   108  		// move to another epoch
   109  		eng.OnEpoch(ctx, types.Epoch{Action: proto.EpochAction_EPOCH_ACTION_END})
   110  
   111  		assert.Equal(t, "20", eng.AvailableFeeDiscount(assetID, party).String())
   112  
   113  		// expect discount of 3 to be applied
   114  		discountedFee, discount = eng.ApplyFeeDiscount(ctx, assetID, party, num.NewUint(3))
   115  		assert.Equal(t, "0", discountedFee.String())
   116  		assert.Equal(t, "3", discount.String())
   117  
   118  		assert.Equal(t, "17", eng.AvailableFeeDiscount(assetID, party).String())
   119  
   120  		eng.RegisterTradingFees(ctx, assetID, map[string]*num.Uint{party: num.NewUint(5)})
   121  		// move to another epoch
   122  		eng.OnEpoch(ctx, types.Epoch{Action: proto.EpochAction_EPOCH_ACTION_END})
   123  
   124  		// it's 13 because 9 was decayed and extra 5 added = 17-8+5
   125  		assert.Equal(t, "13", eng.AvailableFeeDiscount(assetID, party).String())
   126  
   127  		// expect discount of 4 to be applied
   128  		discountedFee, discount = eng.ApplyFeeDiscount(ctx, assetID, party, num.NewUint(4))
   129  		assert.Equal(t, "0", discountedFee.String())
   130  		assert.Equal(t, "4", discount.String())
   131  	})
   132  }