Skip to content

Commit

Permalink
Merge pull request #11659 from vegaprotocol/11652
Browse files Browse the repository at this point in the history
fix: apply discounts (effectively just maker rebate) on network trades
  • Loading branch information
ze97286 authored Sep 5, 2024
2 parents f9038a9 + 5f4c141 commit 182f79e
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 23 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
- [11583](https://github.com/vegaprotocol/vega/issues/11583) - Rough bound on price interval when matching with `AMMs` is now looser and calculated in the `AMM` engine.
- [11624](https://github.com/vegaprotocol/vega/issues/11624) - prevent creation of rewards with no payout, but with high computational cost.
- [11619](https://github.com/vegaprotocol/vega/issues/11619) - Fix `EstimatePositions` API for capped futures.
- [11652](https://github.com/vegaprotocol/vega/issues/11652) - Apply fees and discounts on network disposal trades.
- [11645](https://github.com/vegaprotocol/vega/issues/11645) - Support party stats with no markets to retrieve for all markets.


## 0.78.0

### 🛠 Improvements
Expand Down
2 changes: 1 addition & 1 deletion core/execution/future/liquidation.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (m *Market) checkNetwork(ctx context.Context, now time.Time) error {
return nil
}
// transfer fees to the good party -> fees are now taken from the insurance pool
fees, _ := m.fee.GetFeeForPositionResolution(conf.Trades)
fees, _ := m.fee.GetFeeForPositionResolution(conf.Trades, m.referralDiscountRewardService, m.volumeDiscountService, m.volumeRebateService)
tresps, err := m.collateral.TransferFees(ctx, m.GetID(), m.settlementAsset, fees)
if err != nil {
// we probably should reject the order, although if we end up here we have a massive problem.
Expand Down
71 changes: 57 additions & 14 deletions core/fee/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func (e *Engine) CalculateForContinuousMode(

e.feesStats.RegisterMakerFee(maker, taker, fee.MakerFee)

totalTradingFees := num.UintZero().AddSum(fee.MakerFee, fee.InfrastructureFee, fee.LiquidityFee)
totalTradingFees := num.UintZero().AddSum(fee.MakerFee, fee.InfrastructureFee, fee.LiquidityFee, fee.BuyBackFee, fee.TreasuryFee, fee.HighVolumeMakerFee)

switch trade.Aggressor {
case types.SideBuy:
Expand Down Expand Up @@ -451,26 +451,41 @@ func (e *Engine) CalculateForFrequentBatchesAuctionMode(
}, nil
}

func (e *Engine) GetFeeForPositionResolution(trades []*types.Trade) (events.FeesTransfer, *types.Fee) {
func (e *Engine) GetFeeForPositionResolution(trades []*types.Trade,
referral ReferralDiscountRewardService,
volumeDiscount VolumeDiscountService,
volumeRebate VolumeRebateService,
) (events.FeesTransfer, *types.Fee) {
if len(trades) == 0 {
return nil, nil
}
var (
netFee *types.Fee
gt *types.Transfer
gt []*types.Transfer
)
transfers := make([]*types.Transfer, 0, len(trades))
for _, t := range trades {
fees := e.calculateContinuousModeFees(t)

maker := t.Buyer
if t.Buyer == types.NetworkParty {
maker = t.Seller
}
size := num.NewUint(t.Size)
// multiply by size
tradeValueForFee := size.Mul(t.Price, size).ToDecimal().Div(e.positionFactor)
postRewardDiscountFees, _ := e.applyDiscountsAndRewards(types.NetworkParty, maker, tradeValueForFee, fees, referral, volumeDiscount, volumeRebate)
e.feesStats.RegisterMakerFee(maker, types.NetworkParty, postRewardDiscountFees.MakerFee)

goodParty := t.Buyer
t.SellerFee = fees
t.SellerFee = postRewardDiscountFees
if t.Buyer == types.NetworkParty {
goodParty = t.Seller
t.SellerFee = types.NewFee()
t.BuyerFee = fees
t.BuyerFee = postRewardDiscountFees
}
netFee, gt = e.getNetworkFeeWithMakerTransfer(fees, netFee, goodParty)
transfers = append(transfers, gt)
netFee, gt = e.getNetworkFeeWithMakerTransfer(postRewardDiscountFees, netFee, goodParty)
transfers = append(transfers, gt...)
}
netTf, total := e.getNetworkFeeTransfers(netFee)
// calculate the
Expand Down Expand Up @@ -549,29 +564,44 @@ func (e *Engine) buildLiquidityFeesTransfer(
return ft
}

func (e *Engine) getNetworkFeeWithMakerTransfer(fees *types.Fee, current *types.Fee, goodParty string) (*types.Fee, *types.Transfer) {
transfer := &types.Transfer{
func (e *Engine) getNetworkFeeWithMakerTransfer(fees *types.Fee, current *types.Fee, goodParty string) (*types.Fee, []*types.Transfer) {
transfers := []*types.Transfer{}
transfers = append(transfers, &types.Transfer{
Owner: goodParty,
Amount: &types.FinancialAmount{
Asset: e.asset,
Amount: fees.MakerFee,
Amount: fees.MakerFee.Clone(),
},
MinAmount: num.UintZero(),
Type: types.TransferTypeMakerFeeReceive,
})
if !fees.HighVolumeMakerFee.IsZero() {
transfers = append(transfers, &types.Transfer{
Owner: goodParty,
Amount: &types.FinancialAmount{
Asset: e.asset,
Amount: fees.HighVolumeMakerFee,
},
MinAmount: num.UintZero(),
Type: types.TransferTypeHighMakerRebateReceive,
})
}

if current == nil {
return fees.Clone(), transfer
return fees.Clone(), transfers
}
current.MakerFee.AddSum(fees.MakerFee)
current.LiquidityFee.AddSum(fees.LiquidityFee)
current.InfrastructureFee.AddSum(fees.InfrastructureFee)
current.BuyBackFee.AddSum(fees.BuyBackFee)
current.TreasuryFee.AddSum(fees.TreasuryFee)
return current, transfer
current.HighVolumeMakerFee.AddSum(fees.HighVolumeMakerFee)

return current, transfers
}

func (e *Engine) getNetworkFeeTransfers(fees *types.Fee) ([]*types.Transfer, *num.Uint) {
return []*types.Transfer{
transfers := []*types.Transfer{
{
Owner: types.NetworkParty,
Amount: &types.FinancialAmount{
Expand Down Expand Up @@ -617,7 +647,20 @@ func (e *Engine) getNetworkFeeTransfers(fees *types.Fee) ([]*types.Transfer, *nu
MinAmount: num.UintZero(),
Type: types.TransferTypeTreasuryPay,
},
}, num.Sum(fees.MakerFee, fees.InfrastructureFee, fees.LiquidityFee)
}
if !fees.HighVolumeMakerFee.IsZero() {
transfers = append(transfers, &types.Transfer{
Owner: types.NetworkParty,
Amount: &types.FinancialAmount{
Asset: e.asset,
Amount: fees.HighVolumeMakerFee.Clone(),
},
MinAmount: num.UintZero(),
Type: types.TransferTypeHighMakerRebatePay,
})
}

return transfers, num.Sum(fees.MakerFee, fees.InfrastructureFee, fees.LiquidityFee, fees.BuyBackFee, fees.HighVolumeMakerFee)
}

func (e *Engine) applyDiscountsAndRewards(taker string, maker string, tradeValueForFeePurposes num.Decimal, fees *types.Fee, referral ReferralDiscountRewardService, volumeDiscount VolumeDiscountService, volumeRebate VolumeRebateService) (*types.Fee, *types.ReferrerReward) {
Expand Down
19 changes: 12 additions & 7 deletions core/fee/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,8 @@ func testCalcContinuousTradingAndCheckAmountsExtended(t *testing.T) {
TotalFeesPaidAndReceived: []*eventspb.PartyAmount{
{
Party: "party1",
Amount: "875",
QuantumAmount: "875",
Amount: "3375",
QuantumAmount: "3375",
},
{
Party: "party2",
Expand Down Expand Up @@ -744,8 +744,8 @@ func testCalcContinuousTradingAndCheckAmountsWithDiscountExtended(t *testing.T)
TotalFeesPaidAndReceived: []*eventspb.PartyAmount{
{
Party: "party1",
Amount: "443",
QuantumAmount: "443",
Amount: "2943",
QuantumAmount: "2943",
},
{
Party: "party2",
Expand Down Expand Up @@ -1204,7 +1204,7 @@ func testCalcContinuousTradingExtended(t *testing.T) {
feeAmounts := ft.TotalFeesAmountPerParty()
party1Amount, ok := feeAmounts["party1"]
assert.True(t, ok)
assert.Equal(t, num.NewUint(43928), party1Amount)
assert.Equal(t, num.NewUint(45221), party1Amount)

// get the transfer and check we have enough of each types
transfers := ft.Transfers()
Expand Down Expand Up @@ -1670,12 +1670,17 @@ func testCalcBatchAuctionTradingDifferentBatches(t *testing.T) {
func testCloseoutFees(t *testing.T) {
eng := getTestFee(t)
ctrl := gomock.NewController(t)
referralDiscountService := mocks.NewMockReferralDiscountRewardService(ctrl)
referralDiscountService.EXPECT().RewardsFactorsMultiplierAppliedForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes()
discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl)
volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl)
volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
discountRewardService.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes()
discountRewardService.EXPECT().RewardsFactorsMultiplierAppliedForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes()
volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes()
discountRewardService.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("not a referrer")).AnyTimes()
referralDiscountService.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes()
volumeRebateService.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes()
trades := []*types.Trade{
{
Aggressor: types.SideSell,
Expand Down Expand Up @@ -1707,10 +1712,10 @@ func testCloseoutFees(t *testing.T) {
},
}

ft, fee := eng.GetFeeForPositionResolution(trades)
ft, fee := eng.GetFeeForPositionResolution(trades, referralDiscountService, volumeDiscountService, volumeRebateService)
assert.NotNil(t, fee)
allTransfers := ft.Transfers()
// first we have the network -> pay transfers, then 1 transfer per good party
// first we have the network -> pay transfers , then 1 transfer per good party
// two additional transfers for the buy back and treasury fees
assert.Equal(t, len(trades), len(allTransfers)-5)
goodPartyTransfers := allTransfers[5:]
Expand Down

0 comments on commit 182f79e

Please sign in to comment.