diff --git a/CHANGELOG.md b/CHANGELOG.md index c5f5ff1d200..89313c54124 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ - [11028](https://github.com/vegaprotocol/vega/issues/11028) - Add API to estimate order book depth based on `vAMM`. - [11400](https://github.com/vegaprotocol/vega/issues/11400) - Add support for long block auction. - [11026](https://github.com/vegaprotocol/vega/issues/11026) - Add API flag to get paid liquidity fees for a `vAMM` using the parent key. +- [11428](https://github.com/vegaprotocol/vega/issues/11428) - Add buy back and treasury fee and separate discount/reward factors. ### 🐛 Fixes diff --git a/commands/proposal_submission.go b/commands/proposal_submission.go index 075c63977da..43845678b67 100644 --- a/commands/proposal_submission.go +++ b/commands/proposal_submission.go @@ -494,25 +494,73 @@ func checkBenefitTier(index int, tier *vegapb.BenefitTier) Errors { } } - if len(tier.ReferralRewardFactor) == 0 { - errs.AddForProperty(propertyPath+".referral_reward_factor", ErrIsRequired) + if tier.ReferralRewardFactors == nil { + errs.AddForProperty(propertyPath+".referral_reward_factors", ErrIsRequired) } else { - rrf, err := num.DecimalFromString(tier.ReferralRewardFactor) - if err != nil { - errs.AddForProperty(propertyPath+".referral_reward_factor", ErrIsNotValidNumber) - } else if rrf.IsNegative() { - errs.AddForProperty(propertyPath+".referral_reward_factor", ErrMustBePositiveOrZero) + if len(tier.ReferralRewardFactors.InfrastructureRewardFactor) == 0 { + errs.AddForProperty(propertyPath+".referral_reward_factors.infrastructure_reward_factor", ErrIsRequired) + } else { + rrf, err := num.DecimalFromString(tier.ReferralRewardFactors.InfrastructureRewardFactor) + if err != nil { + errs.AddForProperty(propertyPath+".referral_reward_factors.infrastructure_reward_factor", ErrIsNotValidNumber) + } else if rrf.IsNegative() { + errs.AddForProperty(propertyPath+".referral_reward_factors.infrastructure_reward_factor", ErrMustBePositiveOrZero) + } + } + if len(tier.ReferralRewardFactors.MakerRewardFactor) == 0 { + errs.AddForProperty(propertyPath+".referral_reward_factors.maker_reward_factor", ErrIsRequired) + } else { + rrf, err := num.DecimalFromString(tier.ReferralRewardFactors.MakerRewardFactor) + if err != nil { + errs.AddForProperty(propertyPath+".referral_reward_factors.maker_reward_factor", ErrIsNotValidNumber) + } else if rrf.IsNegative() { + errs.AddForProperty(propertyPath+".referral_reward_factors.maker_reward_factor", ErrMustBePositiveOrZero) + } + } + if len(tier.ReferralRewardFactors.LiquidityRewardFactor) == 0 { + errs.AddForProperty(propertyPath+".referral_reward_factors.liquidity_reward_factor", ErrIsRequired) + } else { + rrf, err := num.DecimalFromString(tier.ReferralRewardFactors.LiquidityRewardFactor) + if err != nil { + errs.AddForProperty(propertyPath+".referral_reward_factors.liquidity_reward_factor", ErrIsNotValidNumber) + } else if rrf.IsNegative() { + errs.AddForProperty(propertyPath+".referral_reward_factors.liquidity_reward_factor", ErrMustBePositiveOrZero) + } } } - if len(tier.ReferralDiscountFactor) == 0 { - errs.AddForProperty(propertyPath+".referral_discount_factor", ErrIsRequired) + if tier.ReferralDiscountFactors == nil { + errs.AddForProperty(propertyPath+".referral_discount_factors", ErrIsRequired) } else { - rdf, err := num.DecimalFromString(tier.ReferralDiscountFactor) - if err != nil { - errs.AddForProperty(propertyPath+".referral_discount_factor", ErrIsNotValidNumber) - } else if rdf.IsNegative() { - errs.AddForProperty(propertyPath+".referral_discount_factor", ErrMustBePositiveOrZero) + if len(tier.ReferralDiscountFactors.InfrastructureDiscountFactor) == 0 { + errs.AddForProperty(propertyPath+".referral_discount_factors.infrastructure_discount_factor", ErrIsRequired) + } else { + rrf, err := num.DecimalFromString(tier.ReferralDiscountFactors.InfrastructureDiscountFactor) + if err != nil { + errs.AddForProperty(propertyPath+".referral_discount_factors.infrastructure_discount_factor", ErrIsNotValidNumber) + } else if rrf.IsNegative() { + errs.AddForProperty(propertyPath+".referral_discount_factors.infrastructure_discount_factor", ErrMustBePositiveOrZero) + } + } + if len(tier.ReferralDiscountFactors.MakerDiscountFactor) == 0 { + errs.AddForProperty(propertyPath+".referral_discount_factors.maker_discount_factor", ErrIsRequired) + } else { + rrf, err := num.DecimalFromString(tier.ReferralDiscountFactors.MakerDiscountFactor) + if err != nil { + errs.AddForProperty(propertyPath+".referral_discount_factors.maker_discount_factor", ErrIsNotValidNumber) + } else if rrf.IsNegative() { + errs.AddForProperty(propertyPath+".referral_discount_factors.maker_discount_factor", ErrMustBePositiveOrZero) + } + } + if len(tier.ReferralDiscountFactors.LiquidityDiscountFactor) == 0 { + errs.AddForProperty(propertyPath+".referral_discount_factors.liquidity_discount_factor", ErrIsRequired) + } else { + rrf, err := num.DecimalFromString(tier.ReferralDiscountFactors.LiquidityDiscountFactor) + if err != nil { + errs.AddForProperty(propertyPath+".referral_discount_factors.liquidity_discount_factor", ErrIsNotValidNumber) + } else if rrf.IsNegative() { + errs.AddForProperty(propertyPath+".referral_discount_factors.liquidity_discount_factor", ErrMustBePositiveOrZero) + } } } diff --git a/commands/proposal_submission_update_referral_program_test.go b/commands/proposal_submission_update_referral_program_test.go index a987c8e5fff..2df7549bfbf 100644 --- a/commands/proposal_submission_update_referral_program_test.go +++ b/commands/proposal_submission_update_referral_program_test.go @@ -183,6 +183,8 @@ func testSubmissionForReferralProgramUpdateWithoutTierMinimumRunningNotionalTake } func testSubmissionForReferralProgramUpdateWithDuplicateBenefitTierEntriesFails(t *testing.T) { + factors := []string{"1.1", "1.2", "1.3", "1.4", "1.5", "1.6"} + err := checkProposalSubmission(&commandspb.ProposalSubmission{ Terms: &types.ProposalTerms{ Change: &types.ProposalTerms_UpdateReferralProgram{ @@ -192,20 +194,44 @@ func testSubmissionForReferralProgramUpdateWithDuplicateBenefitTierEntriesFails( { MinimumRunningNotionalTakerVolume: "100", MinimumEpochs: "10", - ReferralRewardFactor: "1.1", - ReferralDiscountFactor: "1.2", + ReferralRewardFactors: &types.RewardFactors{ + InfrastructureRewardFactor: factors[0], + MakerRewardFactor: factors[1], + LiquidityRewardFactor: factors[2], + }, + ReferralDiscountFactors: &types.DiscountFactors{ + InfrastructureDiscountFactor: factors[1], + MakerDiscountFactor: factors[2], + LiquidityDiscountFactor: factors[3], + }, }, { MinimumRunningNotionalTakerVolume: "100", MinimumEpochs: "10", - ReferralRewardFactor: "1.2", - ReferralDiscountFactor: "1.3", + ReferralRewardFactors: &types.RewardFactors{ + InfrastructureRewardFactor: factors[1], + MakerRewardFactor: factors[2], + LiquidityRewardFactor: factors[3], + }, + ReferralDiscountFactors: &types.DiscountFactors{ + InfrastructureDiscountFactor: factors[2], + MakerDiscountFactor: factors[3], + LiquidityDiscountFactor: factors[4], + }, }, { MinimumRunningNotionalTakerVolume: "100", MinimumEpochs: "20", - ReferralRewardFactor: "1.3", - ReferralDiscountFactor: "1.4", + ReferralRewardFactors: &types.RewardFactors{ + InfrastructureRewardFactor: factors[2], + MakerRewardFactor: factors[3], + LiquidityRewardFactor: factors[4], + }, + ReferralDiscountFactors: &types.DiscountFactors{ + InfrastructureDiscountFactor: factors[3], + MakerDiscountFactor: factors[4], + LiquidityDiscountFactor: factors[5], + }, }, }, }, @@ -376,8 +402,8 @@ func testSubmissionForReferralProgramUpdateWithoutTierReferralRewardFactorFails( }, }) - assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_reward_factor"), commands.ErrIsRequired) - assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_reward_factor"), commands.ErrIsRequired) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_reward_factors"), commands.ErrIsRequired) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_reward_factors"), commands.ErrIsRequired) } func testSubmissionForReferralProgramUpdateWithBadFormatForTierReferralRewardFactorFails(t *testing.T) { @@ -388,9 +414,17 @@ func testSubmissionForReferralProgramUpdateWithBadFormatForTierReferralRewardFac Changes: &types.ReferralProgramChanges{ BenefitTiers: []*types.BenefitTier{ { - ReferralRewardFactor: "qbc", + ReferralRewardFactors: &types.RewardFactors{ + InfrastructureRewardFactor: "qbc", + MakerRewardFactor: "qbc", + LiquidityRewardFactor: "qbc", + }, }, { - ReferralRewardFactor: "0x32", + ReferralRewardFactors: &types.RewardFactors{ + InfrastructureRewardFactor: "0x32", + MakerRewardFactor: "0x32", + LiquidityRewardFactor: "0x32", + }, }, }, }, @@ -399,8 +433,8 @@ func testSubmissionForReferralProgramUpdateWithBadFormatForTierReferralRewardFac }, }) - assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_reward_factor"), commands.ErrIsNotValidNumber) - assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_reward_factor"), commands.ErrIsNotValidNumber) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_reward_factors.infrastructure_reward_factor"), commands.ErrIsNotValidNumber) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_reward_factors.infrastructure_reward_factor"), commands.ErrIsNotValidNumber) } func testSubmissionForReferralProgramUpdateWithBadValueForTierReferralRewardFactorFails(t *testing.T) { @@ -411,9 +445,17 @@ func testSubmissionForReferralProgramUpdateWithBadValueForTierReferralRewardFact Changes: &types.ReferralProgramChanges{ BenefitTiers: []*types.BenefitTier{ { - ReferralRewardFactor: "-10", + ReferralRewardFactors: &types.RewardFactors{ + InfrastructureRewardFactor: "-10", + MakerRewardFactor: "-10", + LiquidityRewardFactor: "-10", + }, }, { - ReferralRewardFactor: "-1", + ReferralRewardFactors: &types.RewardFactors{ + InfrastructureRewardFactor: "-1", + MakerRewardFactor: "-1", + LiquidityRewardFactor: "-1", + }, }, }, }, @@ -422,8 +464,12 @@ func testSubmissionForReferralProgramUpdateWithBadValueForTierReferralRewardFact }, }) - assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_reward_factor"), commands.ErrMustBePositiveOrZero) - assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_reward_factor"), commands.ErrMustBePositiveOrZero) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_reward_factors.infrastructure_reward_factor"), commands.ErrMustBePositiveOrZero) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_reward_factors.infrastructure_reward_factor"), commands.ErrMustBePositiveOrZero) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_reward_factors.maker_reward_factor"), commands.ErrMustBePositiveOrZero) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_reward_factors.maker_reward_factor"), commands.ErrMustBePositiveOrZero) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_reward_factors.liquidity_reward_factor"), commands.ErrMustBePositiveOrZero) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_reward_factors.liquidity_reward_factor"), commands.ErrMustBePositiveOrZero) } func testSubmissionForReferralProgramUpdateWithoutTierReferralDiscountFactorFails(t *testing.T) { @@ -434,9 +480,9 @@ func testSubmissionForReferralProgramUpdateWithoutTierReferralDiscountFactorFail Changes: &types.ReferralProgramChanges{ BenefitTiers: []*types.BenefitTier{ { - ReferralDiscountFactor: "", + ReferralDiscountFactors: &types.DiscountFactors{}, }, { - ReferralDiscountFactor: "", + ReferralDiscountFactors: &types.DiscountFactors{}, }, }, }, @@ -445,8 +491,12 @@ func testSubmissionForReferralProgramUpdateWithoutTierReferralDiscountFactorFail }, }) - assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_discount_factor"), commands.ErrIsRequired) - assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_discount_factor"), commands.ErrIsRequired) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_discount_factors.infrastructure_discount_factor"), commands.ErrIsRequired) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_discount_factors.infrastructure_discount_factor"), commands.ErrIsRequired) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_discount_factors.maker_discount_factor"), commands.ErrIsRequired) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_discount_factors.maker_discount_factor"), commands.ErrIsRequired) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_discount_factors.liquidity_discount_factor"), commands.ErrIsRequired) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_discount_factors.liquidity_discount_factor"), commands.ErrIsRequired) } func testSubmissionForReferralProgramUpdateWithBadFormatForTierReferralDiscountFactorFails(t *testing.T) { @@ -457,9 +507,17 @@ func testSubmissionForReferralProgramUpdateWithBadFormatForTierReferralDiscountF Changes: &types.ReferralProgramChanges{ BenefitTiers: []*types.BenefitTier{ { - ReferralDiscountFactor: "qbc", + ReferralDiscountFactors: &types.DiscountFactors{ + InfrastructureDiscountFactor: "qbc", + LiquidityDiscountFactor: "qbc", + MakerDiscountFactor: "qbc", + }, }, { - ReferralDiscountFactor: "0x32", + ReferralDiscountFactors: &types.DiscountFactors{ + InfrastructureDiscountFactor: "0x32", + LiquidityDiscountFactor: "0x32", + MakerDiscountFactor: "0x32", + }, }, }, }, @@ -468,8 +526,12 @@ func testSubmissionForReferralProgramUpdateWithBadFormatForTierReferralDiscountF }, }) - assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_discount_factor"), commands.ErrIsNotValidNumber) - assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_discount_factor"), commands.ErrIsNotValidNumber) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_discount_factors.infrastructure_discount_factor"), commands.ErrIsNotValidNumber) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_discount_factors.infrastructure_discount_factor"), commands.ErrIsNotValidNumber) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_discount_factors.maker_discount_factor"), commands.ErrIsNotValidNumber) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_discount_factors.maker_discount_factor"), commands.ErrIsNotValidNumber) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_discount_factors.liquidity_discount_factor"), commands.ErrIsNotValidNumber) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_discount_factors.liquidity_discount_factor"), commands.ErrIsNotValidNumber) } func testSubmissionForReferralProgramUpdateWithBadValueForTierReferralDiscountFactorFails(t *testing.T) { @@ -480,9 +542,17 @@ func testSubmissionForReferralProgramUpdateWithBadValueForTierReferralDiscountFa Changes: &types.ReferralProgramChanges{ BenefitTiers: []*types.BenefitTier{ { - ReferralDiscountFactor: "-10", + ReferralDiscountFactors: &types.DiscountFactors{ + InfrastructureDiscountFactor: "-10", + MakerDiscountFactor: "-10", + LiquidityDiscountFactor: "-10", + }, }, { - ReferralDiscountFactor: "-1", + ReferralDiscountFactors: &types.DiscountFactors{ + InfrastructureDiscountFactor: "-1", + MakerDiscountFactor: "-1", + LiquidityDiscountFactor: "-1", + }, }, }, }, @@ -491,8 +561,12 @@ func testSubmissionForReferralProgramUpdateWithBadValueForTierReferralDiscountFa }, }) - assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_discount_factor"), commands.ErrMustBePositiveOrZero) - assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_discount_factor"), commands.ErrMustBePositiveOrZero) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_discount_factors.infrastructure_discount_factor"), commands.ErrMustBePositiveOrZero) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_discount_factors.infrastructure_discount_factor"), commands.ErrMustBePositiveOrZero) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_discount_factors.liquidity_discount_factor"), commands.ErrMustBePositiveOrZero) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_discount_factors.liquidity_discount_factor"), commands.ErrMustBePositiveOrZero) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.0.referral_discount_factors.maker_discount_factor"), commands.ErrMustBePositiveOrZero) + assert.Contains(t, err.Get("proposal_submission.terms.change.update_referral_program.changes.benefit_tiers.1.referral_discount_factors.maker_discount_factor"), commands.ErrMustBePositiveOrZero) } func testSubmissionForReferralProgramUpdateWithoutStakingTierMinimumStakedTokensFails(t *testing.T) { diff --git a/core/collateral/engine.go b/core/collateral/engine.go index 10e999436ad..7c9915e416c 100644 --- a/core/collateral/engine.go +++ b/core/collateral/engine.go @@ -727,7 +727,7 @@ func (e *Engine) transferSpotFees(ctx context.Context, marketID string, assetID for _, transfer := range transfers { req, err := e.getSpotFeeTransferRequest( - transfer, makerFee, infraFee, liquiFee, marketID, assetID) + ctx, transfer, makerFee, infraFee, liquiFee, marketID, assetID) if err != nil { e.log.Error("Failed to build transfer request for event", logging.Error(err)) @@ -758,6 +758,7 @@ func (e *Engine) transferSpotFees(ctx context.Context, marketID string, assetID } func (e *Engine) getSpotFeeTransferRequest( + ctx context.Context, t *types.Transfer, makerFee, infraFee, liquiFee *types.Account, marketID, assetID string, @@ -790,6 +791,13 @@ func (e *Engine) getSpotFeeTransferRequest( return nil, err } + networkTreausry, err := e.GetNetworkTreasuryAccount(assetID) + if err != nil { + return nil, err + } + + buyBackAccount := e.getOrCreateBuyBackFeesAccount(ctx, assetID) + treq := &types.TransferRequest{ Amount: t.Amount.Amount.Clone(), MinAmount: t.Amount.Amount.Clone(), @@ -809,6 +817,20 @@ func (e *Engine) getSpotFeeTransferRequest( treq.FromAccount = []*types.Account{infraFee} treq.ToAccount = []*types.Account{general} return treq, nil + case types.TransferTypeTreasuryPay: + amt := num.Min(treq.Amount, general.Balance.Clone()) + treq.Amount = amt + treq.MinAmount = amt + treq.FromAccount = []*types.Account{general} + treq.ToAccount = []*types.Account{networkTreausry} + return treq, nil + case types.TransferTypeBuyBackFeePay: + amt := num.Min(treq.Amount, general.Balance.Clone()) + treq.Amount = amt + treq.MinAmount = amt + treq.FromAccount = []*types.Account{general} + treq.ToAccount = []*types.Account{buyBackAccount} + return treq, nil case types.TransferTypeLiquidityFeePay: amt := num.Min(treq.Amount, general.Balance.Clone()) treq.Amount = amt @@ -2229,6 +2251,12 @@ func (e *Engine) getFeeTransferRequest( general *types.Account err error ) + networkTreausry, err := e.GetNetworkTreasuryAccount(assetID) + if err != nil { + return nil, err + } + buyBackAccount := e.getOrCreateBuyBackFeesAccount(ctx, assetID) + if t.Owner == types.NetworkParty { general, err = e.GetMarketInsurancePoolAccount(marketID, assetID) if err != nil { @@ -2290,6 +2318,28 @@ func (e *Engine) getFeeTransferRequest( treq.FromAccount = append(treq.FromAccount, orderMargin) } treq.ToAccount = []*types.Account{infraFee} + case types.TransferTypeTreasuryPay: + margin, err := marginAccount() + if err != nil { + return nil, err + } + orderMargin := orderMarginAccount() + treq.FromAccount = []*types.Account{general, margin} + if orderMargin != nil { + treq.FromAccount = append(treq.FromAccount, orderMargin) + } + treq.ToAccount = []*types.Account{networkTreausry} + case types.TransferTypeBuyBackFeePay: + margin, err := marginAccount() + if err != nil { + return nil, err + } + orderMargin := orderMarginAccount() + treq.FromAccount = []*types.Account{general, margin} + if orderMargin != nil { + treq.FromAccount = append(treq.FromAccount, orderMargin) + } + treq.ToAccount = []*types.Account{buyBackAccount} case types.TransferTypeInfrastructureFeeDistribute: treq.FromAccount = []*types.Account{infraFee} treq.ToAccount = []*types.Account{general} @@ -4589,6 +4639,26 @@ func (e *Engine) GetNetworkTreasuryAccount(asset string) (*types.Account, error) return e.GetAccountByID(e.accountID(noMarket, systemOwner, asset, types.AccountTypeNetworkTreasury)) } +func (e *Engine) getOrCreateBuyBackFeesAccount(ctx context.Context, asset string) *types.Account { + accID := e.accountID(noMarket, systemOwner, asset, types.AccountTypeNetworkTreasury) + acc, err := e.GetAccountByID(accID) + if err == nil { + return acc + } + ntAcc := &types.Account{ + ID: accID, + Asset: asset, + Owner: systemOwner, + Balance: num.UintZero(), + MarketID: noMarket, + Type: types.AccountTypeBuyBackFees, + } + e.accs[accID] = ntAcc + e.addAccountToHashableSlice(ntAcc) + e.broker.Send(events.NewAccountEvent(ctx, *ntAcc)) + return ntAcc +} + func (e *Engine) GetOrCreateNetworkTreasuryAccount(ctx context.Context, asset string) *types.Account { accID := e.accountID(noMarket, systemOwner, asset, types.AccountTypeNetworkTreasury) acc, err := e.GetAccountByID(accID) diff --git a/core/events/referral_set.go b/core/events/referral_set.go index 7440065ec9c..8b7f67bb124 100644 --- a/core/events/referral_set.go +++ b/core/events/referral_set.go @@ -71,15 +71,13 @@ type ReferralSetStatsUpdated struct { func (t ReferralSetStatsUpdated) Unwrap() *types.ReferralSetStats { volume, _ := num.UintFromString(t.e.ReferralSetRunningNotionalTakerVolume, 10) stats := map[types.PartyID]*types.RefereeStats{} - rewardFactor, _ := num.DecimalFromString(t.e.RewardFactor) rewardsMultiplier, _ := num.DecimalFromString(t.e.RewardsMultiplier) - rewardsFactorMultiplier, _ := num.DecimalFromString(t.e.RewardsFactorMultiplier) - + rewardsFactorsMultiplier := types.FactorsFromRewardFactorsWithDefault(t.e.RewardFactorsMultiplier, t.e.RewardsFactorMultiplier) + rewardFactors := types.FactorsFromRewardFactorsWithDefault(t.e.RewardFactors, t.e.RewardFactor) for _, stat := range t.e.RefereesStats { - discountFactor, _ := num.DecimalFromString(stat.DiscountFactor) - + discountFactors := types.FactorsFromDiscountFactorsWithDefault(stat.DiscountFactors, stat.DiscountFactor) stats[types.PartyID(stat.PartyId)] = &types.RefereeStats{ - DiscountFactor: discountFactor, + DiscountFactors: discountFactors, } } @@ -89,9 +87,9 @@ func (t ReferralSetStatsUpdated) Unwrap() *types.ReferralSetStats { WasEligible: t.e.WasEligible, ReferralSetRunningVolume: volume, RefereesStats: stats, - RewardFactor: rewardFactor, + RewardFactors: rewardFactors, RewardsMultiplier: rewardsMultiplier, - RewardsFactorMultiplier: rewardsFactorMultiplier, + RewardsFactorsMultiplier: rewardsFactorsMultiplier, } } @@ -113,7 +111,7 @@ func NewReferralSetStatsUpdatedEvent(ctx context.Context, update *types.Referral for partyID, stat := range update.RefereesStats { refereesStats = append(refereesStats, &eventspb.RefereeStats{ PartyId: string(partyID), - DiscountFactor: stat.DiscountFactor.String(), + DiscountFactors: stat.DiscountFactors.IntoDiscountFactorsProto(), EpochNotionalTakerVolume: stat.TakerVolume.String(), }) } @@ -131,9 +129,9 @@ func NewReferralSetStatsUpdatedEvent(ctx context.Context, update *types.Referral ReferralSetRunningNotionalTakerVolume: update.ReferralSetRunningVolume.String(), ReferrerTakerVolume: update.ReferrerTakerVolume.String(), RefereesStats: refereesStats, - RewardFactor: update.RewardFactor.String(), + RewardFactors: update.RewardFactors.IntoRewardFactorsProto(), RewardsMultiplier: update.RewardsMultiplier.String(), - RewardsFactorMultiplier: update.RewardsFactorMultiplier.String(), + RewardFactorsMultiplier: update.RewardsFactorsMultiplier.IntoRewardFactorsProto(), }, } } diff --git a/core/execution/common/interfaces.go b/core/execution/common/interfaces.go index 757c3704743..8f00eb95822 100644 --- a/core/execution/common/interfaces.go +++ b/core/execution/common/interfaces.go @@ -374,6 +374,8 @@ type CommonMarket interface { OnMarketProbabilityOfTradingTauScalingUpdate(context.Context, num.Decimal) OnMarketValueWindowLengthUpdate(time.Duration) OnFeeFactorsInfrastructureFeeUpdate(context.Context, num.Decimal) + OnFeeFactorsTreasuryFeeUpdate(context.Context, num.Decimal) + OnFeeFactorsBuyBackFeeUpdate(context.Context, num.Decimal) OnFeeFactorsMakerFeeUpdate(context.Context, num.Decimal) OnMarkPriceUpdateMaximumFrequency(context.Context, time.Duration) OnMarketAuctionMinimumDurationUpdate(context.Context, time.Duration) diff --git a/core/execution/common/market_activity_tracker.go b/core/execution/common/market_activity_tracker.go index 050f8c39b40..b148c4e6689 100644 --- a/core/execution/common/market_activity_tracker.go +++ b/core/execution/common/market_activity_tracker.go @@ -67,6 +67,8 @@ type marketTracker struct { lpFees map[string]*num.Uint infraFees map[string]*num.Uint lpPaidFees map[string]*num.Uint + buybackFeesPaid map[string]*num.Uint + treasuryFeesPaid map[string]*num.Uint totalMakerFeesReceived *num.Uint totalMakerFeesPaid *num.Uint @@ -187,6 +189,8 @@ func (mat *MarketActivityTracker) MarketProposed(asset, marketID, proposer strin lpFees: map[string]*num.Uint{}, infraFees: map[string]*num.Uint{}, lpPaidFees: map[string]*num.Uint{}, + buybackFeesPaid: map[string]*num.Uint{}, + treasuryFeesPaid: map[string]*num.Uint{}, totalMakerFeesReceived: num.UintZero(), totalMakerFeesPaid: num.UintZero(), totalLpFees: num.UintZero(), @@ -467,7 +471,7 @@ func (mat *MarketActivityTracker) RemoveMarket(asset, marketID string) { func (mt *marketTracker) aggregatedFees() map[string]*num.Uint { totalFees := map[string]*num.Uint{} - fees := []map[string]*num.Uint{mt.infraFees, mt.lpPaidFees, mt.makerFeesPaid} + fees := []map[string]*num.Uint{mt.infraFees, mt.lpPaidFees, mt.makerFeesPaid, mt.buybackFeesPaid, mt.treasuryFeesPaid} for _, fee := range fees { for party, paid := range fee { if _, ok := totalFees[party]; !ok { @@ -544,6 +548,8 @@ func (mt *marketTracker) clearFeeActivity() { mt.lpFees = map[string]*num.Uint{} mt.infraFees = map[string]*num.Uint{} mt.lpPaidFees = map[string]*num.Uint{} + mt.treasuryFeesPaid = map[string]*num.Uint{} + mt.buybackFeesPaid = map[string]*num.Uint{} mt.epochTotalMakerFeesReceived = append(mt.epochTotalMakerFeesReceived, mt.totalMakerFeesReceived) mt.epochTotalMakerFeesPaid = append(mt.epochTotalMakerFeesPaid, mt.totalMakerFeesPaid) @@ -573,6 +579,10 @@ func (mat *MarketActivityTracker) UpdateFeesFromTransfers(asset, market string, mat.addFees(mt.infraFees, t.Owner, t.Amount.Amount, num.UintZero()) case types.TransferTypeLiquidityFeePay: mat.addFees(mt.lpPaidFees, t.Owner, t.Amount.Amount, num.UintZero()) + case types.TransferTypeBuyBackFeePay: + mat.addFees(mt.buybackFeesPaid, t.Owner, t.Amount.Amount, num.UintZero()) + case types.TransferTypeTreasuryPay: + mat.addFees(mt.treasuryFeesPaid, t.Owner, t.Amount.Amount, num.UintZero()) default: } } diff --git a/core/execution/common/market_activity_tracker_snapshot.go b/core/execution/common/market_activity_tracker_snapshot.go index 38e92fc88f8..4a95fc4f69c 100644 --- a/core/execution/common/market_activity_tracker_snapshot.go +++ b/core/execution/common/market_activity_tracker_snapshot.go @@ -295,6 +295,8 @@ func (mt *marketTracker) IntoProto(market string) *checkpoint.MarketActivityTrac LpFees: marketFeesToProto(mt.lpFees), InfraFees: marketFeesToProto(mt.infraFees), LpPaidFees: marketFeesToProto(mt.lpPaidFees), + BuyBackFees: marketFeesToProto(mt.buybackFeesPaid), + TreasuryFees: marketFeesToProto(mt.treasuryFeesPaid), Proposer: mt.proposer, BonusPaid: paid, ValueTraded: mt.valueTraded.String(), @@ -394,6 +396,8 @@ func marketTrackerFromProto(tracker *checkpoint.MarketActivityTracker) *marketTr makerFeesReceived: map[string]*num.Uint{}, makerFeesPaid: map[string]*num.Uint{}, lpFees: map[string]*num.Uint{}, + buybackFeesPaid: map[string]*num.Uint{}, + treasuryFeesPaid: map[string]*num.Uint{}, infraFees: map[string]*num.Uint{}, lpPaidFees: map[string]*num.Uint{}, totalMakerFeesReceived: num.UintZero(), @@ -467,6 +471,22 @@ func marketTrackerFromProto(tracker *checkpoint.MarketActivityTracker) *marketTr } } + if len(tracker.BuyBackFees) > 0 { + for _, mf := range tracker.BuyBackFees { + fee, _ := num.UintFromString(mf.Fee, 10) + mft.buybackFeesPaid[mf.Party] = fee + mft.allPartiesCache[mf.Party] = struct{}{} + } + } + + if len(tracker.TreasuryFees) > 0 { + for _, mf := range tracker.TreasuryFees { + fee, _ := num.UintFromString(mf.Fee, 10) + mft.treasuryFeesPaid[mf.Party] = fee + mft.allPartiesCache[mf.Party] = struct{}{} + } + } + if len(tracker.LpPaidFees) > 0 { for _, mf := range tracker.LpPaidFees { fee, _ := num.UintFromString(mf.Fee, 10) diff --git a/core/execution/engine_netparams.go b/core/execution/engine_netparams.go index 5c54162fdc4..6b6aa1038de 100644 --- a/core/execution/engine_netparams.go +++ b/core/execution/engine_netparams.go @@ -35,6 +35,8 @@ type netParamsValues struct { suppliedStakeToObligationFactor num.Decimal infrastructureFee num.Decimal makerFee num.Decimal + treasuryFee num.Decimal + buyBackFee num.Decimal scalingFactors *types.ScalingFactors maxLiquidityFee num.Decimal bondPenaltyFactor num.Decimal @@ -76,6 +78,8 @@ func defaultNetParamsValues() netParamsValues { suppliedStakeToObligationFactor: num.DecimalFromInt64(-1), infrastructureFee: num.DecimalFromInt64(-1), makerFee: num.DecimalFromInt64(-1), + buyBackFee: num.DecimalFromInt64(-1), + treasuryFee: num.DecimalFromInt64(-1), scalingFactors: nil, maxLiquidityFee: num.DecimalFromInt64(-1), bondPenaltyFactor: num.DecimalFromInt64(-1), @@ -329,6 +333,34 @@ func (e *Engine) OnMarketFeeFactorsMakerFeeUpdate(ctx context.Context, d num.Dec return nil } +func (e *Engine) OnMarketFeeFactorsTreasuryFeeUpdate(ctx context.Context, d num.Decimal) error { + if e.log.IsDebug() { + e.log.Debug("update treasury fee in market fee factors", + logging.Decimal("treasury-fee", d), + ) + } + + for _, mkt := range e.allMarketsCpy { + mkt.OnFeeFactorsTreasuryFeeUpdate(ctx, d) + } + e.npv.treasuryFee = d + return nil +} + +func (e *Engine) OnMarketFeeFactorsBuyBackFeeUpdate(ctx context.Context, d num.Decimal) error { + if e.log.IsDebug() { + e.log.Debug("update buy back fee in market fee factors", + logging.Decimal("buy-back-fee", d), + ) + } + + for _, mkt := range e.allMarketsCpy { + mkt.OnFeeFactorsBuyBackFeeUpdate(ctx, d) + } + e.npv.buyBackFee = d + return nil +} + func (e *Engine) OnMarketFeeFactorsInfrastructureFeeUpdate(ctx context.Context, d num.Decimal) error { if e.log.IsDebug() { e.log.Debug("update infrastructure fee in market fee factors", @@ -496,6 +528,14 @@ func (e *Engine) propagateSpotInitialNetParams(ctx context.Context, mkt *spot.Ma mkt.OnFeeFactorsMakerFeeUpdate(ctx, e.npv.makerFee) } + if !e.npv.buyBackFee.Equal(num.DecimalFromInt64(-1)) { + mkt.OnFeeFactorsBuyBackFeeUpdate(ctx, e.npv.buyBackFee) + } + + if !e.npv.treasuryFee.Equal(num.DecimalFromInt64(-1)) { + mkt.OnFeeFactorsTreasuryFeeUpdate(ctx, e.npv.treasuryFee) + } + if e.npv.marketValueWindowLength != -1 { mkt.OnMarketValueWindowLengthUpdate(e.npv.marketValueWindowLength) } @@ -560,6 +600,14 @@ func (e *Engine) propagateInitialNetParamsToFutureMarket(ctx context.Context, mk mkt.OnFeeFactorsMakerFeeUpdate(ctx, e.npv.makerFee) } + if !e.npv.buyBackFee.Equal(num.DecimalFromInt64(-1)) { + mkt.OnFeeFactorsBuyBackFeeUpdate(ctx, e.npv.buyBackFee) + } + + if !e.npv.treasuryFee.Equal(num.DecimalFromInt64(-1)) { + mkt.OnFeeFactorsTreasuryFeeUpdate(ctx, e.npv.treasuryFee) + } + if e.npv.scalingFactors != nil { if err := mkt.OnMarginScalingFactorsUpdate(ctx, e.npv.scalingFactors); err != nil { return err diff --git a/core/execution/engine_snapshot_test.go b/core/execution/engine_snapshot_test.go index 9453f95d09b..93c5814cbec 100644 --- a/core/execution/engine_snapshot_test.go +++ b/core/execution/engine_snapshot_test.go @@ -91,9 +91,9 @@ func getMockedEngine(t *testing.T) *engineFake { referralDiscountReward := fmock.NewMockReferralDiscountRewardService(ctrl) volumeDiscount := fmock.NewMockVolumeDiscountService(ctrl) - referralDiscountReward.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - referralDiscountReward.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + referralDiscountReward.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + referralDiscountReward.EXPECT().RewardsFactorsMultiplierAppliedForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("not a referrer")).AnyTimes() banking := mocks.NewMockBanking(ctrl) parties := mocks.NewMockParties(ctrl) @@ -159,9 +159,9 @@ func createEngine(t *testing.T) (*execution.Engine, *gomock.Controller) { balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl) referralDiscountReward := fmock.NewMockReferralDiscountRewardService(ctrl) volumeDiscount := fmock.NewMockVolumeDiscountService(ctrl) - referralDiscountReward.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - referralDiscountReward.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + referralDiscountReward.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + referralDiscountReward.EXPECT().RewardsFactorsMultiplierAppliedForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("not a referrer")).AnyTimes() mat := common.NewMarketActivityTracker(log, teams, balanceChecker, broker) banking := mocks.NewMockBanking(ctrl) diff --git a/core/execution/future/market_callbacks.go b/core/execution/future/market_callbacks.go index ee8e9d9e0ae..362c6571747 100644 --- a/core/execution/future/market_callbacks.go +++ b/core/execution/future/market_callbacks.go @@ -58,6 +58,18 @@ func (m *Market) OnFeeFactorsMakerFeeUpdate(ctx context.Context, d num.Decimal) m.broker.Send(events.NewMarketUpdatedEvent(ctx, *m.mkt)) } +func (m *Market) OnFeeFactorsTreasuryFeeUpdate(ctx context.Context, d num.Decimal) { + m.fee.OnFeeFactorsTreasuryFeeUpdate(d) + m.mkt.Fees.Factors.TreasuryFee = d + m.broker.Send(events.NewMarketUpdatedEvent(ctx, *m.mkt)) +} + +func (m *Market) OnFeeFactorsBuyBackFeeUpdate(ctx context.Context, d num.Decimal) { + m.fee.OnFeeFactorsBuyBackFeeUpdate(d) + m.mkt.Fees.Factors.BuyBackFee = d + m.broker.Send(events.NewMarketUpdatedEvent(ctx, *m.mkt)) +} + func (m *Market) OnFeeFactorsInfrastructureFeeUpdate(ctx context.Context, d num.Decimal) { m.fee.OnFeeFactorsInfrastructureFeeUpdate(d) m.mkt.Fees.Factors.InfrastructureFee = d diff --git a/core/execution/future/market_snapshot_test.go b/core/execution/future/market_snapshot_test.go index 239a7008213..a17d7bc8175 100644 --- a/core/execution/future/market_snapshot_test.go +++ b/core/execution/future/market_snapshot_test.go @@ -254,8 +254,8 @@ func newMarketFromSnapshot(t *testing.T, ctx context.Context, ctrl *gomock.Contr positionConfig.StreamPositionVerbose = true referralDiscountReward := fmock.NewMockReferralDiscountRewardService(ctrl) volumeDiscount := fmock.NewMockVolumeDiscountService(ctrl) - referralDiscountReward.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + referralDiscountReward.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("not a referrer")).AnyTimes() banking := mocks.NewMockBanking(ctrl) parties := mocks.NewMockParties(ctrl) diff --git a/core/execution/future/market_test.go b/core/execution/future/market_test.go index 70c945919a0..d69df9fb56f 100644 --- a/core/execution/future/market_test.go +++ b/core/execution/future/market_test.go @@ -241,9 +241,9 @@ func (tm *testMarket) Run(ctx context.Context, mktCfg types.Market) *testMarket referralDiscountReward := fmocks.NewMockReferralDiscountRewardService(tm.ctrl) volumeDiscount := fmocks.NewMockVolumeDiscountService(tm.ctrl) referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("no referrer")).AnyTimes() - referralDiscountReward.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - referralDiscountReward.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + referralDiscountReward.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + referralDiscountReward.EXPECT().RewardsFactorsMultiplierAppliedForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() banking := mocks.NewMockBanking(tm.ctrl) parties := mocks.NewMockParties(tm.ctrl) @@ -654,9 +654,9 @@ func getTestMarket2WithDP( referralDiscountReward := fmocks.NewMockReferralDiscountRewardService(tm.ctrl) volumeDiscount := fmocks.NewMockVolumeDiscountService(tm.ctrl) referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("no referrer")).AnyTimes() - referralDiscountReward.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - referralDiscountReward.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + referralDiscountReward.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + referralDiscountReward.EXPECT().RewardsFactorsMultiplierAppliedForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() banking := mocks.NewMockBanking(ctrl) parties := mocks.NewMockParties(ctrl) diff --git a/core/execution/snapshot_test.go b/core/execution/snapshot_test.go index 6bb7f899871..e6b36b60057 100644 --- a/core/execution/snapshot_test.go +++ b/core/execution/snapshot_test.go @@ -624,9 +624,9 @@ func getEngine(t *testing.T, vegaPath paths.Paths, now time.Time) *snapshotTestD require.NoError(t, collateralEngine.EnableAsset(context.Background(), ethAsset)) referralDiscountReward := fmock.NewMockReferralDiscountRewardService(ctrl) volumeDiscount := fmock.NewMockVolumeDiscountService(ctrl) - referralDiscountReward.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - referralDiscountReward.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + referralDiscountReward.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + referralDiscountReward.EXPECT().RewardsFactorsMultiplierAppliedForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("not a referrer")).AnyTimes() banking := mocks.NewMockBanking(ctrl) parties := mocks.NewMockParties(ctrl) @@ -697,9 +697,9 @@ func getEngineWithParties(t *testing.T, now time.Time, balance *num.Uint, partie } referralDiscountReward := fmock.NewMockReferralDiscountRewardService(ctrl) volumeDiscount := fmock.NewMockVolumeDiscountService(ctrl) - referralDiscountReward.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - referralDiscountReward.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + referralDiscountReward.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + referralDiscountReward.EXPECT().RewardsFactorsMultiplierAppliedForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("not a referrer")).AnyTimes() banking := mocks.NewMockBanking(ctrl) partiesMock := mocks.NewMockParties(ctrl) diff --git a/core/execution/spot/market_callbacks.go b/core/execution/spot/market_callbacks.go index 690a4c0a057..a87ba4536d4 100644 --- a/core/execution/spot/market_callbacks.go +++ b/core/execution/spot/market_callbacks.go @@ -42,6 +42,18 @@ func (m *Market) OnMarketProbabilityOfTradingTauScalingUpdate(_ context.Context, m.liquidity.OnProbabilityOfTradingTauScalingUpdate(d) } +func (m *Market) OnFeeFactorsTreasuryFeeUpdate(ctx context.Context, d num.Decimal) { + m.fee.OnFeeFactorsTreasuryFeeUpdate(d) + m.mkt.Fees.Factors.TreasuryFee = d + m.broker.Send(events.NewMarketUpdatedEvent(ctx, *m.mkt)) +} + +func (m *Market) OnFeeFactorsBuyBackFeeUpdate(ctx context.Context, d num.Decimal) { + m.fee.OnFeeFactorsBuyBackFeeUpdate(d) + m.mkt.Fees.Factors.BuyBackFee = d + m.broker.Send(events.NewMarketUpdatedEvent(ctx, *m.mkt)) +} + func (m *Market) OnFeeFactorsMakerFeeUpdate(ctx context.Context, d num.Decimal) { m.fee.OnFeeFactorsMakerFeeUpdate(d) m.mkt.Fees.Factors.MakerFee = d diff --git a/core/execution/spot/market_test.go b/core/execution/spot/market_test.go index c8b84aa9289..0445716b845 100644 --- a/core/execution/spot/market_test.go +++ b/core/execution/spot/market_test.go @@ -219,9 +219,9 @@ func newTestMarket( referralDiscountReward := fmocks.NewMockReferralDiscountRewardService(ctrl) volumeDiscount := fmocks.NewMockVolumeDiscountService(ctrl) referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("no referrer")).AnyTimes() - referralDiscountReward.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - referralDiscountReward.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + referralDiscountReward.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + referralDiscountReward.EXPECT().RewardsFactorsMultiplierAppliedForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() banking := mocks.NewMockBanking(ctrl) market, _ := spot.NewMarket(log, matching.NewDefaultConfig(), fee.NewDefaultConfig(), liquidity.NewDefaultConfig(), collateral, &mkt, ts, broker, as, statevarEngine, mat, baseAsset, quoteAsset, peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, banking) diff --git a/core/fee/engine.go b/core/fee/engine.go index 516988a724e..87a85217e46 100644 --- a/core/fee/engine.go +++ b/core/fee/engine.go @@ -33,13 +33,13 @@ var ( //go:generate go run github.com/golang/mock/mockgen -destination mocks/mocks.go -package mocks code.vegaprotocol.io/vega/core/fee ReferralDiscountRewardService,VolumeDiscountService type ReferralDiscountRewardService interface { - ReferralDiscountFactorForParty(party types.PartyID) num.Decimal - RewardsFactorMultiplierAppliedForParty(party types.PartyID) num.Decimal + ReferralDiscountFactorsForParty(party types.PartyID) types.Factors + RewardsFactorsMultiplierAppliedForParty(party types.PartyID) types.Factors GetReferrer(referee types.PartyID) (types.PartyID, error) } type VolumeDiscountService interface { - VolumeDiscountFactorForParty(party types.PartyID) num.Decimal + VolumeDiscountFactorForParty(party types.PartyID) types.Factors } type Engine struct { @@ -58,6 +58,8 @@ type factors struct { makerFee num.Decimal infrastructureFee num.Decimal liquidityFee num.Decimal + treasuryFee num.Decimal + buyBackFee num.Decimal } func New( @@ -137,6 +139,8 @@ func (e *Engine) UpdateFeeFactors(fees types.Fees) error { if !fees.Factors.LiquidityFee.IsZero() && fees.Factors.LiquidityFee.IsPositive() { e.f.liquidityFee = fees.Factors.LiquidityFee } + e.f.treasuryFee = fees.Factors.TreasuryFee + e.f.buyBackFee = fees.Factors.BuyBackFee e.feeCfg = fees return nil @@ -221,6 +225,26 @@ func (e *Engine) CalculateForContinuousMode( Type: types.TransferTypeMakerFeeReceive, }) + // create a transfer for the aggressor + transfers = append(transfers, &types.Transfer{ + Owner: taker, + Amount: &types.FinancialAmount{ + Asset: e.asset, + Amount: fee.BuyBackFee.Clone(), + }, + Type: types.TransferTypeBuyBackFeePay, + }) + + // create a transfer for the aggressor + transfers = append(transfers, &types.Transfer{ + Owner: taker, + Amount: &types.FinancialAmount{ + Asset: e.asset, + Amount: fee.TreasuryFee.Clone(), + }, + Type: types.TransferTypeTreasuryPay, + }) + if reward == nil { continue } @@ -510,6 +534,8 @@ func (e *Engine) getNetworkFeeWithMakerTransfer(fees *types.Fee, current *types. 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 } @@ -542,21 +568,39 @@ func (e *Engine) getNetworkFeeTransfers(fees *types.Fee) ([]*types.Transfer, *nu MinAmount: num.UintZero(), Type: types.TransferTypeLiquidityFeePay, }, + { + Owner: types.NetworkParty, + Amount: &types.FinancialAmount{ + Asset: e.asset, + Amount: fees.BuyBackFee.Clone(), + }, + MinAmount: num.UintZero(), + Type: types.TransferTypeBuyBackFeePay, + }, + { + Owner: types.NetworkParty, + Amount: &types.FinancialAmount{ + Asset: e.asset, + Amount: fees.TreasuryFee.Clone(), + }, + MinAmount: num.UintZero(), + Type: types.TransferTypeTreasuryPay, + }, }, num.Sum(fees.MakerFee, fees.InfrastructureFee, fees.LiquidityFee) } func (e *Engine) applyDiscountsAndRewards(taker string, fees *types.Fee, referral ReferralDiscountRewardService, volumeDiscount VolumeDiscountService) (*types.Fee, *types.ReferrerReward) { - referralDiscountFactor := referral.ReferralDiscountFactorForParty(types.PartyID(taker)) - volumeDiscountFactor := volumeDiscount.VolumeDiscountFactorForParty(types.PartyID(taker)) + referralDiscountFactors := referral.ReferralDiscountFactorsForParty(types.PartyID(taker)) + volumeDiscountFactors := volumeDiscount.VolumeDiscountFactorForParty(types.PartyID(taker)) mf := fees.MakerFee.Clone() inf := fees.InfrastructureFee.Clone() lf := fees.LiquidityFee.Clone() // calculate referral discounts - referralMakerDiscount, _ := num.UintFromDecimal(mf.ToDecimal().Mul(referralDiscountFactor).Floor()) - referralInfDiscount, _ := num.UintFromDecimal(inf.ToDecimal().Mul(referralDiscountFactor).Floor()) - referralLfDiscount, _ := num.UintFromDecimal(lf.ToDecimal().Mul(referralDiscountFactor).Floor()) + referralMakerDiscount, _ := num.UintFromDecimal(mf.ToDecimal().Mul(referralDiscountFactors.Maker).Floor()) + referralInfDiscount, _ := num.UintFromDecimal(inf.ToDecimal().Mul(referralDiscountFactors.Infra).Floor()) + referralLfDiscount, _ := num.UintFromDecimal(lf.ToDecimal().Mul(referralDiscountFactors.Liquidity).Floor()) // apply referral discounts mf = mf.Sub(mf, referralMakerDiscount) @@ -564,9 +608,9 @@ func (e *Engine) applyDiscountsAndRewards(taker string, fees *types.Fee, referra lf = lf.Sub(lf, referralLfDiscount) // calculate volume discounts - volumeMakerDiscount, _ := num.UintFromDecimal(mf.ToDecimal().Mul(volumeDiscountFactor).Floor()) - volumeInfDiscount, _ := num.UintFromDecimal(inf.ToDecimal().Mul(volumeDiscountFactor).Floor()) - volumeLfDiscount, _ := num.UintFromDecimal(lf.ToDecimal().Mul(volumeDiscountFactor).Floor()) + volumeMakerDiscount, _ := num.UintFromDecimal(mf.ToDecimal().Mul(volumeDiscountFactors.Maker).Floor()) + volumeInfDiscount, _ := num.UintFromDecimal(inf.ToDecimal().Mul(volumeDiscountFactors.Infra).Floor()) + volumeLfDiscount, _ := num.UintFromDecimal(lf.ToDecimal().Mul(volumeDiscountFactors.Liquidity).Floor()) // apply volume discounts mf = mf.Sub(mf, volumeMakerDiscount) @@ -577,6 +621,8 @@ func (e *Engine) applyDiscountsAndRewards(taker string, fees *types.Fee, referra MakerFee: mf, LiquidityFee: lf, InfrastructureFee: inf, + BuyBackFee: fees.BuyBackFee.Clone(), + TreasuryFee: fees.TreasuryFee.Clone(), MakerFeeVolumeDiscount: volumeMakerDiscount, InfrastructureFeeVolumeDiscount: volumeInfDiscount, LiquidityFeeVolumeDiscount: volumeLfDiscount, @@ -604,16 +650,16 @@ func (e *Engine) applyDiscountsAndRewards(taker string, fees *types.Fee, referra ) // calculate rewards - factor := referral.RewardsFactorMultiplierAppliedForParty(types.PartyID(taker)) - if factor.IsZero() { + factors := referral.RewardsFactorsMultiplierAppliedForParty(types.PartyID(taker)) + if factors == types.EmptyFactors { return f, nil } referrerReward := types.NewReferrerReward() - referrerReward.MakerFeeReferrerReward, _ = num.UintFromDecimal(factor.Mul(mf.ToDecimal()).Floor()) - referrerReward.InfrastructureFeeReferrerReward, _ = num.UintFromDecimal(factor.Mul(inf.ToDecimal()).Floor()) - referrerReward.LiquidityFeeReferrerReward, _ = num.UintFromDecimal(factor.Mul(lf.ToDecimal()).Floor()) + referrerReward.MakerFeeReferrerReward, _ = num.UintFromDecimal(factors.Maker.Mul(mf.ToDecimal()).Floor()) + referrerReward.InfrastructureFeeReferrerReward, _ = num.UintFromDecimal(factors.Infra.Mul(inf.ToDecimal()).Floor()) + referrerReward.LiquidityFeeReferrerReward, _ = num.UintFromDecimal(factors.Liquidity.Mul(lf.ToDecimal()).Floor()) mf = mf.Sub(mf, referrerReward.MakerFeeReferrerReward) inf = inf.Sub(inf, referrerReward.InfrastructureFeeReferrerReward) @@ -677,10 +723,14 @@ func (e *Engine) calculateContinuousModeFees(trade *types.Trade) *types.Fee { mf, _ := num.UintFromDecimal(total.Mul(e.f.makerFee).Ceil()) inf, _ := num.UintFromDecimal(total.Mul(e.f.infrastructureFee).Ceil()) lf, _ := num.UintFromDecimal(total.Mul(e.f.liquidityFee).Ceil()) + bbf, _ := num.UintFromDecimal(total.Mul(e.f.buyBackFee).Ceil()) + tf, _ := num.UintFromDecimal(total.Mul(e.f.treasuryFee).Ceil()) return &types.Fee{ MakerFee: mf, InfrastructureFee: inf, LiquidityFee: lf, + BuyBackFee: bbf, + TreasuryFee: tf, } } @@ -689,10 +739,14 @@ func (e *Engine) calculateAuctionModeFees(trade *types.Trade) *types.Fee { two := num.DecimalFromInt64(2) inf, _ := num.UintFromDecimal(fee.InfrastructureFee.ToDecimal().Div(two).Ceil()) lf, _ := num.UintFromDecimal(fee.LiquidityFee.ToDecimal().Div(two).Ceil()) + bbf, _ := num.UintFromDecimal(fee.BuyBackFee.ToDecimal().Div(two).Ceil()) + tf, _ := num.UintFromDecimal(fee.TreasuryFee.ToDecimal().Div(two).Ceil()) return &types.Fee{ MakerFee: num.UintZero(), InfrastructureFee: inf, LiquidityFee: lf, + TreasuryFee: tf, + BuyBackFee: bbf, } } @@ -760,6 +814,16 @@ func (e *Engine) OnFeeFactorsMakerFeeUpdate(f num.Decimal) { e.f.makerFee = f } +func (e *Engine) OnFeeFactorsBuyBackFeeUpdate(f num.Decimal) { + e.feeCfg.Factors.BuyBackFee = f + e.f.buyBackFee = f +} + +func (e *Engine) OnFeeFactorsTreasuryFeeUpdate(f num.Decimal) { + e.feeCfg.Factors.TreasuryFee = f + e.f.treasuryFee = f +} + func (e *Engine) OnFeeFactorsInfrastructureFeeUpdate(f num.Decimal) { e.feeCfg.Factors.InfrastructureFee = f e.f.infrastructureFee = f diff --git a/core/fee/engine_test.go b/core/fee/engine_test.go index 30c0889aceb..0c4f56d117f 100644 --- a/core/fee/engine_test.go +++ b/core/fee/engine_test.go @@ -141,9 +141,9 @@ func testCalcContinuousTradingAndCheckAmounts(t *testing.T) { ctrl := gomock.NewController(t) discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl) volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl) - discountRewardService.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - discountRewardService.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + 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() require.NoError(t, eng.UpdateFeeFactors(types.Fees{ Factors: &types.FeeFactors{ @@ -249,9 +249,22 @@ func testCalcContinuousTradingAndCheckAmountsWithDiscount(t *testing.T) { ctrl := gomock.NewController(t) discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl) volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl) - discountRewardService.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalFromFloat(0.3)).AnyTimes() - discountRewardService.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalFromFloat(0.2)).AnyTimes() - volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalFromFloat(0.1)).AnyTimes() + discountRewardService.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.Factors{ + Infra: num.NewDecimalFromFloat(0.3), + Maker: num.NewDecimalFromFloat(0.3), + Liquidity: num.NewDecimalFromFloat(0.3), + }).AnyTimes() + discountRewardService.EXPECT().RewardsFactorsMultiplierAppliedForParty(gomock.Any()).Return(types.Factors{ + Infra: num.NewDecimalFromFloat(0.2), + Maker: num.NewDecimalFromFloat(0.2), + Liquidity: num.NewDecimalFromFloat(0.2), + }).AnyTimes() + volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return( + types.Factors{ + Infra: num.NewDecimalFromFloat(0.1), + Maker: num.NewDecimalFromFloat(0.1), + Liquidity: num.NewDecimalFromFloat(0.1), + }) discountRewardService.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID("party3"), nil).AnyTimes() require.NoError(t, eng.UpdateFeeFactors(types.Fees{ Factors: &types.FeeFactors{ @@ -398,11 +411,27 @@ func testCalcContinuousTradingAndCheckAmountsWithDiscountsAndRewardsBySide(t *te aggressor = "party2" } - discountRewardService.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalFromFloat(0.5)).AnyTimes() - volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalFromFloat(0.25)).AnyTimes() + discountRewardService.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.Factors{ + Infra: num.NewDecimalFromFloat(0.5), + Maker: num.NewDecimalFromFloat(0.5), + Liquidity: num.NewDecimalFromFloat(0.5), + }).AnyTimes() + volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(types.Factors{ + Infra: num.NewDecimalFromFloat(0.25), + Maker: num.NewDecimalFromFloat(0.25), + Liquidity: num.NewDecimalFromFloat(0.25), + }) discountRewardService.EXPECT().GetReferrer(types.PartyID(aggressor)).Return(types.PartyID("referrer"), nil).AnyTimes() - discountRewardService.EXPECT().RewardsFactorMultiplierAppliedForParty(types.PartyID("party1")).Return(num.DecimalFromFloat(0.3)).AnyTimes() - discountRewardService.EXPECT().RewardsFactorMultiplierAppliedForParty(types.PartyID("party2")).Return(num.DecimalFromFloat(0.3)).AnyTimes() + discountRewardService.EXPECT().RewardsFactorsMultiplierAppliedForParty(types.PartyID("party1")).Return(types.Factors{ + Infra: num.NewDecimalFromFloat(0.3), + Maker: num.NewDecimalFromFloat(0.3), + Liquidity: num.NewDecimalFromFloat(0.3), + }).AnyTimes() + discountRewardService.EXPECT().RewardsFactorsMultiplierAppliedForParty(types.PartyID("party2")).Return(types.Factors{ + Infra: num.NewDecimalFromFloat(0.3), + Maker: num.NewDecimalFromFloat(0.3), + Liquidity: num.NewDecimalFromFloat(0.3), + }).AnyTimes() ft, err := eng.CalculateForContinuousMode(trades, discountRewardService, volumeDiscountService) assert.NotNil(t, ft) @@ -504,12 +533,28 @@ func testCalcContinuousTradingAndCheckAmountsWithDiscountsAndRewardsBySideMultip aggressor = "party2" } - discountRewardService.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalFromFloat(0.5)).AnyTimes() - volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalFromFloat(0.25)).AnyTimes() + discountRewardService.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.Factors{ + Infra: num.NewDecimalFromFloat(0.5), + Maker: num.NewDecimalFromFloat(0.5), + Liquidity: num.NewDecimalFromFloat(0.5), + }).AnyTimes() + volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(types.Factors{ + Infra: num.NewDecimalFromFloat(0.25), + Maker: num.NewDecimalFromFloat(0.25), + Liquidity: num.NewDecimalFromFloat(0.25), + }).AnyTimes() discountRewardService.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID("referrer"), nil).AnyTimes() discountRewardService.EXPECT().GetReferrer(types.PartyID(aggressor)).Return(types.PartyID("referrer"), nil).AnyTimes() - discountRewardService.EXPECT().RewardsFactorMultiplierAppliedForParty(aggressor).Return(num.DecimalFromFloat(0.3)).AnyTimes() - discountRewardService.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalFromFloat(0.3)).AnyTimes() + discountRewardService.EXPECT().RewardsFactorsMultiplierAppliedForParty(aggressor).Return(types.Factors{ + Infra: num.NewDecimalFromFloat(0.3), + Maker: num.NewDecimalFromFloat(0.3), + Liquidity: num.NewDecimalFromFloat(0.3), + }).AnyTimes() + discountRewardService.EXPECT().RewardsFactorsMultiplierAppliedForParty(gomock.Any()).Return(types.Factors{ + Infra: num.NewDecimalFromFloat(0.3), + Maker: num.NewDecimalFromFloat(0.3), + Liquidity: num.NewDecimalFromFloat(0.3), + }).AnyTimes() ft, err := eng.CalculateForContinuousMode(trades, discountRewardService, volumeDiscountService) assert.NotNil(t, ft) @@ -639,9 +684,9 @@ func testCalcContinuousTrading(t *testing.T) { ctrl := gomock.NewController(t) discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl) volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl) - discountRewardService.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - discountRewardService.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + 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("party1"), errors.New("not a referrer")).AnyTimes() trades := []*types.Trade{ @@ -730,9 +775,9 @@ func testCalcAuctionTrading(t *testing.T) { ctrl := gomock.NewController(t) discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl) volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl) - discountRewardService.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - discountRewardService.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + 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() trades := []*types.Trade{ { @@ -790,18 +835,30 @@ func TestCalcAuctionTradingWithDiscountsAndRewards(t *testing.T) { ctrl := gomock.NewController(t) discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl) volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl) - discountRewardService.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).DoAndReturn(func(p types.PartyID) num.Decimal { + discountRewardService.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).DoAndReturn(func(p types.PartyID) types.Factors { if p == types.PartyID("party1") { - return num.DecimalZero() + return types.EmptyFactors } else { - return num.NewDecimalFromFloat(0.5) + return types.Factors{ + Infra: num.NewDecimalFromFloat(0.5), + Maker: num.NewDecimalFromFloat(0.5), + Liquidity: num.NewDecimalFromFloat(0.5), + } } }).AnyTimes() - volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).DoAndReturn(func(p types.PartyID) num.Decimal { + volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).DoAndReturn(func(p types.PartyID) types.Factors { if p == types.PartyID("party1") { - return num.NewDecimalFromFloat(0.2) + return types.Factors{ + Infra: num.NewDecimalFromFloat(0.2), + Maker: num.NewDecimalFromFloat(0.2), + Liquidity: num.NewDecimalFromFloat(0.2), + } } else { - return num.NewDecimalFromFloat(0.3) + return types.Factors{ + Infra: num.NewDecimalFromFloat(0.3), + Maker: num.NewDecimalFromFloat(0.3), + Liquidity: num.NewDecimalFromFloat(0.3), + } } }).AnyTimes() discountRewardService.EXPECT().GetReferrer(gomock.Any()).DoAndReturn(func(p types.PartyID) (types.PartyID, error) { @@ -811,8 +868,12 @@ func TestCalcAuctionTradingWithDiscountsAndRewards(t *testing.T) { return types.PartyID(""), errors.New("No referrer") } }).AnyTimes() - discountRewardService.EXPECT().RewardsFactorMultiplierAppliedForParty(types.PartyID("party1")).Return(num.DecimalFromFloat(0.5)).AnyTimes() - discountRewardService.EXPECT().RewardsFactorMultiplierAppliedForParty(types.PartyID("party2")).Return(num.DecimalZero()).AnyTimes() + discountRewardService.EXPECT().RewardsFactorsMultiplierAppliedForParty(types.PartyID("party1")).Return(types.Factors{ + Infra: num.NewDecimalFromFloat(0.5), + Maker: num.NewDecimalFromFloat(0.5), + Liquidity: num.NewDecimalFromFloat(0.5), + }).AnyTimes() + discountRewardService.EXPECT().RewardsFactorsMultiplierAppliedForParty(types.PartyID("party2")).Return(types.EmptyFactors).AnyTimes() trades := []*types.Trade{ { @@ -907,9 +968,9 @@ func testCalcBatchAuctionTradingSameBatch(t *testing.T) { ctrl := gomock.NewController(t) discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl) volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl) - discountRewardService.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - discountRewardService.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + 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() trades := []*types.Trade{ { @@ -969,9 +1030,9 @@ func testCalcBatchAuctionTradingDifferentBatches(t *testing.T) { ctrl := gomock.NewController(t) discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl) volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl) - discountRewardService.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - discountRewardService.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + 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() trades := []*types.Trade{ { @@ -1028,9 +1089,9 @@ func testCloseoutFees(t *testing.T) { ctrl := gomock.NewController(t) discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl) volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl) - discountRewardService.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - discountRewardService.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - volumeDiscountService.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + 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() trades := []*types.Trade{ { @@ -1067,9 +1128,10 @@ func testCloseoutFees(t *testing.T) { assert.NotNil(t, fee) allTransfers := ft.Transfers() // first we have the network -> pay transfers, then 1 transfer per good party - assert.Equal(t, len(trades), len(allTransfers)-3) - goodPartyTransfers := allTransfers[3:] - networkTransfers := allTransfers[:3] + // two additional transfers for the buy back and treasury fees + assert.Equal(t, len(trades), len(allTransfers)-5) + goodPartyTransfers := allTransfers[5:] + networkTransfers := allTransfers[:5] numTrades := num.NewUint(uint64(len(trades))) // maker fee is 100 * 0.02 == 2 diff --git a/core/fee/mocks/mocks.go b/core/fee/mocks/mocks.go index 8b4f5a3a07f..ee1d1cab7fd 100644 --- a/core/fee/mocks/mocks.go +++ b/core/fee/mocks/mocks.go @@ -9,7 +9,6 @@ import ( types "code.vegaprotocol.io/vega/core/types" gomock "github.com/golang/mock/gomock" - decimal "github.com/shopspring/decimal" ) // MockReferralDiscountRewardService is a mock of ReferralDiscountRewardService interface. @@ -50,32 +49,32 @@ func (mr *MockReferralDiscountRewardServiceMockRecorder) GetReferrer(arg0 interf return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReferrer", reflect.TypeOf((*MockReferralDiscountRewardService)(nil).GetReferrer), arg0) } -// ReferralDiscountFactorForParty mocks base method. -func (m *MockReferralDiscountRewardService) ReferralDiscountFactorForParty(arg0 types.PartyID) decimal.Decimal { +// ReferralDiscountFactorsForParty mocks base method. +func (m *MockReferralDiscountRewardService) ReferralDiscountFactorsForParty(arg0 types.PartyID) types.Factors { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ReferralDiscountFactorForParty", arg0) - ret0, _ := ret[0].(decimal.Decimal) + ret := m.ctrl.Call(m, "ReferralDiscountFactorsForParty", arg0) + ret0, _ := ret[0].(types.Factors) return ret0 } -// ReferralDiscountFactorForParty indicates an expected call of ReferralDiscountFactorForParty. -func (mr *MockReferralDiscountRewardServiceMockRecorder) ReferralDiscountFactorForParty(arg0 interface{}) *gomock.Call { +// ReferralDiscountFactorsForParty indicates an expected call of ReferralDiscountFactorsForParty. +func (mr *MockReferralDiscountRewardServiceMockRecorder) ReferralDiscountFactorsForParty(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReferralDiscountFactorForParty", reflect.TypeOf((*MockReferralDiscountRewardService)(nil).ReferralDiscountFactorForParty), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReferralDiscountFactorsForParty", reflect.TypeOf((*MockReferralDiscountRewardService)(nil).ReferralDiscountFactorsForParty), arg0) } -// RewardsFactorMultiplierAppliedForParty mocks base method. -func (m *MockReferralDiscountRewardService) RewardsFactorMultiplierAppliedForParty(arg0 types.PartyID) decimal.Decimal { +// RewardsFactorsMultiplierAppliedForParty mocks base method. +func (m *MockReferralDiscountRewardService) RewardsFactorsMultiplierAppliedForParty(arg0 types.PartyID) types.Factors { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RewardsFactorMultiplierAppliedForParty", arg0) - ret0, _ := ret[0].(decimal.Decimal) + ret := m.ctrl.Call(m, "RewardsFactorsMultiplierAppliedForParty", arg0) + ret0, _ := ret[0].(types.Factors) return ret0 } -// RewardsFactorMultiplierAppliedForParty indicates an expected call of RewardsFactorMultiplierAppliedForParty. -func (mr *MockReferralDiscountRewardServiceMockRecorder) RewardsFactorMultiplierAppliedForParty(arg0 interface{}) *gomock.Call { +// RewardsFactorsMultiplierAppliedForParty indicates an expected call of RewardsFactorsMultiplierAppliedForParty. +func (mr *MockReferralDiscountRewardServiceMockRecorder) RewardsFactorsMultiplierAppliedForParty(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RewardsFactorMultiplierAppliedForParty", reflect.TypeOf((*MockReferralDiscountRewardService)(nil).RewardsFactorMultiplierAppliedForParty), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RewardsFactorsMultiplierAppliedForParty", reflect.TypeOf((*MockReferralDiscountRewardService)(nil).RewardsFactorsMultiplierAppliedForParty), arg0) } // MockVolumeDiscountService is a mock of VolumeDiscountService interface. @@ -102,10 +101,10 @@ func (m *MockVolumeDiscountService) EXPECT() *MockVolumeDiscountServiceMockRecor } // VolumeDiscountFactorForParty mocks base method. -func (m *MockVolumeDiscountService) VolumeDiscountFactorForParty(arg0 types.PartyID) decimal.Decimal { +func (m *MockVolumeDiscountService) VolumeDiscountFactorForParty(arg0 types.PartyID) types.Factors { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "VolumeDiscountFactorForParty", arg0) - ret0, _ := ret[0].(decimal.Decimal) + ret0, _ := ret[0].(types.Factors) return ret0 } diff --git a/core/governance/engine_update_discount_volume_program_test.go b/core/governance/engine_update_discount_volume_program_test.go index e6c82993b93..b97ebfbd4a9 100644 --- a/core/governance/engine_update_discount_volume_program_test.go +++ b/core/governance/engine_update_discount_volume_program_test.go @@ -61,10 +61,18 @@ func testSubmittingProposalForVolumeDiscountProgramUpdateSucceeds(t *testing.T) VolumeBenefitTiers: []*types.VolumeBenefitTier{ { MinimumRunningNotionalTakerVolume: num.NewUint(10000), - VolumeDiscountFactor: num.DecimalFromFloat(0.001), + VolumeDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.001), + Maker: num.DecimalFromFloat(0.001), + Liquidity: num.DecimalFromFloat(0.001), + }, }, { MinimumRunningNotionalTakerVolume: num.NewUint(20000), - VolumeDiscountFactor: num.DecimalFromFloat(0.005), + VolumeDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.005), + Maker: num.DecimalFromFloat(0.005), + Liquidity: num.DecimalFromFloat(0.005), + }, }, }, }) @@ -108,10 +116,18 @@ func testSubmittingProposalForVolumeDiscountProgramUpdateWithTooManyTiersFails(t VolumeBenefitTiers: []*types.VolumeBenefitTier{ { MinimumRunningNotionalTakerVolume: num.NewUint(10000), - VolumeDiscountFactor: num.DecimalFromFloat(0.001), + VolumeDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.001), + Maker: num.DecimalFromFloat(0.001), + Liquidity: num.DecimalFromFloat(0.001), + }, }, { MinimumRunningNotionalTakerVolume: num.NewUint(20000), - VolumeDiscountFactor: num.DecimalFromFloat(0.005), + VolumeDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.005), + Maker: num.DecimalFromFloat(0.005), + Liquidity: num.DecimalFromFloat(0.005), + }, }, }, }) @@ -155,10 +171,18 @@ func testSubmittingProposalForVolumeDiscountProgramUpdateWithTooHighDiscountFact VolumeBenefitTiers: []*types.VolumeBenefitTier{ { MinimumRunningNotionalTakerVolume: num.NewUint(10000), - VolumeDiscountFactor: num.DecimalFromFloat(0.001), + VolumeDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.001), + Maker: num.DecimalFromFloat(0.001), + Liquidity: num.DecimalFromFloat(0.001), + }, }, { MinimumRunningNotionalTakerVolume: num.NewUint(20000), - VolumeDiscountFactor: num.DecimalFromFloat(0.015), + VolumeDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.015), + Maker: num.DecimalFromFloat(0.015), + Liquidity: num.DecimalFromFloat(0.015), + }, }, }, }) @@ -175,7 +199,7 @@ func testSubmittingProposalForVolumeDiscountProgramUpdateWithTooHighDiscountFact // then require.EqualError(t, err, - "tier 2 defines a volume discount factor higher than the maximum allowed by the network parameter \"volumeDiscountProgram.maxVolumeDiscountFactor\": maximum is 0.01, but got 0.015", + "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", ) require.Nil(t, toSubmit) } diff --git a/core/governance/engine_update_referral_program_test.go b/core/governance/engine_update_referral_program_test.go index d5550a37a20..4bf5f1fea1f 100644 --- a/core/governance/engine_update_referral_program_test.go +++ b/core/governance/engine_update_referral_program_test.go @@ -67,13 +67,29 @@ func testSubmittingProposalForReferralProgramUpdateSucceeds(t *testing.T) { { MinimumEpochs: num.NewUint(1), MinimumRunningNotionalTakerVolume: num.NewUint(10000), - ReferralRewardFactor: num.DecimalFromFloat(0.001), - ReferralDiscountFactor: num.DecimalFromFloat(0.001), + ReferralRewardFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.001), + Maker: num.DecimalFromFloat(0.001), + Liquidity: num.DecimalFromFloat(0.001), + }, + ReferralDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.001), + Maker: num.DecimalFromFloat(0.001), + Liquidity: num.DecimalFromFloat(0.001), + }, }, { MinimumEpochs: num.NewUint(7), MinimumRunningNotionalTakerVolume: num.NewUint(20000), - ReferralRewardFactor: num.DecimalFromFloat(0.005), - ReferralDiscountFactor: num.DecimalFromFloat(0.005), + ReferralRewardFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.005), + Maker: num.DecimalFromFloat(0.005), + Liquidity: num.DecimalFromFloat(0.005), + }, + ReferralDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.005), + Maker: num.DecimalFromFloat(0.005), + Liquidity: num.DecimalFromFloat(0.005), + }, }, }, }) @@ -121,13 +137,29 @@ func testSubmittingProposalForReferralProgramUpdateWithTooManyTiersFails(t *test { MinimumEpochs: num.NewUint(1), MinimumRunningNotionalTakerVolume: num.NewUint(10000), - ReferralRewardFactor: num.DecimalFromFloat(0.001), - ReferralDiscountFactor: num.DecimalFromFloat(0.001), + ReferralRewardFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.001), + Maker: num.DecimalFromFloat(0.001), + Liquidity: num.DecimalFromFloat(0.001), + }, + ReferralDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.001), + Maker: num.DecimalFromFloat(0.001), + Liquidity: num.DecimalFromFloat(0.001), + }, }, { MinimumEpochs: num.NewUint(7), MinimumRunningNotionalTakerVolume: num.NewUint(20000), - ReferralRewardFactor: num.DecimalFromFloat(0.005), - ReferralDiscountFactor: num.DecimalFromFloat(0.005), + ReferralRewardFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.005), + Maker: num.DecimalFromFloat(0.005), + Liquidity: num.DecimalFromFloat(0.005), + }, + ReferralDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.005), + Maker: num.DecimalFromFloat(0.005), + Liquidity: num.DecimalFromFloat(0.005), + }, }, }, }) @@ -175,13 +207,29 @@ func testSubmittingProposalForReferralProgramUpdateWithTooHighRewardFactorFails( { MinimumEpochs: num.NewUint(1), MinimumRunningNotionalTakerVolume: num.NewUint(10000), - ReferralRewardFactor: num.DecimalFromFloat(0.001), - ReferralDiscountFactor: num.DecimalFromFloat(0.001), + ReferralRewardFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.001), + Maker: num.DecimalFromFloat(0.001), + Liquidity: num.DecimalFromFloat(0.001), + }, + ReferralDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.001), + Maker: num.DecimalFromFloat(0.001), + Liquidity: num.DecimalFromFloat(0.001), + }, }, { MinimumEpochs: num.NewUint(7), MinimumRunningNotionalTakerVolume: num.NewUint(20000), - ReferralRewardFactor: num.DecimalFromFloat(0.015), - ReferralDiscountFactor: num.DecimalFromFloat(0.005), + ReferralRewardFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.015), + Maker: num.DecimalFromFloat(0.015), + Liquidity: num.DecimalFromFloat(0.015), + }, + ReferralDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.005), + Maker: num.DecimalFromFloat(0.005), + Liquidity: num.DecimalFromFloat(0.005), + }, }, }, }) @@ -198,7 +246,7 @@ func testSubmittingProposalForReferralProgramUpdateWithTooHighRewardFactorFails( // then require.EqualError(t, err, - "tier 2 defines a referral reward factor higher than the maximum allowed by the network parameter \"referralProgram.maxReferralRewardFactor\": maximum is 0.01, but got 0.015", + "tier 2 defines a referral reward infrastructure factor higher than the maximum allowed by the network parameter \"referralProgram.maxReferralRewardFactor\": maximum is 0.01, but got 0.015", ) require.Nil(t, toSubmit) } @@ -232,13 +280,29 @@ func testSubmittingProposalForReferralProgramUpdateWithTooHighDiscountFactorFail { MinimumEpochs: num.NewUint(1), MinimumRunningNotionalTakerVolume: num.NewUint(10000), - ReferralRewardFactor: num.DecimalFromFloat(0.001), - ReferralDiscountFactor: num.DecimalFromFloat(0.001), + ReferralRewardFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.001), + Maker: num.DecimalFromFloat(0.001), + Liquidity: num.DecimalFromFloat(0.001), + }, + ReferralDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.001), + Maker: num.DecimalFromFloat(0.001), + Liquidity: num.DecimalFromFloat(0.001), + }, }, { MinimumEpochs: num.NewUint(7), MinimumRunningNotionalTakerVolume: num.NewUint(20000), - ReferralRewardFactor: num.DecimalFromFloat(0.010), - ReferralDiscountFactor: num.DecimalFromFloat(0.015), + ReferralRewardFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.01), + Maker: num.DecimalFromFloat(0.01), + Liquidity: num.DecimalFromFloat(0.01), + }, + ReferralDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.015), + Maker: num.DecimalFromFloat(0.015), + Liquidity: num.DecimalFromFloat(0.015), + }, }, }, }) @@ -255,7 +319,7 @@ func testSubmittingProposalForReferralProgramUpdateWithTooHighDiscountFactorFail // then require.EqualError(t, err, - "tier 2 defines a referral discount factor higher than the maximum allowed by the network parameter \"referralProgram.maxReferralDiscountFactor\": maximum is 0.01, but got 0.015", + "tier 2 defines a referral discount infrastructure factor higher than the maximum allowed by the network parameter \"referralProgram.maxReferralDiscountFactor\": maximum is 0.01, but got 0.015", ) require.Nil(t, toSubmit) } @@ -291,13 +355,29 @@ func testSubmittingProposalForReferralProgramUpdateEndsBeforeEnactsFails(t *test { MinimumEpochs: num.NewUint(1), MinimumRunningNotionalTakerVolume: num.NewUint(10000), - ReferralRewardFactor: num.DecimalFromFloat(0.001), - ReferralDiscountFactor: num.DecimalFromFloat(0.001), + ReferralRewardFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.001), + Maker: num.DecimalFromFloat(0.001), + Liquidity: num.DecimalFromFloat(0.001), + }, + ReferralDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.001), + Maker: num.DecimalFromFloat(0.001), + Liquidity: num.DecimalFromFloat(0.001), + }, }, { MinimumEpochs: num.NewUint(7), MinimumRunningNotionalTakerVolume: num.NewUint(20000), - ReferralRewardFactor: num.DecimalFromFloat(0.010), - ReferralDiscountFactor: num.DecimalFromFloat(0.015), + ReferralRewardFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.01), + Maker: num.DecimalFromFloat(0.01), + Liquidity: num.DecimalFromFloat(0.01), + }, + ReferralDiscountFactors: types.Factors{ + Infra: num.DecimalFromFloat(0.015), + Maker: num.DecimalFromFloat(0.015), + Liquidity: num.DecimalFromFloat(0.015), + }, }, }, }, diff --git a/core/governance/market.go b/core/governance/market.go index cbead25e66a..a173c484838 100644 --- a/core/governance/market.go +++ b/core/governance/market.go @@ -226,6 +226,9 @@ func buildMarketFromProposal( // get factors for the market makerFee, _ := netp.Get(netparams.MarketFeeFactorsMakerFee) infraFee, _ := netp.Get(netparams.MarketFeeFactorsInfrastructureFee) + buybackFee, _ := netp.Get(netparams.MarketFeeFactorsBuyBackFee) + treasuryFee, _ := netp.Get(netparams.MarketFeeFactorsTreasuryFee) + // get the margin scaling factors scalingFactors := proto.ScalingFactors{} _ = netp.GetJSONStruct(netparams.MarketMarginScalingFactors, &scalingFactors) @@ -250,6 +253,8 @@ func buildMarketFromProposal( } makerFeeDec, _ := num.DecimalFromString(makerFee) infraFeeDec, _ := num.DecimalFromString(infraFee) + buybackFeeDec, _ := num.DecimalFromString(buybackFee) + treasuryFeeDec, _ := num.DecimalFromString(treasuryFee) // assign here, we want to update this after assigning market variable marginCalc := &types.MarginCalculator{ ScalingFactors: types.ScalingFactorsFromProto(&scalingFactors), @@ -262,6 +267,8 @@ func buildMarketFromProposal( Factors: &types.FeeFactors{ MakerFee: makerFeeDec, InfrastructureFee: infraFeeDec, + TreasuryFee: treasuryFeeDec, + BuyBackFee: buybackFeeDec, }, LiquidityFeeSettings: definition.Changes.LiquidityFeeSettings, }, @@ -312,6 +319,8 @@ func buildSpotMarketFromProposal( // get factors for the market makerFee, _ := netp.Get(netparams.MarketFeeFactorsMakerFee) infraFee, _ := netp.Get(netparams.MarketFeeFactorsInfrastructureFee) + buybackFee, _ := netp.Get(netparams.MarketFeeFactorsBuyBackFee) + treasuryFee, _ := netp.Get(netparams.MarketFeeFactorsTreasuryFee) // get price monitoring parameters if definition.Changes.PriceMonitoringParameters == nil { pmParams := &proto.PriceMonitoringParameters{} @@ -332,6 +341,8 @@ func buildSpotMarketFromProposal( makerFeeDec, _ := num.DecimalFromString(makerFee) infraFeeDec, _ := num.DecimalFromString(infraFee) + buybackFeeDec, _ := num.DecimalFromString(buybackFee) + treasuryFeeDec, _ := num.DecimalFromString(treasuryFee) market := &types.Market{ ID: marketID, DecimalPlaces: definition.Changes.PriceDecimalPlaces, @@ -340,6 +351,8 @@ func buildSpotMarketFromProposal( Factors: &types.FeeFactors{ MakerFee: makerFeeDec, InfrastructureFee: infraFeeDec, + TreasuryFee: treasuryFeeDec, + BuyBackFee: buybackFeeDec, }, LiquidityFeeSettings: definition.Changes.LiquidityFeeSettings, }, diff --git a/core/governance/market_cp_restore_test.go b/core/governance/market_cp_restore_test.go index 15ed96971ce..e5c2bb0ffb8 100644 --- a/core/governance/market_cp_restore_test.go +++ b/core/governance/market_cp_restore_test.go @@ -206,8 +206,8 @@ func createExecutionEngine(t *testing.T, tm time.Time) (*execution.Engine, *gove referralDiscountReward := fmocks.NewMockReferralDiscountRewardService(ctrl) volumeDiscount := fmocks.NewMockVolumeDiscountService(ctrl) referralDiscountReward.EXPECT().GetReferrer(gomock.Any()).Return(types.PartyID(""), errors.New("no referrer")).AnyTimes() - referralDiscountReward.EXPECT().ReferralDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() - referralDiscountReward.EXPECT().RewardsFactorMultiplierAppliedForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() + referralDiscountReward.EXPECT().ReferralDiscountFactorsForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() + referralDiscountReward.EXPECT().RewardsFactorsMultiplierAppliedForParty(gomock.Any()).Return(types.EmptyFactors).AnyTimes() volumeDiscount.EXPECT().VolumeDiscountFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes() execBanking := emocks.NewMockBanking(ctrl) parties := emocks.NewMockParties(ctrl) diff --git a/core/governance/referral_program.go b/core/governance/referral_program.go index 81812c72011..5685a5ed020 100644 --- a/core/governance/referral_program.go +++ b/core/governance/referral_program.go @@ -39,11 +39,23 @@ func validateUpdateReferralProgram(netp NetParams, p *types.UpdateReferralProgra maxRewardFactor, _ := netp.GetDecimal(netparams.ReferralProgramMaxReferralRewardFactor) maxDiscountFactor, _ := netp.GetDecimal(netparams.ReferralProgramMaxReferralDiscountFactor) for i, tier := range p.Changes.BenefitTiers { - if tier.ReferralRewardFactor.GreaterThan(maxRewardFactor) { - return types.ProposalErrorInvalidReferralProgram, fmt.Errorf("tier %d defines a referral reward factor higher than the maximum allowed by the network parameter %q: maximum is %s, but got %s", i+1, netparams.ReferralProgramMaxReferralRewardFactor, maxRewardFactor.String(), tier.ReferralRewardFactor.String()) + if tier.ReferralRewardFactors.Infra.GreaterThan(maxRewardFactor) { + return types.ProposalErrorInvalidReferralProgram, fmt.Errorf("tier %d defines a referral reward infrastructure factor higher than the maximum allowed by the network parameter %q: maximum is %s, but got %s", i+1, netparams.ReferralProgramMaxReferralRewardFactor, maxRewardFactor.String(), tier.ReferralRewardFactors.Infra.String()) } - if tier.ReferralDiscountFactor.GreaterThan(maxDiscountFactor) { - return types.ProposalErrorInvalidReferralProgram, fmt.Errorf("tier %d defines a referral discount factor higher than the maximum allowed by the network parameter %q: maximum is %s, but got %s", i+1, netparams.ReferralProgramMaxReferralDiscountFactor, maxDiscountFactor.String(), tier.ReferralDiscountFactor.String()) + if tier.ReferralRewardFactors.Maker.GreaterThan(maxRewardFactor) { + return types.ProposalErrorInvalidReferralProgram, fmt.Errorf("tier %d defines a referral reward maker factor higher than the maximum allowed by the network parameter %q: maximum is %s, but got %s", i+1, netparams.ReferralProgramMaxReferralRewardFactor, maxRewardFactor.String(), tier.ReferralRewardFactors.Maker.String()) + } + if tier.ReferralRewardFactors.Liquidity.GreaterThan(maxRewardFactor) { + return types.ProposalErrorInvalidReferralProgram, fmt.Errorf("tier %d defines a referral reward liquidity factor higher than the maximum allowed by the network parameter %q: maximum is %s, but got %s", i+1, netparams.ReferralProgramMaxReferralRewardFactor, maxRewardFactor.String(), tier.ReferralRewardFactors.Liquidity.String()) + } + if tier.ReferralDiscountFactors.Infra.GreaterThan(maxDiscountFactor) { + return types.ProposalErrorInvalidReferralProgram, fmt.Errorf("tier %d defines a referral discount infrastructure factor higher than the maximum allowed by the network parameter %q: maximum is %s, but got %s", i+1, netparams.ReferralProgramMaxReferralDiscountFactor, maxDiscountFactor.String(), tier.ReferralDiscountFactors.Infra.String()) + } + if tier.ReferralDiscountFactors.Maker.GreaterThan(maxDiscountFactor) { + return types.ProposalErrorInvalidReferralProgram, fmt.Errorf("tier %d defines a referral discount maker factor higher than the maximum allowed by the network parameter %q: maximum is %s, but got %s", i+1, netparams.ReferralProgramMaxReferralDiscountFactor, maxDiscountFactor.String(), tier.ReferralDiscountFactors.Maker.String()) + } + if tier.ReferralDiscountFactors.Liquidity.GreaterThan(maxDiscountFactor) { + return types.ProposalErrorInvalidReferralProgram, fmt.Errorf("tier %d defines a referral discount liquidity factor higher than the maximum allowed by the network parameter %q: maximum is %s, but got %s", i+1, netparams.ReferralProgramMaxReferralDiscountFactor, maxDiscountFactor.String(), tier.ReferralDiscountFactors.Liquidity.String()) } } return types.ProposalErrorUnspecified, nil diff --git a/core/governance/volume_discount_program.go b/core/governance/volume_discount_program.go index b7359bff4d9..1c2465d5555 100644 --- a/core/governance/volume_discount_program.go +++ b/core/governance/volume_discount_program.go @@ -30,8 +30,14 @@ func validateUpdateVolumeDiscountProgram(netp NetParams, p *types.UpdateVolumeDi maxDiscountFactor, _ := netp.GetDecimal(netparams.VolumeDiscountProgramMaxVolumeDiscountFactor) for i, tier := range p.Changes.VolumeBenefitTiers { - if tier.VolumeDiscountFactor.GreaterThan(maxDiscountFactor) { - return types.ProposalErrorInvalidVolumeDiscountProgram, fmt.Errorf("tier %d defines a volume discount factor higher than the maximum allowed by the network parameter %q: maximum is %s, but got %s", i+1, netparams.VolumeDiscountProgramMaxVolumeDiscountFactor, maxDiscountFactor.String(), tier.VolumeDiscountFactor.String()) + if tier.VolumeDiscountFactors.Infra.GreaterThan(maxDiscountFactor) { + return types.ProposalErrorInvalidVolumeDiscountProgram, fmt.Errorf("tier %d defines a volume discount infrastructure factor higher than the maximum allowed by the network parameter %q: maximum is %s, but got %s", i+1, netparams.VolumeDiscountProgramMaxVolumeDiscountFactor, maxDiscountFactor.String(), tier.VolumeDiscountFactors.Infra.String()) + } + if tier.VolumeDiscountFactors.Maker.GreaterThan(maxDiscountFactor) { + return types.ProposalErrorInvalidVolumeDiscountProgram, fmt.Errorf("tier %d defines a volume discount maker factor higher than the maximum allowed by the network parameter %q: maximum is %s, but got %s", i+1, netparams.VolumeDiscountProgramMaxVolumeDiscountFactor, maxDiscountFactor.String(), tier.VolumeDiscountFactors.Maker.String()) + } + if tier.VolumeDiscountFactors.Liquidity.GreaterThan(maxDiscountFactor) { + return types.ProposalErrorInvalidVolumeDiscountProgram, fmt.Errorf("tier %d defines a volume discount liquidity factor higher than the maximum allowed by the network parameter %q: maximum is %s, but got %s", i+1, netparams.VolumeDiscountProgramMaxVolumeDiscountFactor, maxDiscountFactor.String(), tier.VolumeDiscountFactors.Liquidity.String()) } } return 0, nil diff --git a/core/integration/features/0084-VDPR-012.feature b/core/integration/features/0084-VDPR-012.feature index 2eebd9dcce1..a119e894ea6 100644 --- a/core/integration/features/0084-VDPR-012.feature +++ b/core/integration/features/0084-VDPR-012.feature @@ -25,10 +25,10 @@ Feature: At the start of an epoch, each parties volume_discount_factor is reeval #risk factor short:3.5569036 #risk factor long:0.801225765 And the volume discount program tiers named "VDP-01": - | volume | factor | - | 1000 | 0.001 | - | 2000 | 0.005 | - | 3000 | 0.010 | + | volume | infra factor | liquidity factor | maker factor | + | 1000 | 0.001 | 0.001 | 0.001 | + | 2000 | 0.005 | 0.005 | 0.005 | + | 3000 | 0.010 | 0.010 | 0.010 | And the volume discount program: | id | tiers | closing timestamp | window length | | id1 | VDP-01 | 0 | 4 | @@ -92,18 +92,18 @@ Feature: At the start of an epoch, each parties volume_discount_factor is reeval And the market data for the market "ETH/MAR24" should be: | mark price | trading mode | horizon | min bound | max bound | target stake | supplied stake | open interest | | 1000 | TRADING_MODE_CONTINUOUS | 3600 | 973 | 1027 | 3556 | 100000 | 1 | - And the party "party3" has the following discount factor "0" + And the party "party3" has the following discount infra factor "0" Then the parties place the following orders: | party | market id | side | volume | price | resulting trades | type | tif | | party3 | ETH/MAR24 | buy | 1 | 0 | 1 | TYPE_MARKET | TIF_IOC | | party3 | ETH/MAR24 | sell | 1 | 0 | 1 | TYPE_MARKET | TIF_IOC | When the network moves ahead "1" epochs - And the party "party3" has the following discount factor "0.005" + And the party "party3" has the following discount infra factor "0.005" Then the parties place the following orders: | party | market id | side | volume | price | resulting trades | type | tif | | party3 | ETH/MAR24 | buy | 20 | 0 | 1 | TYPE_MARKET | TIF_IOC | | party3 | ETH/MAR24 | sell | 20 | 0 | 1 | TYPE_MARKET | TIF_IOC | When the network moves ahead "1" epochs - And the party "party3" has the following discount factor "0.01" + And the party "party3" has the following discount infra factor "0.01" diff --git a/core/integration/features/0084-VDPR-013.feature b/core/integration/features/0084-VDPR-013.feature index e9e4ca4f88d..bfe487aae0a 100644 --- a/core/integration/features/0084-VDPR-013.feature +++ b/core/integration/features/0084-VDPR-013.feature @@ -26,10 +26,10 @@ Feature: A parties volume_discount_factor is set equal to the factors in the hig #risk factor short:3.5569036 #risk factor long:0.801225765 And the volume discount program tiers named "VDP-01": - | volume | factor | - | 1000 | 0.01 | - | 2000 | 0.02 | - | 3000 | 0.03 | + | volume | infra factor | liquidity factor | maker factor | + | 1000 | 0.01 | 0.01 | 0.01 | + | 2000 | 0.02 | 0.02 | 0.02 | + | 3000 | 0.03 | 0.03 | 0.03 | And the volume discount program: | id | tiers | closing timestamp | window length | | id1 | VDP-01 | 0 | 4 | @@ -95,7 +95,7 @@ Feature: A parties volume_discount_factor is set equal to the factors in the hig | mark price | trading mode | horizon | min bound | max bound | target stake | supplied stake | open interest | | 1000 | TRADING_MODE_CONTINUOUS | 3600 | 973 | 1027 | 3556 | 100000 | 1 | And the party "party3" has the following taker notional "0" - And the party "party3" has the following discount factor "0" + And the party "party3" has the following discount infra factor "0" Then the parties place the following orders: | party | market id | side | volume | price | resulting trades | type | tif | @@ -103,7 +103,7 @@ Feature: A parties volume_discount_factor is set equal to the factors in the hig | party3 | ETH/MAR24 | sell | 1 | 0 | 1 | TYPE_MARKET | TIF_IOC | When the network moves ahead "1" epochs And the party "party3" has the following taker notional "2000" - And the party "party3" has the following discount factor "0.02" + And the party "party3" has the following discount infra factor "0.02" Then the parties place the following orders: | party | market id | side | volume | price | resulting trades | type | tif | @@ -111,7 +111,7 @@ Feature: A parties volume_discount_factor is set equal to the factors in the hig | party3 | ETH/MAR24 | sell | 1 | 0 | 1 | TYPE_MARKET | TIF_IOC | When the network moves ahead "1" epochs And the party "party3" has the following taker notional "4000" - And the party "party3" has the following discount factor "0.03" + And the party "party3" has the following discount infra factor "0.03" # now that party3 has a discount, lets do a trade with fees # Volume discount rewards are correctly calculated and transferred for each taker fee component during continuous trading. (0029-FEES-027) @@ -134,7 +134,7 @@ Feature: A parties volume_discount_factor is set equal to the factors in the hig And the network moves ahead "1" epochs And the trading mode should be "TRADING_MODE_CONTINUOUS" for the market "ETH/MAR24" - And the party "party3" has the following discount factor "0.03" + And the party "party3" has the following discount infra factor "0.03" Given the parties place the following orders: | party | market id | side | volume | price | resulting trades | type | tif | diff --git a/core/integration/features/0084-VDPR-014.feature b/core/integration/features/0084-VDPR-014.feature index 08263740bbc..c2ce57515f6 100644 --- a/core/integration/features/0084-VDPR-014.feature +++ b/core/integration/features/0084-VDPR-014.feature @@ -23,10 +23,10 @@ Feature: If a party does not qualify for the lowest tier, their volume_discount_ #risk factor short:3.5569036 #risk factor long:0.801225765 And the volume discount program tiers named "VDP-01": - | volume | factor | - | 3000 | 0.01 | - | 4000 | 0.02 | - | 5000 | 0.03 | + | volume | infra factor | liquidity factor | maker factor | + | 3000 | 0.01 | 0.01 | 0.01 | + | 4000 | 0.02 | 0.02 | 0.02 | + | 5000 | 0.03 | 0.03 | 0.03 | And the volume discount program: | id | tiers | closing timestamp | window length | | id1 | VDP-01 | 0 | 4 | @@ -91,7 +91,7 @@ Feature: If a party does not qualify for the lowest tier, their volume_discount_ | mark price | trading mode | horizon | min bound | max bound | target stake | supplied stake | open interest | | 1000 | TRADING_MODE_CONTINUOUS | 3600 | 973 | 1027 | 3556 | 100000 | 1 | And the party "party3" has the following taker notional "0" - And the party "party3" has the following discount factor "0" + And the party "party3" has the following discount infra factor "0" Then the parties place the following orders: | party | market id | side | volume | price | resulting trades | type | tif | @@ -104,4 +104,4 @@ Feature: If a party does not qualify for the lowest tier, their volume_discount_ # The taker trades above are not enough for party3 to hit the first level of the discount tier # so we get a zero for the discount factor And the party "party3" has the following taker notional "2000" - And the party "party3" has the following discount factor "0" + And the party "party3" has the following discount infra factor "0" diff --git a/core/integration/features/referrals/0083-RFPR-benefit_factors.feature b/core/integration/features/referrals/0083-RFPR-benefit_factors.feature index 5b9a65cb655..6dae3544f89 100644 --- a/core/integration/features/referrals/0083-RFPR-benefit_factors.feature +++ b/core/integration/features/referrals/0083-RFPR-benefit_factors.feature @@ -28,9 +28,9 @@ Feature: Setting and applying referee benefit factors # Initalise the referral program then move forwards an epoch to start the program Given the referral benefit tiers "rbt": - | minimum running notional taker volume | minimum epochs | referral reward factor | referral discount factor | - | 2000 | 2 | 0.02 | 0.02 | - | 3000 | 3 | 0.20 | 0.20 | + | minimum running notional taker volume | minimum epochs | referral reward infra factor | referral reward maker factor | referral reward liquidity factor | referral discount infra factor | referral discount maker factor | referral discount liquidity factor | + | 2000 | 2 | 0.02 | 0.02 | 0.02 | 0.02 | 0.02 | 0.02 | + | 3000 | 3 | 0.20 | 0.20 | 0.20 | 0.20 | 0.20 | 0.20 | And the referral staking tiers "rst": | minimum staked tokens | referral reward multiplier | | 1 | 1 | @@ -125,8 +125,8 @@ Feature: Setting and applying referee benefit factors | referee1 | ETH/USD.1.1 | sell | | 1000 | 1 | TYPE_LIMIT | TIF_GTC | When the network moves ahead