code.vegaprotocol.io/vega@v0.79.0/core/fee/engine.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 fee 17 18 import ( 19 "errors" 20 "sort" 21 22 "code.vegaprotocol.io/vega/core/events" 23 "code.vegaprotocol.io/vega/core/types" 24 "code.vegaprotocol.io/vega/libs/num" 25 "code.vegaprotocol.io/vega/logging" 26 eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1" 27 ) 28 29 var ( 30 ErrEmptyTrades = errors.New("empty trades slice sent to fees") 31 ErrInvalidFeeFactor = errors.New("fee factors must be positive") 32 ) 33 34 //go:generate go run github.com/golang/mock/mockgen -destination mocks/mocks.go -package mocks code.vegaprotocol.io/vega/core/fee ReferralDiscountRewardService,VolumeDiscountService,VolumeRebateService 35 type ReferralDiscountRewardService interface { 36 ReferralDiscountFactorsForParty(party types.PartyID) types.Factors 37 RewardsFactorsMultiplierAppliedForParty(party types.PartyID) types.Factors 38 GetReferrer(referee types.PartyID) (types.PartyID, error) 39 } 40 41 type VolumeDiscountService interface { 42 VolumeDiscountFactorForParty(party types.PartyID) types.Factors 43 } 44 45 type VolumeRebateService interface { 46 VolumeRebateFactorForParty(party types.PartyID) num.Decimal 47 } 48 49 type Engine struct { 50 log *logging.Logger 51 cfg Config 52 53 asset string 54 feeCfg types.Fees 55 f factors 56 positionFactor num.Decimal 57 58 feesStats *FeesStats 59 } 60 61 type factors struct { 62 makerFee num.Decimal 63 infrastructureFee num.Decimal 64 liquidityFee num.Decimal 65 treasuryFee num.Decimal 66 buyBackFee num.Decimal 67 } 68 69 func New( 70 log *logging.Logger, 71 cfg Config, 72 feeCfg types.Fees, 73 asset string, 74 positionFactor num.Decimal, 75 ) (*Engine, error) { 76 log = log.Named(namedLogger) 77 log.SetLevel(cfg.Level.Get()) 78 79 e := &Engine{ 80 log: log, 81 feeCfg: feeCfg, 82 cfg: cfg, 83 asset: asset, 84 positionFactor: positionFactor, 85 feesStats: NewFeesStats(), 86 } 87 return e, e.UpdateFeeFactors(e.feeCfg) 88 } 89 90 func NewFromState( 91 log *logging.Logger, 92 cfg Config, 93 feeCfg types.Fees, 94 asset string, 95 positionFactor num.Decimal, 96 FeesStats *eventspb.FeesStats, 97 ) (*Engine, error) { 98 e, err := New(log, cfg, feeCfg, asset, positionFactor) 99 if err != nil { 100 return nil, err 101 } 102 103 e.feesStats = NewFeesStatsFromProto(FeesStats) 104 105 return e, nil 106 } 107 108 func (e *Engine) GetState(assetQuantum num.Decimal) *eventspb.FeesStats { 109 return e.feesStats.ToProto(e.asset, assetQuantum) 110 } 111 112 func (e *Engine) TotalTradingFeesPerParty() map[string]*num.Uint { 113 return e.feesStats.TotalTradingFeesPerParty() 114 } 115 116 func (e *Engine) GetFeesStatsOnEpochEnd(assetQuantum num.Decimal) (FeesStats *eventspb.FeesStats) { 117 FeesStats, e.feesStats = e.feesStats.ToProto(e.asset, assetQuantum), NewFeesStats() 118 return 119 } 120 121 // ReloadConf is used in order to reload the internal configuration of 122 // the fee engine. 123 func (e *Engine) ReloadConf(cfg Config) { 124 e.log.Info("reloading configuration") 125 if e.log.GetLevel() != cfg.Level.Get() { 126 e.log.Info("updating log level", 127 logging.String("old", e.log.GetLevel().String()), 128 logging.String("new", cfg.Level.String()), 129 ) 130 e.log.SetLevel(cfg.Level.Get()) 131 } 132 133 e.cfg = cfg 134 } 135 136 func (e *Engine) UpdateFeeFactors(fees types.Fees) error { 137 if fees.Factors.MakerFee.IsNegative() || fees.Factors.InfrastructureFee.IsNegative() || fees.Factors.LiquidityFee.IsNegative() || fees.Factors.BuyBackFee.IsNegative() || fees.Factors.TreasuryFee.IsNegative() { 138 return ErrInvalidFeeFactor 139 } 140 e.f.makerFee = fees.Factors.MakerFee 141 e.f.infrastructureFee = fees.Factors.InfrastructureFee 142 // not sure we need the IsPositive check here, that ought to be validation 143 if !fees.Factors.LiquidityFee.IsZero() && fees.Factors.LiquidityFee.IsPositive() { 144 e.f.liquidityFee = fees.Factors.LiquidityFee 145 } 146 e.f.treasuryFee = fees.Factors.TreasuryFee 147 e.f.buyBackFee = fees.Factors.BuyBackFee 148 149 e.feeCfg = fees 150 return nil 151 } 152 153 func (e *Engine) SetLiquidityFee(v num.Decimal) { 154 e.f.liquidityFee = v 155 } 156 157 // CalculateForContinuousMode calculate the fee for 158 // trades which were produced from a market running 159 // in continuous trading mode. 160 // A single FeesTransfer is produced here as all fees 161 // are paid by the aggressive order. 162 func (e *Engine) CalculateForContinuousMode( 163 trades []*types.Trade, 164 referral ReferralDiscountRewardService, 165 volumeDiscountService VolumeDiscountService, 166 volumeRebateService VolumeRebateService, 167 ) (events.FeesTransfer, error) { 168 if len(trades) <= 0 { 169 return nil, ErrEmptyTrades 170 } 171 172 var ( 173 taker, maker string 174 totalFeeAmount = num.UintZero() 175 totalInfrastructureFeeAmount = num.UintZero() 176 totalLiquidityFeeAmount = num.UintZero() 177 totalRewardAmount = num.UintZero() 178 // we allocate the len of the trades + 2 179 // len(trade) = number of makerFee + 1 infra fee + 1 liquidity fee 180 transfers = make([]*types.Transfer, 0, (len(trades)*2)+2) 181 transfersRecv = make([]*types.Transfer, 0, len(trades)+2) 182 ) 183 184 for _, trade := range trades { 185 taker = trade.Buyer 186 maker = trade.Seller 187 if trade.Aggressor == types.SideSell { 188 taker = trade.Seller 189 maker = trade.Buyer 190 } 191 size := num.NewUint(trade.Size) 192 // multiply by size 193 tradeValueForFee := size.Mul(trade.Price, size).ToDecimal().Div(e.positionFactor) 194 fee, reward := e.applyDiscountsAndRewards(taker, maker, tradeValueForFee, e.calculateContinuousModeFees(trade), referral, volumeDiscountService, volumeRebateService) 195 196 e.feesStats.RegisterMakerFee(maker, taker, fee.MakerFee) 197 198 totalTradingFees := num.UintZero().AddSum(fee.MakerFee, fee.InfrastructureFee, fee.LiquidityFee, fee.BuyBackFee, fee.TreasuryFee, fee.HighVolumeMakerFee) 199 200 switch trade.Aggressor { 201 case types.SideBuy: 202 trade.BuyerFee = fee 203 trade.SellerFee = types.NewFee() 204 maker = trade.Seller 205 case types.SideSell: 206 trade.SellerFee = fee 207 trade.BuyerFee = types.NewFee() 208 maker = trade.Buyer 209 } 210 211 e.feesStats.RegisterTradingFees(taker, totalTradingFees) 212 e.feesStats.RegisterTradingFees(maker, fee.MakerFee) 213 214 totalFeeAmount.AddSum(totalTradingFees) 215 totalInfrastructureFeeAmount.AddSum(fee.InfrastructureFee) 216 totalLiquidityFeeAmount.AddSum(fee.LiquidityFee) 217 // create a transfer for the aggressor 218 transfers = append(transfers, &types.Transfer{ 219 Owner: taker, 220 Amount: &types.FinancialAmount{ 221 Asset: e.asset, 222 Amount: fee.MakerFee.Clone(), 223 }, 224 Type: types.TransferTypeMakerFeePay, 225 }) 226 // create a transfer for the maker 227 transfersRecv = append(transfersRecv, &types.Transfer{ 228 Owner: maker, 229 Amount: &types.FinancialAmount{ 230 Asset: e.asset, 231 Amount: fee.MakerFee.Clone(), 232 }, 233 Type: types.TransferTypeMakerFeeReceive, 234 }) 235 236 if !fee.HighVolumeMakerFee.IsZero() { 237 // create a transfer for the aggressor 238 transfers = append(transfers, &types.Transfer{ 239 Owner: taker, 240 Amount: &types.FinancialAmount{ 241 Asset: e.asset, 242 Amount: fee.HighVolumeMakerFee.Clone(), 243 }, 244 Type: types.TransferTypeHighMakerRebatePay, 245 }) 246 // create a transfer for the maker 247 transfersRecv = append(transfersRecv, &types.Transfer{ 248 Owner: maker, 249 Amount: &types.FinancialAmount{ 250 Asset: e.asset, 251 Amount: fee.HighVolumeMakerFee.Clone(), 252 }, 253 Type: types.TransferTypeHighMakerRebateReceive, 254 }) 255 } 256 257 // create a transfer for the aggressor 258 transfers = append(transfers, &types.Transfer{ 259 Owner: taker, 260 Amount: &types.FinancialAmount{ 261 Asset: e.asset, 262 Amount: fee.BuyBackFee.Clone(), 263 }, 264 Type: types.TransferTypeBuyBackFeePay, 265 }) 266 267 // create a transfer for the aggressor 268 transfers = append(transfers, &types.Transfer{ 269 Owner: taker, 270 Amount: &types.FinancialAmount{ 271 Asset: e.asset, 272 Amount: fee.TreasuryFee.Clone(), 273 }, 274 Type: types.TransferTypeTreasuryPay, 275 }) 276 277 if reward == nil { 278 continue 279 } 280 totalRewardAmount.AddSum(reward.InfrastructureFeeReferrerReward) 281 totalRewardAmount.AddSum(reward.LiquidityFeeReferrerReward) 282 totalRewardAmount.AddSum(reward.MakerFeeReferrerReward) 283 } 284 285 // now create transfer for the infrastructure 286 transfers = append(transfers, &types.Transfer{ 287 Owner: taker, 288 Amount: &types.FinancialAmount{ 289 Asset: e.asset, 290 Amount: totalInfrastructureFeeAmount, 291 }, 292 Type: types.TransferTypeInfrastructureFeePay, 293 }) 294 // now create transfer for the liquidity 295 transfers = append(transfers, &types.Transfer{ 296 Owner: taker, 297 Amount: &types.FinancialAmount{ 298 Asset: e.asset, 299 Amount: totalLiquidityFeeAmount, 300 }, 301 Type: types.TransferTypeLiquidityFeePay, 302 }) 303 304 // if there's a referral reward - add transfers for it 305 if !totalRewardAmount.IsZero() { 306 referrer, _ := referral.GetReferrer(types.PartyID(taker)) 307 transfers = append(transfers, &types.Transfer{ 308 Owner: taker, 309 Amount: &types.FinancialAmount{ 310 Asset: e.asset, 311 Amount: totalRewardAmount.Clone(), 312 }, 313 Type: types.TransferTypeFeeReferrerRewardPay, 314 }) 315 transfersRecv = append(transfersRecv, &types.Transfer{ 316 Owner: string(referrer), 317 Amount: &types.FinancialAmount{ 318 Asset: e.asset, 319 Amount: totalRewardAmount.Clone(), 320 }, 321 Type: types.TransferTypeFeeReferrerRewardDistribute, 322 }) 323 } 324 325 return &feesTransfer{ 326 totalFeesAmountsPerParty: map[string]*num.Uint{taker: totalFeeAmount, maker: num.UintZero()}, 327 transfers: append(transfers, transfersRecv...), 328 }, nil 329 } 330 331 // CalculateForAuctionMode calculate the fee for 332 // trades which were produced from a market running in 333 // in auction trading mode. 334 // A list FeesTransfer is produced each containing fees transfer from a 335 // single party. 336 func (e *Engine) CalculateForAuctionMode( 337 trades []*types.Trade, 338 referral ReferralDiscountRewardService, 339 volumeDiscount VolumeDiscountService, 340 volumeRebate VolumeRebateService, 341 ) (events.FeesTransfer, error) { 342 if len(trades) <= 0 { 343 return nil, ErrEmptyTrades 344 } 345 var ( 346 totalFeesAmounts = map[string]*num.Uint{} 347 // we allocate for len of trades *4 as all trades generate 348 // 2 fees per party 349 transfers = make([]*types.Transfer, 0, len(trades)*4) 350 ) 351 352 // we iterate over all trades 353 // for each trades both party needs to pay half of the fees 354 // no maker fees are to be paid here. 355 for _, v := range trades { 356 buyerFess, sellerFees, newTransfers := e.getAuctionModeFeesAndTransfers(v, referral, volumeDiscount, volumeRebate) 357 transfers = append(transfers, newTransfers...) 358 359 // increase the total fee for the parties 360 if sellerTotalFee, ok := totalFeesAmounts[v.Seller]; !ok { 361 totalFeesAmounts[v.Seller] = num.Sum(sellerFees.InfrastructureFee, sellerFees.LiquidityFee) 362 } else { 363 sellerTotalFee.AddSum(num.Sum(sellerFees.InfrastructureFee, sellerFees.LiquidityFee)) 364 } 365 if buyerTotalFee, ok := totalFeesAmounts[v.Buyer]; !ok { 366 totalFeesAmounts[v.Buyer] = num.Sum(buyerFess.InfrastructureFee, buyerFess.LiquidityFee).Clone() 367 } else { 368 buyerTotalFee.AddSum(num.Sum(buyerFess.InfrastructureFee, buyerFess.LiquidityFee).Clone()) 369 } 370 371 v.BuyerFee = buyerFess 372 v.SellerFee = sellerFees 373 } 374 375 return &feesTransfer{ 376 totalFeesAmountsPerParty: totalFeesAmounts, 377 transfers: transfers, 378 }, nil 379 } 380 381 // CalculateForFrequentBatchesAuctionMode calculate the fee for 382 // trades which were produced from a market running 383 // in auction trading mode. 384 // A list FeesTransfer is produced each containing fees transfer from a 385 // single party. 386 func (e *Engine) CalculateForFrequentBatchesAuctionMode( 387 trades []*types.Trade, 388 referral ReferralDiscountRewardService, 389 volumeDiscount VolumeDiscountService, 390 volumeRebate VolumeRebateService, 391 ) (events.FeesTransfer, error) { 392 if len(trades) <= 0 { 393 return nil, ErrEmptyTrades 394 } 395 396 var ( 397 totalFeesAmounts = map[string]*num.Uint{} 398 // we allocate for len of trades *4 as all trades generate 399 // at lest2 fees per party 400 transfers = make([]*types.Transfer, 0, len(trades)*4) 401 ) 402 403 // we iterate over all trades 404 // if the parties submitted the order in the same batches, 405 // auction mode fees apply. 406 // if not then the aggressor is the party which submitted 407 // the order last, and continuous trading fees apply 408 for _, v := range trades { 409 var ( 410 sellerTotalFee, buyerTotalFee *num.Uint 411 newTransfers []*types.Transfer 412 ) 413 // we are in the same auction, normal auction fees applies 414 if v.BuyerAuctionBatch == v.SellerAuctionBatch { 415 v.BuyerFee, v.SellerFee, newTransfers = e.getAuctionModeFeesAndTransfers(v, referral, volumeDiscount, volumeRebate) 416 sellerTotalFee = num.Sum(v.BuyerFee.InfrastructureFee, v.BuyerFee.LiquidityFee) 417 buyerTotalFee = num.Sum(v.SellerFee.InfrastructureFee, v.SellerFee.LiquidityFee) 418 } else { 419 // set the aggressor to be the side of the party 420 // entering the later auction 421 v.Aggressor = types.SideSell 422 if v.BuyerAuctionBatch > v.SellerAuctionBatch { 423 v.Aggressor = types.SideBuy 424 } 425 // fees are being assign to the trade directly 426 // no need to do add them there as well 427 ftrnsfr, _ := e.CalculateForContinuousMode([]*types.Trade{v}, referral, volumeDiscount, volumeRebate) 428 newTransfers = ftrnsfr.Transfers() 429 buyerTotalFee = ftrnsfr.TotalFeesAmountPerParty()[v.Buyer] 430 sellerTotalFee = ftrnsfr.TotalFeesAmountPerParty()[v.Seller] 431 } 432 433 transfers = append(transfers, newTransfers...) 434 435 // increase the total fee for the parties 436 if prevTotalFee, ok := totalFeesAmounts[v.Seller]; !ok { 437 totalFeesAmounts[v.Seller] = sellerTotalFee.Clone() 438 } else { 439 prevTotalFee.AddSum(sellerTotalFee) 440 } 441 if prevTotalFee, ok := totalFeesAmounts[v.Buyer]; !ok { 442 totalFeesAmounts[v.Buyer] = buyerTotalFee.Clone() 443 } else { 444 prevTotalFee.AddSum(buyerTotalFee) 445 } 446 } 447 448 return &feesTransfer{ 449 totalFeesAmountsPerParty: totalFeesAmounts, 450 transfers: transfers, 451 }, nil 452 } 453 454 func (e *Engine) GetFeeForPositionResolution(trades []*types.Trade, 455 referral ReferralDiscountRewardService, 456 volumeDiscount VolumeDiscountService, 457 volumeRebate VolumeRebateService, 458 ) (events.FeesTransfer, *types.Fee) { 459 if len(trades) == 0 { 460 return nil, nil 461 } 462 var ( 463 netFee *types.Fee 464 gt []*types.Transfer 465 ) 466 transfers := make([]*types.Transfer, 0, len(trades)) 467 for _, t := range trades { 468 fees := e.calculateContinuousModeFees(t) 469 470 maker := t.Buyer 471 if t.Buyer == types.NetworkParty { 472 maker = t.Seller 473 } 474 size := num.NewUint(t.Size) 475 // multiply by size 476 tradeValueForFee := size.Mul(t.Price, size).ToDecimal().Div(e.positionFactor) 477 postRewardDiscountFees, _ := e.applyDiscountsAndRewards(types.NetworkParty, maker, tradeValueForFee, fees, referral, volumeDiscount, volumeRebate) 478 e.feesStats.RegisterMakerFee(maker, types.NetworkParty, postRewardDiscountFees.MakerFee) 479 480 goodParty := t.Buyer 481 t.SellerFee = postRewardDiscountFees 482 if t.Buyer == types.NetworkParty { 483 goodParty = t.Seller 484 t.SellerFee = types.NewFee() 485 t.BuyerFee = postRewardDiscountFees 486 } 487 netFee, gt = e.getNetworkFeeWithMakerTransfer(postRewardDiscountFees, netFee, goodParty) 488 transfers = append(transfers, gt...) 489 } 490 netTf, total := e.getNetworkFeeTransfers(netFee) 491 // calculate the 492 return &feesTransfer{ 493 totalFeesAmountsPerParty: map[string]*num.Uint{ 494 types.NetworkParty: total, 495 }, 496 transfers: append(netTf, transfers...), 497 }, netFee 498 } 499 500 // BuildLiquidityFeeDistributionTransfer returns the set of transfers that will 501 // be used by the collateral engine to distribute the fees. As shares are 502 // represented in float64 and fees are uint64, shares are floored and the 503 // remainder is assigned to the last party on the share map. Note that the map 504 // is sorted lexicographically to keep determinism. 505 func (e *Engine) BuildLiquidityFeeDistributionTransfer(shares map[string]num.Decimal, acc *types.Account) events.FeesTransfer { 506 return e.buildLiquidityFeesTransfer(shares, acc, types.TransferTypeLiquidityFeeDistribute) 507 } 508 509 // BuildLiquidityFeeAllocationTransfer returns the set of transfers that will 510 // be used by the collateral engine to allocate the fees to liquidity providers per market fee accounts. 511 // As shares are represented in float64 and fees are uint64, shares are floored and the 512 // remainder is assigned to the last party on the share map. Note that the map 513 // is sorted lexicographically to keep determinism. 514 func (e *Engine) BuildLiquidityFeeAllocationTransfer(shares map[string]num.Decimal, acc *types.Account) events.FeesTransfer { 515 return e.buildLiquidityFeesTransfer(shares, acc, types.TransferTypeLiquidityFeeAllocate) 516 } 517 518 func (e *Engine) buildLiquidityFeesTransfer( 519 shares map[string]num.Decimal, 520 acc *types.Account, 521 transferType types.TransferType, 522 ) events.FeesTransfer { 523 if len(shares) == 0 { 524 return nil 525 } 526 527 ft := &feesTransfer{ 528 totalFeesAmountsPerParty: map[string]*num.Uint{}, 529 transfers: make([]*types.Transfer, 0, len(shares)), 530 } 531 532 // Get all the map keys 533 keys := make([]string, 0, len(shares)) 534 535 for key := range shares { 536 keys = append(keys, key) 537 ft.totalFeesAmountsPerParty[key] = num.UintZero() 538 } 539 sort.Strings(keys) 540 541 feeBal := acc.Balance.ToDecimal() 542 var floored num.Decimal 543 for _, key := range keys { 544 share := shares[key] 545 cs := feeBal.Mul(share).Floor() 546 floored = floored.Add(cs) 547 548 amount, _ := num.UintFromDecimal(cs) 549 // populate the return value 550 ft.totalFeesAmountsPerParty[key].AddSum(amount) 551 ft.transfers = append(ft.transfers, &types.Transfer{ 552 Owner: key, 553 Amount: &types.FinancialAmount{ 554 Amount: amount, 555 Asset: acc.Asset, 556 }, 557 MinAmount: amount.Clone(), 558 Type: transferType, 559 }) 560 } 561 562 // if there is a remainder, just keep it in the fee account, will be used next time we pay out fees 563 // last is the party who will get the remaining from ceil 564 return ft 565 } 566 567 func (e *Engine) getNetworkFeeWithMakerTransfer(fees *types.Fee, current *types.Fee, goodParty string) (*types.Fee, []*types.Transfer) { 568 transfers := []*types.Transfer{} 569 transfers = append(transfers, &types.Transfer{ 570 Owner: goodParty, 571 Amount: &types.FinancialAmount{ 572 Asset: e.asset, 573 Amount: fees.MakerFee.Clone(), 574 }, 575 MinAmount: num.UintZero(), 576 Type: types.TransferTypeMakerFeeReceive, 577 }) 578 if !fees.HighVolumeMakerFee.IsZero() { 579 transfers = append(transfers, &types.Transfer{ 580 Owner: goodParty, 581 Amount: &types.FinancialAmount{ 582 Asset: e.asset, 583 Amount: fees.HighVolumeMakerFee, 584 }, 585 MinAmount: num.UintZero(), 586 Type: types.TransferTypeHighMakerRebateReceive, 587 }) 588 } 589 590 if current == nil { 591 return fees.Clone(), transfers 592 } 593 current.MakerFee.AddSum(fees.MakerFee) 594 current.LiquidityFee.AddSum(fees.LiquidityFee) 595 current.InfrastructureFee.AddSum(fees.InfrastructureFee) 596 current.BuyBackFee.AddSum(fees.BuyBackFee) 597 current.TreasuryFee.AddSum(fees.TreasuryFee) 598 current.HighVolumeMakerFee.AddSum(fees.HighVolumeMakerFee) 599 600 return current, transfers 601 } 602 603 func (e *Engine) getNetworkFeeTransfers(fees *types.Fee) ([]*types.Transfer, *num.Uint) { 604 transfers := []*types.Transfer{ 605 { 606 Owner: types.NetworkParty, 607 Amount: &types.FinancialAmount{ 608 Asset: e.asset, 609 Amount: fees.MakerFee.Clone(), 610 }, 611 MinAmount: num.UintZero(), 612 Type: types.TransferTypeMakerFeePay, 613 }, 614 { 615 Owner: types.NetworkParty, 616 Amount: &types.FinancialAmount{ 617 Asset: e.asset, 618 Amount: fees.InfrastructureFee.Clone(), 619 }, 620 MinAmount: num.UintZero(), 621 Type: types.TransferTypeInfrastructureFeePay, 622 }, 623 { 624 Owner: types.NetworkParty, 625 Amount: &types.FinancialAmount{ 626 Asset: e.asset, 627 Amount: fees.LiquidityFee.Clone(), 628 }, 629 MinAmount: num.UintZero(), 630 Type: types.TransferTypeLiquidityFeePay, 631 }, 632 { 633 Owner: types.NetworkParty, 634 Amount: &types.FinancialAmount{ 635 Asset: e.asset, 636 Amount: fees.BuyBackFee.Clone(), 637 }, 638 MinAmount: num.UintZero(), 639 Type: types.TransferTypeBuyBackFeePay, 640 }, 641 { 642 Owner: types.NetworkParty, 643 Amount: &types.FinancialAmount{ 644 Asset: e.asset, 645 Amount: fees.TreasuryFee.Clone(), 646 }, 647 MinAmount: num.UintZero(), 648 Type: types.TransferTypeTreasuryPay, 649 }, 650 } 651 if !fees.HighVolumeMakerFee.IsZero() { 652 transfers = append(transfers, &types.Transfer{ 653 Owner: types.NetworkParty, 654 Amount: &types.FinancialAmount{ 655 Asset: e.asset, 656 Amount: fees.HighVolumeMakerFee.Clone(), 657 }, 658 MinAmount: num.UintZero(), 659 Type: types.TransferTypeHighMakerRebatePay, 660 }) 661 } 662 663 return transfers, num.Sum(fees.MakerFee, fees.InfrastructureFee, fees.LiquidityFee, fees.BuyBackFee, fees.HighVolumeMakerFee) 664 } 665 666 func (e *Engine) applyDiscountsAndRewards(taker string, maker string, tradeValueForFeePurposes num.Decimal, fees *types.Fee, referral ReferralDiscountRewardService, volumeDiscount VolumeDiscountService, volumeRebate VolumeRebateService) (*types.Fee, *types.ReferrerReward) { 667 referralDiscountFactors := referral.ReferralDiscountFactorsForParty(types.PartyID(taker)) 668 volumeDiscountFactors := volumeDiscount.VolumeDiscountFactorForParty(types.PartyID(taker)) 669 highVolumeMakerFee := volumeRebate.VolumeRebateFactorForParty(types.PartyID(maker)).Mul(tradeValueForFeePurposes) 670 highVolumeMakerFeeI, _ := num.UintFromDecimal(highVolumeMakerFee) 671 672 mf := fees.MakerFee.Clone() 673 inf := fees.InfrastructureFee.Clone() 674 lf := fees.LiquidityFee.Clone() 675 676 // calculate referral discounts 677 referralMakerDiscount, _ := num.UintFromDecimal(mf.ToDecimal().Mul(referralDiscountFactors.Maker).Floor()) 678 referralInfDiscount, _ := num.UintFromDecimal(inf.ToDecimal().Mul(referralDiscountFactors.Infra).Floor()) 679 referralLfDiscount, _ := num.UintFromDecimal(lf.ToDecimal().Mul(referralDiscountFactors.Liquidity).Floor()) 680 681 // apply referral discounts 682 mf = mf.Sub(mf, referralMakerDiscount) 683 inf = inf.Sub(inf, referralInfDiscount) 684 lf = lf.Sub(lf, referralLfDiscount) 685 686 // calculate volume discounts 687 volumeMakerDiscount, _ := num.UintFromDecimal(mf.ToDecimal().Mul(volumeDiscountFactors.Maker).Floor()) 688 volumeInfDiscount, _ := num.UintFromDecimal(inf.ToDecimal().Mul(volumeDiscountFactors.Infra).Floor()) 689 volumeLfDiscount, _ := num.UintFromDecimal(lf.ToDecimal().Mul(volumeDiscountFactors.Liquidity).Floor()) 690 691 var rebateDiscountFactor num.Decimal 692 bbAndTreasury := num.Sum(fees.BuyBackFee, fees.TreasuryFee).ToDecimal() 693 if !bbAndTreasury.IsZero() { 694 rebateDiscountFactor = num.DecimalOne().Sub(highVolumeMakerFee.Div(bbAndTreasury)) 695 } 696 697 treasuryFee, _ := num.UintFromDecimal(fees.TreasuryFee.ToDecimal().Mul(rebateDiscountFactor)) 698 buyBackFee, _ := num.UintFromDecimal(fees.BuyBackFee.ToDecimal().Mul(rebateDiscountFactor)) 699 700 // apply volume discounts 701 mf = mf.Sub(mf, volumeMakerDiscount) 702 inf = inf.Sub(inf, volumeInfDiscount) 703 lf = lf.Sub(lf, volumeLfDiscount) 704 705 f := &types.Fee{ 706 HighVolumeMakerFee: highVolumeMakerFeeI, 707 MakerFee: mf, 708 LiquidityFee: lf, 709 InfrastructureFee: inf, 710 BuyBackFee: buyBackFee.Clone(), 711 TreasuryFee: treasuryFee.Clone(), 712 MakerFeeVolumeDiscount: volumeMakerDiscount, 713 InfrastructureFeeVolumeDiscount: volumeInfDiscount, 714 LiquidityFeeVolumeDiscount: volumeLfDiscount, 715 MakerFeeReferrerDiscount: referralMakerDiscount, 716 InfrastructureFeeReferrerDiscount: referralInfDiscount, 717 LiquidityFeeReferrerDiscount: referralLfDiscount, 718 } 719 720 e.feesStats.RegisterRefereeDiscount( 721 taker, 722 num.Sum( 723 referralMakerDiscount, 724 referralInfDiscount, 725 referralLfDiscount, 726 ), 727 ) 728 729 e.feesStats.RegisterVolumeDiscount( 730 taker, 731 num.Sum( 732 volumeMakerDiscount, 733 volumeInfDiscount, 734 volumeLfDiscount, 735 ), 736 ) 737 738 // calculate rewards 739 factors := referral.RewardsFactorsMultiplierAppliedForParty(types.PartyID(taker)) 740 if factors.IsEmpty() { 741 return f, nil 742 } 743 744 referrerReward := types.NewReferrerReward() 745 746 referrerReward.MakerFeeReferrerReward, _ = num.UintFromDecimal(factors.Maker.Mul(mf.ToDecimal()).Floor()) 747 referrerReward.InfrastructureFeeReferrerReward, _ = num.UintFromDecimal(factors.Infra.Mul(inf.ToDecimal()).Floor()) 748 referrerReward.LiquidityFeeReferrerReward, _ = num.UintFromDecimal(factors.Liquidity.Mul(lf.ToDecimal()).Floor()) 749 750 mf = mf.Sub(mf, referrerReward.MakerFeeReferrerReward) 751 inf = inf.Sub(inf, referrerReward.InfrastructureFeeReferrerReward) 752 lf = lf.Sub(lf, referrerReward.LiquidityFeeReferrerReward) 753 754 referrer, err := referral.GetReferrer(types.PartyID(taker)) 755 if err != nil { 756 e.log.Error("could not load referrer from taker of trade", logging.PartyID(taker)) 757 } else { 758 e.feesStats.RegisterReferrerReward( 759 string(referrer), 760 taker, 761 num.Sum( 762 referrerReward.MakerFeeReferrerReward, 763 referrerReward.InfrastructureFeeReferrerReward, 764 referrerReward.LiquidityFeeReferrerReward, 765 ), 766 ) 767 } 768 769 f.MakerFee = mf 770 f.InfrastructureFee = inf 771 f.LiquidityFee = lf 772 return f, referrerReward 773 } 774 775 func (e *Engine) getAuctionModeFeesAndTransfers(t *types.Trade, referral ReferralDiscountRewardService, volumeDiscount VolumeDiscountService, volumeRebate VolumeRebateService) (*types.Fee, *types.Fee, []*types.Transfer) { 776 fee := e.calculateAuctionModeFees(t) 777 // in auction there is no maker so there is no rebate, so passing 0 as the trade value 778 buyerFees, buyerReferrerRewards := e.applyDiscountsAndRewards(t.Buyer, t.Buyer, num.DecimalZero(), fee, referral, volumeDiscount, volumeRebate) 779 sellerFees, sellerReferrerRewards := e.applyDiscountsAndRewards(t.Seller, t.Seller, num.DecimalZero(), fee, referral, volumeDiscount, volumeRebate) 780 781 transfers := make([]*types.Transfer, 0, 12) 782 transfers = append(transfers, 783 e.getAuctionModeFeeTransfers( 784 sellerFees.InfrastructureFee, sellerFees.LiquidityFee, sellerFees.BuyBackFee, sellerFees.TreasuryFee, t.Seller)...) 785 transfers = append(transfers, 786 e.getAuctionModeFeeTransfers( 787 buyerFees.InfrastructureFee, buyerFees.LiquidityFee, buyerFees.BuyBackFee, buyerFees.TreasuryFee, t.Buyer)...) 788 789 if buyerReferrerRewards != nil { 790 referrerParty, _ := referral.GetReferrer(types.PartyID(t.Buyer)) 791 transfers = append(transfers, 792 e.getAuctionModeFeeReferrerRewardTransfers( 793 num.Sum(buyerReferrerRewards.InfrastructureFeeReferrerReward, buyerReferrerRewards.LiquidityFeeReferrerReward), t.Buyer, string(referrerParty))...) 794 } 795 796 if sellerReferrerRewards != nil { 797 referrerParty, _ := referral.GetReferrer(types.PartyID(t.Seller)) 798 transfers = append(transfers, 799 e.getAuctionModeFeeReferrerRewardTransfers( 800 num.Sum(sellerReferrerRewards.InfrastructureFeeReferrerReward, sellerReferrerRewards.LiquidityFeeReferrerReward), t.Seller, string(referrerParty))...) 801 } 802 803 return buyerFees, sellerFees, transfers 804 } 805 806 func (e *Engine) calculateContinuousModeFees(trade *types.Trade) *types.Fee { 807 size := num.NewUint(trade.Size) 808 // multiply by size 809 total := size.Mul(trade.Price, size).ToDecimal().Div(e.positionFactor) 810 mf, _ := num.UintFromDecimal(total.Mul(e.f.makerFee).Ceil()) 811 inf, _ := num.UintFromDecimal(total.Mul(e.f.infrastructureFee).Ceil()) 812 lf, _ := num.UintFromDecimal(total.Mul(e.f.liquidityFee).Ceil()) 813 bbf, _ := num.UintFromDecimal(total.Mul(e.f.buyBackFee).Ceil()) 814 tf, _ := num.UintFromDecimal(total.Mul(e.f.treasuryFee).Ceil()) 815 return &types.Fee{ 816 MakerFee: mf, 817 InfrastructureFee: inf, 818 LiquidityFee: lf, 819 BuyBackFee: bbf, 820 TreasuryFee: tf, 821 HighVolumeMakerFee: num.UintZero(), 822 } 823 } 824 825 func (e *Engine) calculateAuctionModeFees(trade *types.Trade) *types.Fee { 826 fee := e.calculateContinuousModeFees(trade) 827 two := num.DecimalFromInt64(2) 828 inf, _ := num.UintFromDecimal(fee.InfrastructureFee.ToDecimal().Div(two).Ceil()) 829 lf, _ := num.UintFromDecimal(fee.LiquidityFee.ToDecimal().Div(two).Ceil()) 830 bbf, _ := num.UintFromDecimal(fee.BuyBackFee.ToDecimal().Div(two).Ceil()) 831 tf, _ := num.UintFromDecimal(fee.TreasuryFee.ToDecimal().Div(two).Ceil()) 832 return &types.Fee{ 833 MakerFee: num.UintZero(), 834 InfrastructureFee: inf, 835 LiquidityFee: lf, 836 TreasuryFee: tf, 837 BuyBackFee: bbf, 838 } 839 } 840 841 func (e *Engine) getAuctionModeFeeReferrerRewardTransfers(reward *num.Uint, p, referrer string) []*types.Transfer { 842 return []*types.Transfer{ 843 { 844 Owner: p, 845 Amount: &types.FinancialAmount{ 846 Amount: reward.Clone(), 847 Asset: e.asset, 848 }, 849 Type: types.TransferTypeFeeReferrerRewardPay, 850 MinAmount: reward.Clone(), 851 }, { 852 Owner: referrer, 853 Amount: &types.FinancialAmount{ 854 Amount: reward.Clone(), 855 Asset: e.asset, 856 }, 857 Type: types.TransferTypeFeeReferrerRewardDistribute, 858 MinAmount: reward.Clone(), 859 }, 860 } 861 } 862 863 func (e *Engine) getAuctionModeFeeTransfers(infraFee, liquiFee, buyBackFee, treasuryFee *num.Uint, p string) []*types.Transfer { 864 // we return both transfer for the party in a slice 865 // always the infrastructure fee first 866 return []*types.Transfer{ 867 { 868 Owner: p, 869 Amount: &types.FinancialAmount{ 870 Asset: e.asset, 871 Amount: infraFee.Clone(), 872 }, 873 Type: types.TransferTypeInfrastructureFeePay, 874 }, 875 { 876 Owner: p, 877 Amount: &types.FinancialAmount{ 878 Asset: e.asset, 879 Amount: liquiFee.Clone(), 880 }, 881 Type: types.TransferTypeLiquidityFeePay, 882 }, 883 { 884 Owner: p, 885 Amount: &types.FinancialAmount{ 886 Asset: e.asset, 887 Amount: buyBackFee.Clone(), 888 }, 889 Type: types.TransferTypeBuyBackFeePay, 890 }, 891 { 892 Owner: p, 893 Amount: &types.FinancialAmount{ 894 Asset: e.asset, 895 Amount: treasuryFee.Clone(), 896 }, 897 Type: types.TransferTypeTreasuryPay, 898 }, 899 } 900 } 901 902 type feesTransfer struct { 903 totalFeesAmountsPerParty map[string]*num.Uint 904 transfers []*types.Transfer 905 } 906 907 func (f *feesTransfer) TotalFeesAmountPerParty() map[string]*num.Uint { 908 ret := make(map[string]*num.Uint, len(f.totalFeesAmountsPerParty)) 909 for k, v := range f.totalFeesAmountsPerParty { 910 ret[k] = v.Clone() 911 } 912 return ret 913 } 914 func (f *feesTransfer) Transfers() []*types.Transfer { return f.transfers } 915 916 func (e *Engine) OnFeeFactorsMakerFeeUpdate(f num.Decimal) { 917 e.feeCfg.Factors.MakerFee = f 918 e.f.makerFee = f 919 } 920 921 func (e *Engine) OnFeeFactorsBuyBackFeeUpdate(f num.Decimal) { 922 e.feeCfg.Factors.BuyBackFee = f 923 e.f.buyBackFee = f 924 } 925 926 func (e *Engine) OnFeeFactorsTreasuryFeeUpdate(f num.Decimal) { 927 e.feeCfg.Factors.TreasuryFee = f 928 e.f.treasuryFee = f 929 } 930 931 func (e *Engine) OnFeeFactorsInfrastructureFeeUpdate(f num.Decimal) { 932 e.feeCfg.Factors.InfrastructureFee = f 933 e.f.infrastructureFee = f 934 } 935 936 func (e *Engine) GetLiquidityFee() num.Decimal { 937 return e.f.liquidityFee 938 }