diff --git a/CHANGELOG.md b/CHANGELOG.md
index 07f6a415804..7c1612f9ab2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,6 +24,8 @@
### 🛠 Improvements
- [11466](https://github.com/vegaprotocol/vega/issues/11466) - Update CometBFT to version `0.38.10`.
+- [11428](https://github.com/vegaprotocol/vega/issues/11428) - Add buy back and treasury fee and separate discount/reward factors.
+- [11468](https://github.com/vegaprotocol/vega/issues/11468) - Added support for volume rebate program.
### 🐛 Fixes
diff --git a/cmd/data-node/commands/start/sqlsubscribers.go b/cmd/data-node/commands/start/sqlsubscribers.go
index f381571e78a..87903ce48a6 100644
--- a/cmd/data-node/commands/start/sqlsubscribers.go
+++ b/cmd/data-node/commands/start/sqlsubscribers.go
@@ -84,6 +84,8 @@ type SQLSubscribers struct {
timeWeightedNotionalPositionStore *sqlstore.TimeWeightedNotionalPosition
gameScoreStore *sqlstore.GameScores
ammPoolsStore *sqlstore.AMMPools
+ volumeRebateStatsStore *sqlstore.VolumeRebateStats
+ volumeRebateProgramsStore *sqlstore.VolumeRebatePrograms
// Services
candleService *candlesv2.Svc
@@ -142,6 +144,8 @@ type SQLSubscribers struct {
timeWeightedNotionalPositionService *service.TimeWeightedNotionalPosition
gameScoreService *service.GameScore
ammPoolsService *service.AMMPools
+ volumeRebateStatsService *service.VolumeRebateStats
+ volumeRebateProgramService *service.VolumeRebatePrograms
// Subscribers
accountSub *sqlsubscribers.Account
@@ -196,6 +200,8 @@ type SQLSubscribers struct {
timeWeightedNotionalPositionSub *sqlsubscribers.TimeWeightedNotionalPosition
gameScoreSub *sqlsubscribers.GameScore
ammPoolsSub *sqlsubscribers.AMMPools
+ volumeRebateStatsSub *sqlsubscribers.VolumeRebateStatsUpdated
+ volumeRebateProgramSub *sqlsubscribers.VolumeRebateProgram
}
func (s *SQLSubscribers) GetSQLSubscribers() []broker.SQLBrokerSubscriber {
@@ -254,6 +260,8 @@ func (s *SQLSubscribers) GetSQLSubscribers() []broker.SQLBrokerSubscriber {
s.timeWeightedNotionalPositionSub,
s.gameScoreSub,
s.ammPoolsSub,
+ s.volumeRebateProgramSub,
+ s.volumeRebateStatsSub,
}
}
@@ -317,6 +325,8 @@ func (s *SQLSubscribers) CreateAllStores(ctx context.Context, Log *logging.Logge
s.timeWeightedNotionalPositionStore = sqlstore.NewTimeWeightedNotionalPosition(transactionalConnectionSource)
s.gameScoreStore = sqlstore.NewGameScores(transactionalConnectionSource)
s.ammPoolsStore = sqlstore.NewAMMPools(transactionalConnectionSource)
+ s.volumeRebateStatsStore = sqlstore.NewVolumeRebateStats(transactionalConnectionSource)
+ s.volumeRebateProgramsStore = sqlstore.NewVolumeRebatePrograms(transactionalConnectionSource)
}
func (s *SQLSubscribers) SetupServices(ctx context.Context, log *logging.Logger, cfg service.Config, candlesConfig candlesv2.Config) error {
@@ -374,6 +384,8 @@ func (s *SQLSubscribers) SetupServices(ctx context.Context, log *logging.Logger,
s.timeWeightedNotionalPositionService = service.NewTimeWeightedNotionalPosition(s.timeWeightedNotionalPositionStore)
s.gameScoreService = service.NewGameScore(s.gameScoreStore, log)
s.ammPoolsService = service.NewAMMPools(s.ammPoolsStore)
+ s.volumeRebateStatsService = service.NewVolumeRebateStats(s.volumeRebateStatsStore)
+ s.volumeRebateProgramService = service.NewVolumeRebatePrograms(s.volumeRebateProgramsStore)
s.marketDepthService = service.NewMarketDepth(
cfg.MarketDepth,
@@ -455,5 +467,7 @@ func (s *SQLSubscribers) SetupSQLSubscribers() {
s.marginModesSub = sqlsubscribers.NewMarginModes(s.marginModesService)
s.timeWeightedNotionalPositionSub = sqlsubscribers.NewTimeWeightedNotionalPosition(s.timeWeightedNotionalPositionService)
s.gameScoreSub = sqlsubscribers.NewGameScore(s.gameScoreStore)
+ s.volumeRebateStatsSub = sqlsubscribers.NewVolumeRebateStatsUpdated(s.volumeRebateStatsService)
+ s.volumeRebateProgramSub = sqlsubscribers.NewVolumeRebateProgram(s.volumeRebateProgramService)
s.ammPoolsSub = sqlsubscribers.NewAMMPools(s.ammPoolsService, s.marketDepthService)
}
diff --git a/commands/proposal_submission.go b/commands/proposal_submission.go
index 1e6b2d8c8fa..fba99cb8389 100644
--- a/commands/proposal_submission.go
+++ b/commands/proposal_submission.go
@@ -454,14 +454,26 @@ func checkVolumeBenefitTier(index int, tier *vegapb.VolumeBenefitTier) Errors {
errs.AddForProperty(propertyPath+".minimum_running_notional_taker_volume", ErrMustBePositive)
}
}
- if len(tier.VolumeDiscountFactor) == 0 {
- errs.AddForProperty(propertyPath+".volume_discount_factor", ErrIsRequired)
+ if tier.VolumeDiscountFactors == nil {
+ errs.AddForProperty(propertyPath+".volume_discount_factors", ErrIsRequired)
} else {
- rdf, err := num.DecimalFromString(tier.VolumeDiscountFactor)
+ rdf, err := num.DecimalFromString(tier.VolumeDiscountFactors.MakerDiscountFactor)
if err != nil {
- errs.AddForProperty(propertyPath+".volume_discount_factor", ErrIsNotValidNumber)
+ errs.AddForProperty(propertyPath+".volume_discount_factors.maker_discount_factor", ErrIsNotValidNumber)
} else if rdf.IsNegative() {
- errs.AddForProperty(propertyPath+".volume_discount_factor", ErrMustBePositiveOrZero)
+ errs.AddForProperty(propertyPath+".volume_discount_factors.maker_discount_factor", ErrMustBePositiveOrZero)
+ }
+ rdf, err = num.DecimalFromString(tier.VolumeDiscountFactors.LiquidityDiscountFactor)
+ if err != nil {
+ errs.AddForProperty(propertyPath+".volume_discount_factors.liquidity_discount_factor", ErrIsNotValidNumber)
+ } else if rdf.IsNegative() {
+ errs.AddForProperty(propertyPath+".volume_discount_factors.liquidity_discount_factor", ErrMustBePositiveOrZero)
+ }
+ rdf, err = num.DecimalFromString(tier.VolumeDiscountFactors.InfrastructureDiscountFactor)
+ if err != nil {
+ errs.AddForProperty(propertyPath+".volume_discount_factors.infrastructure_discount_factor", ErrIsNotValidNumber)
+ } else if rdf.IsNegative() {
+ errs.AddForProperty(propertyPath+".volume_discount_factors.infrastructure_discount_factor", ErrMustBePositiveOrZero)
}
}
return errs
@@ -494,25 +506,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/commands/proposal_submission_update_volume_discount_program_test.go b/commands/proposal_submission_update_volume_discount_program_test.go
index b5107d318a0..9278e3fe0d0 100644
--- a/commands/proposal_submission_update_volume_discount_program_test.go
+++ b/commands/proposal_submission_update_volume_discount_program_test.go
@@ -220,11 +220,7 @@ func testSubmissionForVolumeDiscountProgramUpdateWithoutTierVolumeDiscountFactor
UpdateVolumeDiscountProgram: &types.UpdateVolumeDiscountProgram{
Changes: &types.VolumeDiscountProgramChanges{
BenefitTiers: []*types.VolumeBenefitTier{
- {
- VolumeDiscountFactor: "",
- }, {
- VolumeDiscountFactor: "",
- },
+ {}, {},
},
},
},
@@ -232,8 +228,8 @@ func testSubmissionForVolumeDiscountProgramUpdateWithoutTierVolumeDiscountFactor
},
})
- assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.0.volume_discount_factor"), commands.ErrIsRequired)
- assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.1.volume_discount_factor"), commands.ErrIsRequired)
+ assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.0.volume_discount_factors"), commands.ErrIsRequired)
+ assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.1.volume_discount_factors"), commands.ErrIsRequired)
}
func testSubmissionForVolumeDiscountProgramUpdateWithBadFormatForTierVolumeDiscountFactorFails(t *testing.T) {
@@ -244,9 +240,17 @@ func testSubmissionForVolumeDiscountProgramUpdateWithBadFormatForTierVolumeDisco
Changes: &types.VolumeDiscountProgramChanges{
BenefitTiers: []*types.VolumeBenefitTier{
{
- VolumeDiscountFactor: "qbc",
+ VolumeDiscountFactors: &types.DiscountFactors{
+ InfrastructureDiscountFactor: "qbc",
+ LiquidityDiscountFactor: "qbc",
+ MakerDiscountFactor: "qbc",
+ },
}, {
- VolumeDiscountFactor: "0x32",
+ VolumeDiscountFactors: &types.DiscountFactors{
+ InfrastructureDiscountFactor: "0x32",
+ LiquidityDiscountFactor: "0x32",
+ MakerDiscountFactor: "0x32",
+ },
},
},
},
@@ -255,8 +259,12 @@ func testSubmissionForVolumeDiscountProgramUpdateWithBadFormatForTierVolumeDisco
},
})
- assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.0.volume_discount_factor"), commands.ErrIsNotValidNumber)
- assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.1.volume_discount_factor"), commands.ErrIsNotValidNumber)
+ assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.0.volume_discount_factors.maker_discount_factor"), commands.ErrIsNotValidNumber)
+ assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.0.volume_discount_factors.liquidity_discount_factor"), commands.ErrIsNotValidNumber)
+ assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.0.volume_discount_factors.infrastructure_discount_factor"), commands.ErrIsNotValidNumber)
+ assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.1.volume_discount_factors.maker_discount_factor"), commands.ErrIsNotValidNumber)
+ assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.1.volume_discount_factors.liquidity_discount_factor"), commands.ErrIsNotValidNumber)
+ assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.1.volume_discount_factors.infrastructure_discount_factor"), commands.ErrIsNotValidNumber)
}
func testSubmissionForVolumeDiscountProgramUpdateWithBadValueForTierVolumeDiscountFactorFails(t *testing.T) {
@@ -267,9 +275,17 @@ func testSubmissionForVolumeDiscountProgramUpdateWithBadValueForTierVolumeDiscou
Changes: &types.VolumeDiscountProgramChanges{
BenefitTiers: []*types.VolumeBenefitTier{
{
- VolumeDiscountFactor: "-10",
+ VolumeDiscountFactors: &types.DiscountFactors{
+ InfrastructureDiscountFactor: "-10",
+ LiquidityDiscountFactor: "-5",
+ MakerDiscountFactor: "-7",
+ },
}, {
- VolumeDiscountFactor: "-1",
+ VolumeDiscountFactors: &types.DiscountFactors{
+ InfrastructureDiscountFactor: "-1",
+ LiquidityDiscountFactor: "-3",
+ MakerDiscountFactor: "-9",
+ },
},
},
},
@@ -278,6 +294,10 @@ func testSubmissionForVolumeDiscountProgramUpdateWithBadValueForTierVolumeDiscou
},
})
- assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.0.volume_discount_factor"), commands.ErrMustBePositiveOrZero)
- assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.1.volume_discount_factor"), commands.ErrMustBePositiveOrZero)
+ assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.0.volume_discount_factors.maker_discount_factor"), commands.ErrMustBePositiveOrZero)
+ assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.0.volume_discount_factors.liquidity_discount_factor"), commands.ErrMustBePositiveOrZero)
+ assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.0.volume_discount_factors.infrastructure_discount_factor"), commands.ErrMustBePositiveOrZero)
+ assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.0.volume_discount_factors.maker_discount_factor"), commands.ErrMustBePositiveOrZero)
+ assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.0.volume_discount_factors.liquidity_discount_factor"), commands.ErrMustBePositiveOrZero)
+ assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_discount_program.changes.benefit_tiers.0.volume_discount_factors.infrastructure_discount_factor"), commands.ErrMustBePositiveOrZero)
}
diff --git a/core/collateral/engine.go b/core/collateral/engine.go
index 39640306389..bb245e10d92 100644
--- a/core/collateral/engine.go
+++ b/core/collateral/engine.go
@@ -732,7 +732,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))
@@ -763,6 +763,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,
@@ -795,6 +796,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(),
@@ -814,6 +822,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
@@ -836,6 +858,17 @@ func (e *Engine) getSpotFeeTransferRequest(
treq.FromAccount = []*types.Account{makerFee}
treq.ToAccount = []*types.Account{general}
return treq, nil
+ case types.TransferTypeHighMakerRebateReceive:
+ treq.FromAccount = []*types.Account{makerFee}
+ treq.ToAccount = []*types.Account{general}
+ return treq, nil
+ case types.TransferTypeHighMakerRebatePay:
+ amt := num.Min(treq.Amount, general.Balance.Clone())
+ treq.Amount = amt
+ treq.MinAmount = amt
+ treq.FromAccount = []*types.Account{general}
+ treq.ToAccount = []*types.Account{makerFee}
+ return treq, nil
case types.TransferTypeLiquidityFeeAllocate:
partyLiquidityFee, err := partyLiquidityFeeAccount()
if err != nil {
@@ -2234,6 +2267,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 {
@@ -2295,6 +2334,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}
@@ -2326,6 +2387,21 @@ func (e *Engine) getFeeTransferRequest(
case types.TransferTypeMakerFeeReceive:
treq.FromAccount = []*types.Account{makerFee}
treq.ToAccount = []*types.Account{general}
+ case types.TransferTypeHighMakerRebatePay:
+ 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{makerFee}
+ case types.TransferTypeHighMakerRebateReceive:
+ treq.FromAccount = []*types.Account{makerFee}
+ treq.ToAccount = []*types.Account{general}
+ return treq, nil
case types.TransferTypeLiquidityFeeAllocate:
partyLiquidityFee, err := partyLiquidityFeeAccount()
if err != nil {
@@ -4594,6 +4670,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/bus.go b/core/events/bus.go
index bc21bac0741..3fa9e0f6c05 100644
--- a/core/events/bus.go
+++ b/core/events/bus.go
@@ -174,6 +174,10 @@ const (
CancelledOrdersEvent
GameScoresEvent
AMMPoolEvent
+ VolumeRebateProgramStartedEvent
+ VolumeRebateProgramEndedEvent
+ VolumeRebateProgramUpdatedEvent
+ VolumeRebateStatsUpdatedEvent
)
var (
@@ -277,6 +281,10 @@ var (
eventspb.BusEventType_BUS_EVENT_TYPE_CANCELLED_ORDERS: CancelledOrdersEvent,
eventspb.BusEventType_BUS_EVENT_TYPE_GAME_SCORES: GameScoresEvent,
eventspb.BusEventType_BUS_EVENT_TYPE_AMM: AMMPoolEvent,
+ eventspb.BusEventType_BUS_EVENT_TYPE_VOLUME_REBATE_PROGRAM_STARTED: VolumeRebateProgramStartedEvent,
+ eventspb.BusEventType_BUS_EVENT_TYPE_VOLUME_REBATE_PROGRAM_ENDED: VolumeRebateProgramEndedEvent,
+ eventspb.BusEventType_BUS_EVENT_TYPE_VOLUME_REBATE_PROGRAM_UPDATED: VolumeRebateProgramUpdatedEvent,
+ eventspb.BusEventType_BUS_EVENT_TYPE_VOLUME_REBATE_STATS_UPDATED: VolumeRebateStatsUpdatedEvent,
// If adding a type here, please also add it to datanode/broker/convert.go
}
@@ -371,6 +379,11 @@ var (
CancelledOrdersEvent: eventspb.BusEventType_BUS_EVENT_TYPE_CANCELLED_ORDERS,
GameScoresEvent: eventspb.BusEventType_BUS_EVENT_TYPE_GAME_SCORES,
AMMPoolEvent: eventspb.BusEventType_BUS_EVENT_TYPE_AMM,
+ VolumeRebateProgramStartedEvent: eventspb.BusEventType_BUS_EVENT_TYPE_VOLUME_REBATE_PROGRAM_STARTED,
+ VolumeRebateProgramEndedEvent: eventspb.BusEventType_BUS_EVENT_TYPE_VOLUME_REBATE_PROGRAM_ENDED,
+ VolumeRebateProgramUpdatedEvent: eventspb.BusEventType_BUS_EVENT_TYPE_VOLUME_REBATE_PROGRAM_UPDATED,
+ VolumeRebateStatsUpdatedEvent: eventspb.BusEventType_BUS_EVENT_TYPE_VOLUME_REBATE_STATS_UPDATED,
+
// If adding a type here, please also add it to datanode/broker/convert.go
}
@@ -464,6 +477,10 @@ var (
CancelledOrdersEvent: "CancelledOrdersEvent",
GameScoresEvent: "GameScoresEvent",
AMMPoolEvent: "AMMPoolEvent",
+ VolumeRebateProgramStartedEvent: "VolumeRebateProgramStartedEvent",
+ VolumeRebateProgramEndedEvent: "VolumeRebateProgramEndedEvent",
+ VolumeRebateProgramUpdatedEvent: "VolumeRebateProgramUpdatedEvent",
+ VolumeRebateStatsUpdatedEvent: "VolumeRebateStatsUpdatedEvent",
}
)
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/events/volume_rebate_program.go b/core/events/volume_rebate_program.go
new file mode 100644
index 00000000000..1ff9f86663a
--- /dev/null
+++ b/core/events/volume_rebate_program.go
@@ -0,0 +1,172 @@
+// Copyright (C) 2023 Gobalsky Labs Limited
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package events
+
+import (
+ "context"
+ "time"
+
+ "code.vegaprotocol.io/vega/core/types"
+ "code.vegaprotocol.io/vega/libs/ptr"
+ eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1"
+)
+
+type VolumeRebateProgramStarted struct {
+ *Base
+ e *eventspb.VolumeRebateProgramStarted
+}
+
+func (v *VolumeRebateProgramStarted) GetVolumeRebateProgramStarted() *eventspb.VolumeRebateProgramStarted {
+ return v.e
+}
+
+func (t *VolumeRebateProgramStarted) StreamMessage() *eventspb.BusEvent {
+ busEvent := newBusEventFromBase(t.Base)
+ busEvent.Event = &eventspb.BusEvent_VolumeRebateProgramStarted{
+ VolumeRebateProgramStarted: t.e,
+ }
+
+ return busEvent
+}
+
+func NewVolumeRebateProgramStartedEvent(ctx context.Context, p *types.VolumeRebateProgram, epochTime time.Time, epoch uint64) *VolumeRebateProgramStarted {
+ return &VolumeRebateProgramStarted{
+ Base: newBase(ctx, VolumeRebateProgramStartedEvent),
+ e: &eventspb.VolumeRebateProgramStarted{
+ Program: p.IntoProto(),
+ StartedAt: epochTime.UnixNano(),
+ AtEpoch: epoch,
+ },
+ }
+}
+
+func VolumeRebateProgramStartedEventFromStream(ctx context.Context, be *eventspb.BusEvent) *VolumeRebateProgramStarted {
+ return &VolumeRebateProgramStarted{
+ Base: newBaseFromBusEvent(ctx, VolumeRebateProgramStartedEvent, be),
+ e: be.GetVolumeRebateProgramStarted(),
+ }
+}
+
+type VolumeRebateProgramUpdated struct {
+ *Base
+ e *eventspb.VolumeRebateProgramUpdated
+}
+
+func (v *VolumeRebateProgramUpdated) GetVolumeRebateProgramUpdated() *eventspb.VolumeRebateProgramUpdated {
+ return v.e
+}
+
+func (t *VolumeRebateProgramUpdated) StreamMessage() *eventspb.BusEvent {
+ busEvent := newBusEventFromBase(t.Base)
+ busEvent.Event = &eventspb.BusEvent_VolumeRebateProgramUpdated{
+ VolumeRebateProgramUpdated: t.e,
+ }
+
+ return busEvent
+}
+
+func NewVolumeRebateProgramUpdatedEvent(ctx context.Context, p *types.VolumeRebateProgram, epochTime time.Time, epoch uint64) *VolumeRebateProgramUpdated {
+ return &VolumeRebateProgramUpdated{
+ Base: newBase(ctx, VolumeRebateProgramUpdatedEvent),
+ e: &eventspb.VolumeRebateProgramUpdated{
+ Program: p.IntoProto(),
+ UpdatedAt: epochTime.UnixNano(),
+ AtEpoch: epoch,
+ },
+ }
+}
+
+func VolumeRebateProgramUpdatedEventFromStream(ctx context.Context, be *eventspb.BusEvent) *VolumeRebateProgramUpdated {
+ return &VolumeRebateProgramUpdated{
+ Base: newBaseFromBusEvent(ctx, VolumeRebateProgramUpdatedEvent, be),
+ e: be.GetVolumeRebateProgramUpdated(),
+ }
+}
+
+type VolumeRebateProgramEnded struct {
+ *Base
+ e *eventspb.VolumeRebateProgramEnded
+}
+
+func (v *VolumeRebateProgramEnded) GetVolumeRebateProgramEnded() *eventspb.VolumeRebateProgramEnded {
+ return v.e
+}
+
+func (t *VolumeRebateProgramEnded) StreamMessage() *eventspb.BusEvent {
+ busEvent := newBusEventFromBase(t.Base)
+ busEvent.Event = &eventspb.BusEvent_VolumeRebateProgramEnded{
+ VolumeRebateProgramEnded: t.e,
+ }
+
+ return busEvent
+}
+
+func NewVolumeRebateProgramEndedEvent(ctx context.Context, version uint64, id string, epochTime time.Time, epoch uint64) *VolumeRebateProgramEnded {
+ return &VolumeRebateProgramEnded{
+ Base: newBase(ctx, VolumeRebateProgramEndedEvent),
+ e: &eventspb.VolumeRebateProgramEnded{
+ Version: version,
+ Id: id,
+ EndedAt: epochTime.UnixNano(),
+ AtEpoch: epoch,
+ },
+ }
+}
+
+func VolumeRebateProgramEndedEventFromStream(ctx context.Context, be *eventspb.BusEvent) *VolumeRebateProgramEnded {
+ return &VolumeRebateProgramEnded{
+ Base: newBaseFromBusEvent(ctx, VolumeRebateProgramEndedEvent, be),
+ e: be.GetVolumeRebateProgramEnded(),
+ }
+}
+
+type VolumeRebateStatsUpdated struct {
+ *Base
+ vdsu eventspb.VolumeRebateStatsUpdated
+}
+
+func NewVolumeRebateStatsUpdatedEvent(ctx context.Context, vdsu *eventspb.VolumeRebateStatsUpdated) *VolumeRebateStatsUpdated {
+ order := &VolumeRebateStatsUpdated{
+ Base: newBase(ctx, VolumeRebateStatsUpdatedEvent),
+ vdsu: *vdsu,
+ }
+ return order
+}
+
+func (p *VolumeRebateStatsUpdated) VolumeRebateStatsUpdated() *eventspb.VolumeRebateStatsUpdated {
+ return ptr.From(p.vdsu)
+}
+
+func (p VolumeRebateStatsUpdated) Proto() eventspb.VolumeRebateStatsUpdated {
+ return p.vdsu
+}
+
+func (p VolumeRebateStatsUpdated) StreamMessage() *eventspb.BusEvent {
+ busEvent := newBusEventFromBase(p.Base)
+ busEvent.Event = &eventspb.BusEvent_VolumeRebateStatsUpdated{
+ VolumeRebateStatsUpdated: ptr.From(p.vdsu),
+ }
+
+ return busEvent
+}
+
+func VolumeRebateStatsUpdatedEventFromStream(ctx context.Context, be *eventspb.BusEvent) *VolumeRebateStatsUpdated {
+ order := &VolumeRebateStatsUpdated{
+ Base: newBaseFromBusEvent(ctx, VolumeRebateStatsUpdatedEvent, be),
+ vdsu: ptr.UnBox(be.GetVolumeRebateStatsUpdated()),
+ }
+ return order
+}
diff --git a/core/execution/amm/engine_test.go b/core/execution/amm/engine_test.go
index a2f0095d3d2..55f06037c2d 100644
--- a/core/execution/amm/engine_test.go
+++ b/core/execution/amm/engine_test.go
@@ -725,7 +725,7 @@ func getTestEngine(t *testing.T) *tstEngine {
teams := cmocks.NewMockTeams(ctrl)
balanceChecker := cmocks.NewMockAccountBalanceChecker(ctrl)
- mat := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ mat := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, col)
parties := cmocks.NewMockParties(ctrl)
parties.EXPECT().AssignDeriveKey(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
diff --git a/core/execution/common/interfaces.go b/core/execution/common/interfaces.go
index 7ac1b714e3a..a5ecf247111 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/liquidity_provision_test.go b/core/execution/common/liquidity_provision_test.go
index 779311dfc72..2349dfa782c 100644
--- a/core/execution/common/liquidity_provision_test.go
+++ b/core/execution/common/liquidity_provision_test.go
@@ -83,7 +83,7 @@ func newMarketLiquidity(t *testing.T) *marketLiquidityTest {
teams := mocks.NewMockTeams(ctrl)
bc := mocks.NewMockAccountBalanceChecker(ctrl)
- marketTracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, bc, broker)
+ marketTracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, bc, broker, collateralEngine)
epochEngine.NotifyOnEpoch(marketTracker.OnEpochEvent, marketTracker.OnEpochRestore)
amm := ammcmocks.NewMockAMM(ctrl)
diff --git a/core/execution/common/market_activity_tracker.go b/core/execution/common/market_activity_tracker.go
index c55337681de..6b78e97eaa5 100644
--- a/core/execution/common/market_activity_tracker.go
+++ b/core/execution/common/market_activity_tracker.go
@@ -47,6 +47,10 @@ var (
dScalingFactor = num.DecimalFromInt64(scalingFactor)
)
+type QuantumGetter interface {
+ GetAssetQuantum(asset string) (num.Decimal, error)
+}
+
type twPosition struct {
position uint64 // abs last recorded position
t time.Time // time of last recorded position
@@ -67,6 +71,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
@@ -105,6 +111,7 @@ type MarketActivityTracker struct {
teams Teams
balanceChecker AccountBalanceChecker
eligibilityChecker EligibilityChecker
+ collateral QuantumGetter
currentEpoch uint64
epochStartTime time.Time
@@ -120,7 +127,7 @@ type MarketActivityTracker struct {
}
// NewMarketActivityTracker instantiates the fees tracker.
-func NewMarketActivityTracker(log *logging.Logger, teams Teams, balanceChecker AccountBalanceChecker, broker Broker) *MarketActivityTracker {
+func NewMarketActivityTracker(log *logging.Logger, teams Teams, balanceChecker AccountBalanceChecker, broker Broker, collateral QuantumGetter) *MarketActivityTracker {
mat := &MarketActivityTracker{
log: log,
balanceChecker: balanceChecker,
@@ -132,6 +139,7 @@ func NewMarketActivityTracker(log *logging.Logger, teams Teams, balanceChecker A
ss: &snapshotState{},
takerFeesPaidInEpoch: []map[string]map[string]map[string]*num.Uint{},
broker: broker,
+ collateral: collateral,
}
return mat
@@ -187,6 +195,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 +477,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 {
@@ -517,6 +527,63 @@ func (mat *MarketActivityTracker) clearDeletedMarkets() {
}
}
+func (mat *MarketActivityTracker) CalculateTotalMakerContributionInQuantum(windowSize int) (map[string]*num.Uint, map[string]num.Decimal) {
+ m := map[string]*num.Uint{}
+ total := num.UintZero()
+ for ast, trackers := range mat.assetToMarketTrackers {
+ quantum, err := mat.collateral.GetAssetQuantum(ast)
+ if err != nil {
+ continue
+ }
+ for _, trckr := range trackers {
+ for i := 0; i < windowSize; i++ {
+ idx := len(trckr.epochMakerFeesReceived) - i - 1
+ if idx < 0 {
+ break
+ }
+ partyFees := trckr.epochMakerFeesReceived[len(trckr.epochMakerFeesReceived)-i-1]
+ for party, fees := range partyFees {
+ if _, ok := m[party]; !ok {
+ m[party] = num.UintZero()
+ }
+ feesInQunatum, overflow := num.UintFromDecimal(fees.ToDecimal().Div(quantum))
+ if overflow {
+ continue
+ }
+ m[party].AddSum(feesInQunatum)
+ total.AddSum(feesInQunatum)
+ }
+ }
+ }
+ }
+ if total.IsZero() {
+ return m, map[string]decimal.Decimal{}
+ }
+ totalFrac := num.DecimalZero()
+ fractions := []*types.PartyContributionScore{}
+ for p, f := range m {
+ frac := f.ToDecimal().Div(total.ToDecimal())
+ fractions = append(fractions, &types.PartyContributionScore{Party: p, Score: frac})
+ totalFrac = totalFrac.Add(frac)
+ }
+ capAtOne(fractions, totalFrac)
+ fracMap := make(map[string]num.Decimal, len(fractions))
+ for _, partyFraction := range fractions {
+ fracMap[partyFraction.Party] = partyFraction.Score
+ }
+ return m, fracMap
+}
+
+func capAtOne(partyFractions []*types.PartyContributionScore, total num.Decimal) {
+ if total.LessThanOrEqual(num.DecimalOne()) {
+ return
+ }
+
+ sort.SliceStable(partyFractions, func(i, j int) bool { return partyFractions[i].Score.GreaterThan(partyFractions[j].Score) })
+ delta := total.Sub(num.DecimalFromInt64(1))
+ partyFractions[0].Score = num.MaxD(num.DecimalZero(), partyFractions[0].Score.Sub(delta))
+}
+
func (mt *marketTracker) calcFeesAtMilestone() {
mt.epochMakerFeesReceived = append(mt.epochMakerFeesReceived, mt.makerFeesReceived)
mt.epochMakerFeesPaid = append(mt.epochMakerFeesPaid, mt.makerFeesPaid)
@@ -544,6 +611,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 +642,13 @@ 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())
+ case types.TransferTypeHighMakerRebateReceive:
+ // we count high maker fee receive as maker fees for that purpose.
+ mat.addFees(mt.makerFeesReceived, t.Owner, t.Amount.Amount, mt.totalMakerFeesReceived)
default:
}
}
diff --git a/core/execution/common/market_activity_tracker_internal_test.go b/core/execution/common/market_activity_tracker_internal_test.go
index f187eaac070..4fc13cedd9d 100644
--- a/core/execution/common/market_activity_tracker_internal_test.go
+++ b/core/execution/common/market_activity_tracker_internal_test.go
@@ -350,7 +350,8 @@ func TestCalculateMetricForIndividualsAvePosition(t *testing.T) {
broker := bmocks.NewMockBroker(ctrl)
broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
broker.EXPECT().Send(gomock.Any()).AnyTimes()
- tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&DummyEligibilityChecker{})
epochService.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Time{}})
@@ -552,7 +553,8 @@ func TestCalculateMetricForPartyAvePosition(t *testing.T) {
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
- tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&DummyEligibilityChecker{})
epochService.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Time{}})
@@ -790,7 +792,8 @@ func TestCalculateMetricForIndividualReturnVolatility(t *testing.T) {
broker := bmocks.NewMockBroker(ctrl)
broker.EXPECT().Send(gomock.Any()).AnyTimes()
broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
- tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&DummyEligibilityChecker{})
epochService.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Time{}})
@@ -996,7 +999,8 @@ func TestCalculateMetricForIndividualsRelativeReturn(t *testing.T) {
broker := bmocks.NewMockBroker(ctrl)
broker.EXPECT().Send(gomock.Any()).AnyTimes()
broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
- tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&DummyEligibilityChecker{})
epochService.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Time{}})
@@ -1217,7 +1221,8 @@ func TestCalculateMetricForPartyRelativeReturn(t *testing.T) {
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
- tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&DummyEligibilityChecker{})
epochService.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Time{}})
@@ -1474,7 +1479,8 @@ func TestCalculateMetricForParty(t *testing.T) {
teams := mocks.NewMockTeams(ctrl)
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
- tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&DummyEligibilityChecker{})
epochService.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Time{}})
@@ -1563,6 +1569,12 @@ func (e *DummyEpochEngine) NotifyOnEpoch(f func(context.Context, types.Epoch), _
e.target = f
}
+type DummyCollateralEngine struct{}
+
+func (e DummyCollateralEngine) GetAssetQuantum(asset string) (num.Decimal, error) {
+ return num.DecimalOne(), nil
+}
+
type DummyEligibilityChecker struct{}
func (e *DummyEligibilityChecker) IsEligibleForProposerBonus(marketID string, volumeTraded *num.Uint) bool {
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/common/market_activity_tracker_test.go b/core/execution/common/market_activity_tracker_test.go
index 61b677ace76..b40dc596318 100644
--- a/core/execution/common/market_activity_tracker_test.go
+++ b/core/execution/common/market_activity_tracker_test.go
@@ -62,7 +62,8 @@ func TestMarketTracker(t *testing.T) {
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
tracker.SetEligibilityChecker(&EligibilityChecker{})
tracker.MarketProposed("asset1", "market1", "me")
@@ -140,7 +141,7 @@ func TestMarketTracker(t *testing.T) {
teams2 := mocks.NewMockTeams(ctrl)
balanceChecker2 := mocks.NewMockAccountBalanceChecker(ctrl)
broker = bmocks.NewMockBroker(ctrl)
- trackerLoad := common.NewMarketActivityTracker(logging.NewTestLogger(), teams2, balanceChecker2, broker)
+ trackerLoad := common.NewMarketActivityTracker(logging.NewTestLogger(), teams2, balanceChecker2, broker, collateralService)
pl := snapshotpb.Payload{}
require.NoError(t, proto.Unmarshal(state1, &pl))
@@ -160,7 +161,8 @@ func TestRemoveMarket(t *testing.T) {
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&EligibilityChecker{})
tracker.MarketProposed("asset1", "market1", "me")
@@ -187,7 +189,8 @@ func TestAddRemoveAMM(t *testing.T) {
broker := bmocks.NewMockBroker(ctrl)
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&EligibilityChecker{})
tracker.MarketProposed("asset1", "market1", "me")
@@ -208,6 +211,105 @@ func TestAddRemoveAMM(t *testing.T) {
require.Equal(t, map[string]struct{}{}, tracker.GetAllAMMParties("asset1", nil))
}
+func TestCalculateTotalMakerContributionInQuantum(t *testing.T) {
+ // ctx := context.Background()
+ epochService := &TestEpochEngine{}
+ ctrl := gomock.NewController(t)
+ teams := mocks.NewMockTeams(ctrl)
+ balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
+ balanceChecker.EXPECT().GetAvailableBalance(gomock.Any()).Return(num.UintZero(), nil).AnyTimes()
+ broker := bmocks.NewMockBroker(ctrl)
+ broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
+ broker.EXPECT().Send(gomock.Any()).AnyTimes()
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
+ epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
+ tracker.SetEligibilityChecker(&EligibilityChecker{})
+ tracker.MarketProposed("asset1", "market1", "me")
+ tracker.MarketProposed("asset1", "market2", "me2")
+ tracker.MarketProposed("asset1", "market4", "me4")
+ tracker.MarketProposed("asset2", "market3", "me3")
+
+ collateralService.EXPECT().GetAssetQuantum("asset1").Return(num.DecimalOne(), nil).AnyTimes()
+ collateralService.EXPECT().GetAssetQuantum("asset2").Return(num.DecimalTwo(), nil).AnyTimes()
+ // no fees generated expect empty slice
+ epochService.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START})
+ epochService.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_END})
+
+ // expect no makers fee contributors
+ contribution, fraction := tracker.CalculateTotalMakerContributionInQuantum(1)
+ require.Equal(t, 0, len(fraction))
+ require.Equal(t, 0, len(contribution))
+
+ contribution, fraction = tracker.CalculateTotalMakerContributionInQuantum(2)
+ require.Equal(t, 0, len(fraction))
+ require.Equal(t, 0, len(contribution))
+
+ epochService.target(context.Background(), types.Epoch{Seq: 2, Action: vgproto.EpochAction_EPOCH_ACTION_START})
+
+ // now lets get some fees paid
+ // update with a few transfers
+ transfersM1 := []*types.Transfer{
+ {Owner: "party1", Type: types.TransferTypeMakerFeeReceive, Amount: &types.FinancialAmount{Asset: "asset1", Amount: num.NewUint(100)}},
+ {Owner: "party1", Type: types.TransferTypeMakerFeeReceive, Amount: &types.FinancialAmount{Asset: "asset1", Amount: num.NewUint(400)}},
+ {Owner: "party2", Type: types.TransferTypeMakerFeeReceive, Amount: &types.FinancialAmount{Asset: "asset1", Amount: num.NewUint(900)}},
+ {Owner: "party2", Type: types.TransferTypeMakerFeeReceive, Amount: &types.FinancialAmount{Asset: "asset1", Amount: num.NewUint(600)}},
+ }
+ tracker.UpdateFeesFromTransfers("asset1", "market1", transfersM1)
+
+ transfersM2 := []*types.Transfer{
+ {Owner: "party1", Type: types.TransferTypeMakerFeeReceive, Amount: &types.FinancialAmount{Asset: "asset1", Amount: num.NewUint(500)}},
+ }
+ tracker.UpdateFeesFromTransfers("asset1", "market2", transfersM2)
+
+ transfersM3 := []*types.Transfer{
+ {Owner: "party2", Type: types.TransferTypeMakerFeeReceive, Amount: &types.FinancialAmount{Asset: "asset2", Amount: num.NewUint(450)}},
+ }
+ tracker.UpdateFeesFromTransfers("asset2", "market3", transfersM3)
+ epochService.target(context.Background(), types.Epoch{Seq: 2, Action: vgproto.EpochAction_EPOCH_ACTION_END})
+
+ contribution, fraction = tracker.CalculateTotalMakerContributionInQuantum(1)
+ // party 1 received in total:
+ // asset1 : 1000
+ // party 2 received in total:
+ // asset1 : 1500
+ // asset2: 450/2 = 225
+ require.Equal(t, 2, len(fraction))
+ require.Equal(t, 2, len(contribution))
+ require.Equal(t, "1000", contribution["party1"].String())
+ require.Equal(t, "1725", contribution["party2"].String())
+ require.Equal(t, "0.3669724770642202", fraction["party1"].String())
+ require.Equal(t, "0.6330275229357798", fraction["party2"].String())
+
+ epochService.target(context.Background(), types.Epoch{Seq: 3, Action: vgproto.EpochAction_EPOCH_ACTION_START})
+
+ transfersM4 := []*types.Transfer{
+ {Owner: "party1", Type: types.TransferTypeMakerFeeReceive, Amount: &types.FinancialAmount{Asset: "asset1", Amount: num.NewUint(2000)}},
+ }
+ tracker.UpdateFeesFromTransfers("asset1", "market2", transfersM4)
+
+ transfersM5 := []*types.Transfer{
+ {Owner: "party2", Type: types.TransferTypeMakerFeeReceive, Amount: &types.FinancialAmount{Asset: "asset2", Amount: num.NewUint(550)}},
+ }
+ tracker.UpdateFeesFromTransfers("asset2", "market3", transfersM5)
+ epochService.target(context.Background(), types.Epoch{Seq: 3, Action: vgproto.EpochAction_EPOCH_ACTION_END})
+
+ // party 1 received in total this epoch:
+ // asset1 : 2000
+ // party 2 received in total:
+ // asset2: 550/2 = 275
+ // in total for both epochs:
+ // party1 = 3000
+ // party2 = 2000
+ contribution, fraction = tracker.CalculateTotalMakerContributionInQuantum(2)
+ require.Equal(t, 2, len(fraction))
+ require.Equal(t, 2, len(contribution))
+ require.Equal(t, "3000", contribution["party1"].String())
+ require.Equal(t, "2000", contribution["party2"].String())
+ require.Equal(t, "0.6", fraction["party1"].String())
+ require.Equal(t, "0.4", fraction["party2"].String())
+}
+
func TestGetScores(t *testing.T) {
ctx := context.Background()
epochService := &TestEpochEngine{}
@@ -218,7 +320,8 @@ func TestGetScores(t *testing.T) {
broker := bmocks.NewMockBroker(ctrl)
broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
broker.EXPECT().Send(gomock.Any()).AnyTimes()
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&EligibilityChecker{})
tracker.MarketProposed("asset1", "market1", "me")
@@ -368,7 +471,8 @@ func TestGetScoresIndividualsDifferentScopes(t *testing.T) {
broker := bmocks.NewMockBroker(ctrl)
broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
broker.EXPECT().Send(gomock.Any()).AnyTimes()
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&EligibilityChecker{})
tracker.MarketProposed("asset1", "market1", "me")
@@ -530,7 +634,8 @@ func TestMarketTrackerStateChange(t *testing.T) {
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
tracker.SetEligibilityChecker(&EligibilityChecker{})
state1, _, err := tracker.GetState(key)
@@ -561,7 +666,8 @@ func TestFeesTrackerWith0(t *testing.T) {
balanceChecker.EXPECT().GetAvailableBalance(gomock.Any()).Return(num.UintZero(), nil).AnyTimes()
broker := bmocks.NewMockBroker(ctrl)
broker.EXPECT().Send(gomock.Any()).AnyTimes()
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochEngine.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
epochEngine.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START})
@@ -595,7 +701,8 @@ func TestGetLastEpochTakeFees(t *testing.T) {
teams := mocks.NewMockTeams(ctrl)
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochEngine.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
epochEngine.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START})
tracker.SetEligibilityChecker(&EligibilityChecker{})
@@ -659,7 +766,8 @@ func TestGetLastEpochTakeFeesMultiEpochWindow(t *testing.T) {
teams := mocks.NewMockTeams(ctrl)
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochEngine.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
epochEngine.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START})
tracker.SetEligibilityChecker(&EligibilityChecker{})
@@ -749,7 +857,8 @@ func TestFeesTracker(t *testing.T) {
broker := bmocks.NewMockBroker(ctrl)
broker.EXPECT().Send(gomock.Any()).AnyTimes()
broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochEngine.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
epochEngine.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START})
tracker.SetEligibilityChecker(&EligibilityChecker{})
@@ -851,7 +960,7 @@ func TestFeesTracker(t *testing.T) {
balanceChecker = mocks.NewMockAccountBalanceChecker(ctrl)
balanceChecker.EXPECT().GetAvailableBalance(gomock.Any()).Return(num.UintZero(), nil).AnyTimes()
broker.EXPECT().Send(gomock.Any()).AnyTimes()
- trackerLoad := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ trackerLoad := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochEngineLoad.NotifyOnEpoch(trackerLoad.OnEpochEvent, trackerLoad.OnEpochRestore)
pl := snapshotpb.Payload{}
@@ -935,7 +1044,8 @@ func TestSnapshot(t *testing.T) {
teams := mocks.NewMockTeams(ctrl)
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
- trackerLoad := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ trackerLoad := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
pl := snapshotpb.Payload{}
require.NoError(t, proto.Unmarshal(state1, &pl))
@@ -958,7 +1068,8 @@ func TestCheckpoint(t *testing.T) {
teams := mocks.NewMockTeams(ctrl)
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
- trackerLoad := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ trackerLoad := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
require.NoError(t, trackerLoad.Load(context.Background(), b))
@@ -1021,7 +1132,8 @@ func TestSnapshotRoundTripViaEngine(t *testing.T) {
teams := mocks.NewMockTeams(ctrl)
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
- tracker2 := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker2 := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
snapshotEngine2, err := snp.NewEngine(vegaPath, config, log, timeService, statsData.Blockchain)
require.NoError(t, err)
defer snapshotEngine2.Close()
@@ -1059,7 +1171,8 @@ func TestMarketProposerBonusScenarios(t *testing.T) {
teams := mocks.NewMockTeams(ctrl)
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&EligibilityChecker{})
@@ -1192,7 +1305,8 @@ func TestPositionMetric(t *testing.T) {
broker := bmocks.NewMockBroker(ctrl)
broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
broker.EXPECT().Send(gomock.Any()).AnyTimes()
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
epochStartTime := time.Now()
@@ -1301,7 +1415,8 @@ func TestRealisedReturnMetric(t *testing.T) {
broker := bmocks.NewMockBroker(ctrl)
broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
broker.EXPECT().Send(gomock.Any()).AnyTimes()
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
epochStartTime := time.Now()
@@ -1405,7 +1520,8 @@ func TestRelativeReturnMetric(t *testing.T) {
broker := bmocks.NewMockBroker(ctrl)
broker.EXPECT().Send(gomock.Any()).AnyTimes()
broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
epochStartTime := time.Now()
@@ -1494,7 +1610,8 @@ func TestTeamStatsForMarkets(t *testing.T) {
teams := mocks.NewMockTeams(ctrl)
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
asset1 := vgrand.RandomStr(5)
asset2 := vgrand.RandomStr(5)
@@ -1606,8 +1723,8 @@ func setupDefaultTrackerForTest(t *testing.T) *common.MarketActivityTracker {
teams := mocks.NewMockTeams(ctrl)
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
-
- tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ collateralService := mocks.NewMockCollateral(ctrl)
+ tracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, collateralService)
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
epochStartTime := time.Now()
diff --git a/core/execution/common/mat_intermediate_scores_internal_test.go b/core/execution/common/mat_intermediate_scores_internal_test.go
index a60ffc9f120..3d59b55be20 100644
--- a/core/execution/common/mat_intermediate_scores_internal_test.go
+++ b/core/execution/common/mat_intermediate_scores_internal_test.go
@@ -47,7 +47,7 @@ func TestPublishGameMetricAveragePosition(t *testing.T) {
gameScoreEvents = append(gameScoreEvents, evt)
}
}).AnyTimes()
- tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, DummyCollateralEngine{})
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&DummyEligibilityChecker{})
epochService.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Time{}})
@@ -289,7 +289,7 @@ func TestPublishGameMetricReturnVolatility(t *testing.T) {
gameScoreEvents = append(gameScoreEvents, evt)
}
}).AnyTimes()
- tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, DummyCollateralEngine{})
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&DummyEligibilityChecker{})
epochService.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Time{}})
@@ -537,7 +537,7 @@ func TestPublishGameMetricRelativeReturn(t *testing.T) {
gameScoreEvents = append(gameScoreEvents, evt)
}
}).AnyTimes()
- tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, DummyCollateralEngine{})
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&DummyEligibilityChecker{})
epochService.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Unix(0, 0)})
@@ -757,7 +757,7 @@ func TestPublishGameMetricRealisedReturn(t *testing.T) {
gameScoreEvents = append(gameScoreEvents, evt)
}
}).AnyTimes()
- tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, DummyCollateralEngine{})
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&DummyEligibilityChecker{})
epochService.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Unix(0, 0)})
@@ -879,7 +879,7 @@ func TestPublishGameMetricFees(t *testing.T) {
gameScoreEvents = append(gameScoreEvents, evt)
}
}).AnyTimes()
- tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker)
+ tracker := NewMarketActivityTracker(logging.NewTestLogger(), teams, balanceChecker, broker, DummyCollateralEngine{})
epochService.NotifyOnEpoch(tracker.OnEpochEvent, tracker.OnEpochRestore)
tracker.SetEligibilityChecker(&DummyEligibilityChecker{})
epochService.target(context.Background(), types.Epoch{Seq: 1, Action: vgproto.EpochAction_EPOCH_ACTION_START, StartTime: time.Unix(0, 0)})
diff --git a/core/execution/engine.go b/core/execution/engine.go
index e1b1bf5a707..5431c1f5cd7 100644
--- a/core/execution/engine.go
+++ b/core/execution/engine.go
@@ -86,8 +86,10 @@ type Engine struct {
assets common.Assets
referralDiscountRewardService fee.ReferralDiscountRewardService
volumeDiscountService fee.VolumeDiscountService
- banking common.Banking
- parties common.Parties
+ volumeRebateService fee.VolumeRebateService
+
+ banking common.Banking
+ parties common.Parties
broker common.Broker
timeService common.TimeService
@@ -137,6 +139,7 @@ func NewEngine(
assets common.Assets,
referralDiscountRewardService fee.ReferralDiscountRewardService,
volumeDiscountService fee.VolumeDiscountService,
+ volumeRebateService fee.VolumeRebateService,
banking common.Banking,
parties common.Parties,
delayTransactionsTarget common.DelayTransactionsTarget,
@@ -165,9 +168,11 @@ func NewEngine(
skipRestoreSuccessors: map[string]struct{}{},
referralDiscountRewardService: referralDiscountRewardService,
volumeDiscountService: volumeDiscountService,
- banking: banking,
- parties: parties,
- delayTransactionsTarget: delayTransactionsTarget,
+ volumeRebateService: volumeRebateService,
+
+ banking: banking,
+ parties: parties,
+ delayTransactionsTarget: delayTransactionsTarget,
}
// set the eligibility for proposer bonus checker
@@ -707,6 +712,7 @@ func (e *Engine) submitMarket(ctx context.Context, marketConfig *types.Market, o
e.peggedOrderCountUpdated,
e.referralDiscountRewardService,
e.volumeDiscountService,
+ e.volumeRebateService,
e.banking,
e.parties,
)
@@ -790,6 +796,7 @@ func (e *Engine) submitSpotMarket(ctx context.Context, marketConfig *types.Marke
e.peggedOrderCountUpdated,
e.referralDiscountRewardService,
e.volumeDiscountService,
+ e.volumeRebateService,
e.banking,
)
if err != nil {
diff --git a/core/execution/engine_netparams.go b/core/execution/engine_netparams.go
index 85b3033d7ba..c0580f1c1e6 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",
@@ -503,6 +535,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)
}
@@ -567,6 +607,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.go b/core/execution/engine_snapshot.go
index 05a56317fef..3ec884cf124 100644
--- a/core/execution/engine_snapshot.go
+++ b/core/execution/engine_snapshot.go
@@ -138,6 +138,7 @@ func (e *Engine) restoreSpotMarket(ctx context.Context, em *types.ExecSpotMarket
e.peggedOrderCountUpdated,
e.referralDiscountRewardService,
e.volumeDiscountService,
+ e.volumeRebateService,
e.banking,
)
if err != nil {
@@ -215,6 +216,7 @@ func (e *Engine) restoreMarket(ctx context.Context, em *types.ExecMarket) (*futu
e.peggedOrderCountUpdated,
e.referralDiscountRewardService,
e.volumeDiscountService,
+ e.volumeRebateService,
e.banking,
e.parties,
)
diff --git a/core/execution/engine_snapshot_test.go b/core/execution/engine_snapshot_test.go
index 9453f95d09b..ed67607aa7b 100644
--- a/core/execution/engine_snapshot_test.go
+++ b/core/execution/engine_snapshot_test.go
@@ -90,17 +90,18 @@ func getMockedEngine(t *testing.T) *engineFake {
balanceChecker := mocks.NewMockAccountBalanceChecker(ctrl)
referralDiscountReward := fmock.NewMockReferralDiscountRewardService(ctrl)
volumeDiscount := fmock.NewMockVolumeDiscountService(ctrl)
+ volumeRebate := fmock.NewMockVolumeRebateService(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)
delayTarget := mocks.NewMockDelayTransactionsTarget(ctrl)
delayTarget.EXPECT().MarketDelayRequiredUpdated(gomock.Any(), gomock.Any()).AnyTimes()
- mat := common.NewMarketActivityTracker(log, teams, balanceChecker, broker)
- exec := execution.NewEngine(log, execConfig, timeService, collateralService, oracleService, broker, statevar, mat, asset, referralDiscountReward, volumeDiscount, banking, parties, delayTarget)
+ mat := common.NewMarketActivityTracker(log, teams, balanceChecker, broker, collateralService)
+ exec := execution.NewEngine(log, execConfig, timeService, collateralService, oracleService, broker, statevar, mat, asset, referralDiscountReward, volumeDiscount, volumeRebate, banking, parties, delayTarget)
epochEngine.NotifyOnEpoch(mat.OnEpochEvent, mat.OnEpochRestore)
return &engineFake{
Engine: exec,
@@ -159,16 +160,17 @@ 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()
+ volumeRebate := fmock.NewMockVolumeRebateService(ctrl)
+ 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)
+ mat := common.NewMarketActivityTracker(log, teams, balanceChecker, broker, collateralService)
banking := mocks.NewMockBanking(ctrl)
parties := mocks.NewMockParties(ctrl)
delayTarget := mocks.NewMockDelayTransactionsTarget(ctrl)
delayTarget.EXPECT().MarketDelayRequiredUpdated(gomock.Any(), gomock.Any()).AnyTimes()
- e := execution.NewEngine(log, executionConfig, timeService, collateralService, oracleService, broker, statevar, mat, asset, referralDiscountReward, volumeDiscount, banking, parties, delayTarget)
+ e := execution.NewEngine(log, executionConfig, timeService, collateralService, oracleService, broker, statevar, mat, asset, referralDiscountReward, volumeDiscount, volumeRebate, banking, parties, delayTarget)
epochEngine.NotifyOnEpoch(mat.OnEpochEvent, mat.OnEpochRestore)
return e, ctrl
}
diff --git a/core/execution/future/market.go b/core/execution/future/market.go
index 4bf2c65722a..820d5f131b2 100644
--- a/core/execution/future/market.go
+++ b/core/execution/future/market.go
@@ -96,6 +96,7 @@ type Market struct {
fee *fee.Engine
referralDiscountRewardService fee.ReferralDiscountRewardService
volumeDiscountService fee.VolumeDiscountService
+ volumeRebateService fee.VolumeRebateService
liquidity *common.MarketLiquidity
liquidityEngine common.LiquidityEngine
@@ -197,6 +198,7 @@ func NewMarket(
peggedOrderNotify func(int64),
referralDiscountRewardService fee.ReferralDiscountRewardService,
volumeDiscountService fee.VolumeDiscountService,
+ volumeRebateService fee.VolumeRebateService,
banking common.Banking,
parties common.Parties,
) (*Market, error) {
@@ -347,6 +349,7 @@ func NewMarket(
perp: marketType == types.MarketTypePerp,
referralDiscountRewardService: referralDiscountRewardService,
volumeDiscountService: volumeDiscountService,
+ volumeRebateService: volumeRebateService,
partyMarginFactor: map[string]num.Decimal{},
banking: banking,
markPriceCalculator: common.NewCompositePriceCalculator(ctx, mkt.MarkPriceConfiguration, oracleEngine, timeService),
@@ -2693,12 +2696,12 @@ func (m *Market) calcFees(trades []*types.Trade) (events.FeesTransfer, error) {
)
if !m.as.InAuction() {
- fees, err = m.fee.CalculateForContinuousMode(trades, m.referralDiscountRewardService, m.volumeDiscountService)
+ fees, err = m.fee.CalculateForContinuousMode(trades, m.referralDiscountRewardService, m.volumeDiscountService, m.volumeRebateService)
} else if m.as.IsMonitorAuction() {
// we are in auction mode
- fees, err = m.fee.CalculateForAuctionMode(trades, m.referralDiscountRewardService, m.volumeDiscountService)
+ fees, err = m.fee.CalculateForAuctionMode(trades, m.referralDiscountRewardService, m.volumeDiscountService, m.volumeRebateService)
} else if m.as.IsFBA() {
- fees, err = m.fee.CalculateForFrequentBatchesAuctionMode(trades, m.referralDiscountRewardService, m.volumeDiscountService)
+ fees, err = m.fee.CalculateForFrequentBatchesAuctionMode(trades, m.referralDiscountRewardService, m.volumeDiscountService, m.volumeRebateService)
}
if err != nil {
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.go b/core/execution/future/market_snapshot.go
index cbded574128..ed979d73159 100644
--- a/core/execution/future/market_snapshot.go
+++ b/core/execution/future/market_snapshot.go
@@ -67,6 +67,7 @@ func NewMarketFromSnapshot(
peggedOrderNotify func(int64),
referralDiscountRewardService fee.ReferralDiscountRewardService,
volumeDiscountService fee.VolumeDiscountService,
+ volumeRebateService fee.VolumeRebateService,
banking common.Banking,
parties common.Parties,
) (*Market, error) {
@@ -234,6 +235,7 @@ func NewMarketFromSnapshot(
fee: feeEngine,
referralDiscountRewardService: referralDiscountRewardService,
volumeDiscountService: volumeDiscountService,
+ volumeRebateService: volumeRebateService,
liquidityEngine: liquidityEngine,
liquidity: marketLiquidity,
parties: map[string]struct{}{},
diff --git a/core/execution/future/market_snapshot_test.go b/core/execution/future/market_snapshot_test.go
index 239a7008213..1e422c5d1f4 100644
--- a/core/execution/future/market_snapshot_test.go
+++ b/core/execution/future/market_snapshot_test.go
@@ -242,8 +242,6 @@ func newMarketFromSnapshot(t *testing.T, ctx context.Context, ctrl *gomock.Contr
teams := mocks.NewMockTeams(ctrl)
bc := mocks.NewMockAccountBalanceChecker(ctrl)
broker := bmocks.NewMockBroker(ctrl)
- marketActivityTracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, bc, broker)
- epochEngine.NotifyOnEpoch(marketActivityTracker.OnEpochEvent, marketActivityTracker.OnEpochRestore)
broker.EXPECT().Stage(gomock.Any()).AnyTimes()
broker.EXPECT().Send(gomock.Any()).AnyTimes()
@@ -251,16 +249,20 @@ func newMarketFromSnapshot(t *testing.T, ctx context.Context, ctrl *gomock.Contr
timeService.EXPECT().GetTimeNow().AnyTimes()
collateralEngine := collateral.New(log, collateral.NewDefaultConfig(), timeService, broker)
+ marketActivityTracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, bc, broker, collateralEngine)
+ epochEngine.NotifyOnEpoch(marketActivityTracker.OnEpochEvent, marketActivityTracker.OnEpochRestore)
+
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()
+ volumeRebate := fmock.NewMockVolumeRebateService(ctrl)
+ 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)
return future.NewMarketFromSnapshot(ctx, log, em, riskConfig, positionConfig, settlementConfig, matchingConfig,
feeConfig, liquidityConfig, collateralEngine, oracleEngine, timeService, broker, stubs.NewStateVar(), cfgAsset, marketActivityTracker,
- peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, banking, parties)
+ peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, volumeRebate, banking, parties)
}
diff --git a/core/execution/future/market_test.go b/core/execution/future/market_test.go
index 8e62e199c84..e243bf1a3f9 100644
--- a/core/execution/future/market_test.go
+++ b/core/execution/future/market_test.go
@@ -235,22 +235,24 @@ func (tm *testMarket) Run(ctx context.Context, mktCfg types.Market) *testMarket
teams := mocks.NewMockTeams(tm.ctrl)
bc := mocks.NewMockAccountBalanceChecker(tm.ctrl)
broker := bmocks.NewMockBroker(tm.ctrl)
- marketActivityTracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, bc, broker)
+ marketActivityTracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, bc, broker, collateralEngine)
epochEngine.NotifyOnEpoch(marketActivityTracker.OnEpochEvent, marketActivityTracker.OnEpochRestore)
referralDiscountReward := fmocks.NewMockReferralDiscountRewardService(tm.ctrl)
volumeDiscount := fmocks.NewMockVolumeDiscountService(tm.ctrl)
+ volumeRebate := fmocks.NewMockVolumeRebateService(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()
+ volumeRebate.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes()
banking := mocks.NewMockBanking(tm.ctrl)
parties := mocks.NewMockParties(tm.ctrl)
mktEngine, err := future.NewMarket(ctx,
tm.log, riskConfig, positionConfig, settlementConfig, matchingConfig,
feeConfig, liquidityConfig, collateralEngine, oracleEngine, &mktCfg, tm.timeService, tm.broker, mas, statevarEngine, marketActivityTracker, cfgAsset,
- peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, banking, parties,
+ peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, volumeRebate, banking, parties,
)
require.NoError(tm.t, err)
@@ -648,22 +650,25 @@ func getTestMarket2WithDP(
epoch.EXPECT().NotifyOnEpoch(gomock.Any(), gomock.Any()).Times(1)
teams := mocks.NewMockTeams(tm.ctrl)
bc := mocks.NewMockAccountBalanceChecker(tm.ctrl)
- marketActivityTracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, bc, broker)
+ marketActivityTracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, bc, broker, collateralEngine)
epoch.NotifyOnEpoch(marketActivityTracker.OnEpochEvent, marketActivityTracker.OnEpochRestore)
referralDiscountReward := fmocks.NewMockReferralDiscountRewardService(tm.ctrl)
volumeDiscount := fmocks.NewMockVolumeDiscountService(tm.ctrl)
+ volumeRebate := fmocks.NewMockVolumeRebateService(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()
+ volumeRebate.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes()
banking := mocks.NewMockBanking(ctrl)
parties := mocks.NewMockParties(ctrl)
mktEngine, err := future.NewMarket(context.Background(),
log, riskConfig, positionConfig, settlementConfig, matchingConfig,
feeConfig, liquidityConfig, collateralEngine, oracleEngine, mktCfg, timeService, broker, mas, statevar, marketActivityTracker, cfgAsset,
- peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, banking, parties)
+ peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, volumeRebate, banking, parties)
if err != nil {
t.Fatalf("couldn't create a market: %v", err)
}
diff --git a/core/execution/snapshot_test.go b/core/execution/snapshot_test.go
index 6bb7f899871..359475abe5b 100644
--- a/core/execution/snapshot_test.go
+++ b/core/execution/snapshot_test.go
@@ -610,7 +610,7 @@ func getEngine(t *testing.T, vegaPath paths.Paths, now time.Time) *snapshotTestD
ctrl := gomock.NewController(t)
teams := mocks.NewMockTeams(ctrl)
bc := mocks.NewMockAccountBalanceChecker(ctrl)
- marketActivityTracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, bc, broker)
+ marketActivityTracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, bc, broker, collateralEngine)
epochEngine.NotifyOnEpoch(marketActivityTracker.OnEpochEvent, marketActivityTracker.OnEpochRestore)
ethAsset := types.Asset{
@@ -624,9 +624,10 @@ 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()
+ volumeRebate := fmock.NewMockVolumeRebateService(ctrl)
+ 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)
@@ -644,6 +645,7 @@ func getEngine(t *testing.T, vegaPath paths.Paths, now time.Time) *snapshotTestD
stubs.NewAssetStub(),
referralDiscountReward,
volumeDiscount,
+ volumeRebate,
banking,
parties,
delayTarget,
@@ -680,7 +682,7 @@ func getEngineWithParties(t *testing.T, now time.Time, balance *num.Uint, partie
ctrl := gomock.NewController(t)
teams := mocks.NewMockTeams(ctrl)
bc := mocks.NewMockAccountBalanceChecker(ctrl)
- marketActivityTracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, bc, broker)
+ marketActivityTracker := common.NewMarketActivityTracker(logging.NewTestLogger(), teams, bc, broker, collateralEngine)
epochEngine.NotifyOnEpoch(marketActivityTracker.OnEpochEvent, marketActivityTracker.OnEpochRestore)
ethAsset := types.Asset{
@@ -697,9 +699,11 @@ 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()
+ volumeRebate := fmock.NewMockVolumeRebateService(ctrl)
+
+ 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)
@@ -717,6 +721,7 @@ func getEngineWithParties(t *testing.T, now time.Time, balance *num.Uint, partie
stubs.NewAssetStub(),
referralDiscountReward,
volumeDiscount,
+ volumeRebate,
banking,
partiesMock,
delayTarget,
diff --git a/core/execution/spot/market.go b/core/execution/spot/market.go
index d44f2b922ab..63b63583eaa 100644
--- a/core/execution/spot/market.go
+++ b/core/execution/spot/market.go
@@ -82,6 +82,7 @@ type Market struct {
fee *fee.Engine
referralDiscountRewardService fee.ReferralDiscountRewardService
volumeDiscountService fee.VolumeDiscountService
+ volumeRebateService fee.VolumeRebateService
liquidity *common.MarketLiquidity
liquidityEngine common.LiquidityEngine
@@ -159,6 +160,7 @@ func NewMarket(
peggedOrderNotify func(int64),
referralDiscountRewardService fee.ReferralDiscountRewardService,
volumeDiscountService fee.VolumeDiscountService,
+ volumeRebateService fee.VolumeRebateService,
banking common.Banking,
) (*Market, error) {
if len(mkt.ID) == 0 {
@@ -232,6 +234,7 @@ func NewMarket(
fee: feeEngine,
referralDiscountRewardService: referralDiscountRewardService,
volumeDiscountService: volumeDiscountService,
+ volumeRebateService: volumeRebateService,
parties: map[string]struct{}{},
as: as,
pMonitor: pMonitor,
@@ -3170,15 +3173,15 @@ func (m *Market) calculateFeesForTrades(trades []*types.Trade) (events.FeesTrans
err error
)
if !m.as.InAuction() {
- fees, err = m.fee.CalculateForContinuousMode(trades, m.referralDiscountRewardService, m.volumeDiscountService)
+ fees, err = m.fee.CalculateForContinuousMode(trades, m.referralDiscountRewardService, m.volumeDiscountService, m.volumeRebateService)
} else if m.as.IsMonitorAuction() {
// we are in auction mode
- fees, err = m.fee.CalculateForAuctionMode(trades, m.referralDiscountRewardService, m.volumeDiscountService)
+ fees, err = m.fee.CalculateForAuctionMode(trades, m.referralDiscountRewardService, m.volumeDiscountService, m.volumeRebateService)
} else if m.as.IsFBA() {
- fees, err = m.fee.CalculateForFrequentBatchesAuctionMode(trades, m.referralDiscountRewardService, m.volumeDiscountService)
+ fees, err = m.fee.CalculateForFrequentBatchesAuctionMode(trades, m.referralDiscountRewardService, m.volumeDiscountService, m.volumeRebateService)
} else {
if !m.as.IsOpeningAuction() {
- fees, err = m.fee.CalculateForAuctionMode(trades, m.referralDiscountRewardService, m.volumeDiscountService)
+ fees, err = m.fee.CalculateForAuctionMode(trades, m.referralDiscountRewardService, m.volumeDiscountService, m.volumeRebateService)
}
}
return fees, err
diff --git a/core/execution/spot/market_callbacks.go b/core/execution/spot/market_callbacks.go
index 77cc9fa13de..436bc46e2ad 100644
--- a/core/execution/spot/market_callbacks.go
+++ b/core/execution/spot/market_callbacks.go
@@ -46,6 +46,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_snapshot.go b/core/execution/spot/market_snapshot.go
index 3c27306163a..252963c965e 100644
--- a/core/execution/spot/market_snapshot.go
+++ b/core/execution/spot/market_snapshot.go
@@ -64,6 +64,7 @@ func NewMarketFromSnapshot(
peggedOrderNotify func(int64),
referralDiscountRewardService fee.ReferralDiscountRewardService,
volumeDiscountService fee.VolumeDiscountService,
+ volumeRebateService fee.VolumeRebateService,
banking common.Banking,
) (*Market, error) {
mkt := em.Market
@@ -158,6 +159,7 @@ func NewMarketFromSnapshot(
fee: feeEngine,
referralDiscountRewardService: referralDiscountRewardService,
volumeDiscountService: volumeDiscountService,
+ volumeRebateService: volumeRebateService,
liquidity: marketLiquidity,
liquidityEngine: liquidity,
parties: map[string]struct{}{},
diff --git a/core/execution/spot/market_test.go b/core/execution/spot/market_test.go
index c8b84aa9289..41d3393b039 100644
--- a/core/execution/spot/market_test.go
+++ b/core/execution/spot/market_test.go
@@ -210,7 +210,7 @@ func newTestMarket(
teams := mocks.NewMockTeams(ctrl)
bc := mocks.NewMockAccountBalanceChecker(ctrl)
broker.EXPECT().SendBatch(gomock.Any()).Times(1)
- mat := common.NewMarketActivityTracker(log, teams, bc, broker)
+ mat := common.NewMarketActivityTracker(log, teams, bc, broker, collateral)
epoch.NotifyOnEpoch(mat.OnEpochEvent, mat.OnEpochRestore)
baseAsset := NewAssetStub(base, baseDP)
@@ -218,13 +218,15 @@ func newTestMarket(
referralDiscountReward := fmocks.NewMockReferralDiscountRewardService(ctrl)
volumeDiscount := fmocks.NewMockVolumeDiscountService(ctrl)
+ volumeRebate := fmocks.NewMockVolumeRebateService(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()
+ volumeRebate.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalZero()).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)
+ market, _ := spot.NewMarket(log, matching.NewDefaultConfig(), fee.NewDefaultConfig(), liquidity.NewDefaultConfig(), collateral, &mkt, ts, broker, as, statevarEngine, mat, baseAsset, quoteAsset, peggedOrderCounterForTest, referralDiscountReward, volumeDiscount, volumeRebate, banking)
tm := &testMarket{
market: market,
diff --git a/core/fee/engine.go b/core/fee/engine.go
index 516988a724e..1322e8de467 100644
--- a/core/fee/engine.go
+++ b/core/fee/engine.go
@@ -31,15 +31,19 @@ var (
ErrInvalidFeeFactor = errors.New("fee factors must be positive")
)
-//go:generate go run github.com/golang/mock/mockgen -destination mocks/mocks.go -package mocks code.vegaprotocol.io/vega/core/fee ReferralDiscountRewardService,VolumeDiscountService
+//go:generate go run github.com/golang/mock/mockgen -destination mocks/mocks.go -package mocks code.vegaprotocol.io/vega/core/fee ReferralDiscountRewardService,VolumeDiscountService,VolumeRebateService
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 VolumeRebateService interface {
+ VolumeRebateFactorForParty(party types.PartyID) num.Decimal
}
type Engine struct {
@@ -58,6 +62,8 @@ type factors struct {
makerFee num.Decimal
infrastructureFee num.Decimal
liquidityFee num.Decimal
+ treasuryFee num.Decimal
+ buyBackFee num.Decimal
}
func New(
@@ -128,7 +134,7 @@ func (e *Engine) ReloadConf(cfg Config) {
}
func (e *Engine) UpdateFeeFactors(fees types.Fees) error {
- if fees.Factors.MakerFee.IsNegative() || fees.Factors.InfrastructureFee.IsNegative() || fees.Factors.LiquidityFee.IsNegative() {
+ if fees.Factors.MakerFee.IsNegative() || fees.Factors.InfrastructureFee.IsNegative() || fees.Factors.LiquidityFee.IsNegative() || fees.Factors.BuyBackFee.IsNegative() || fees.Factors.TreasuryFee.IsNegative() {
return ErrInvalidFeeFactor
}
e.f.makerFee = fees.Factors.MakerFee
@@ -137,6 +143,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
@@ -155,6 +163,7 @@ func (e *Engine) CalculateForContinuousMode(
trades []*types.Trade,
referral ReferralDiscountRewardService,
volumeDiscountService VolumeDiscountService,
+ volumeRebateService VolumeRebateService,
) (events.FeesTransfer, error) {
if len(trades) <= 0 {
return nil, ErrEmptyTrades
@@ -179,7 +188,10 @@ func (e *Engine) CalculateForContinuousMode(
taker = trade.Seller
maker = trade.Buyer
}
- fee, reward := e.applyDiscountsAndRewards(taker, e.calculateContinuousModeFees(trade), referral, volumeDiscountService)
+ size := num.NewUint(trade.Size)
+ // multiply by size
+ tradeValueForFee := size.Mul(trade.Price, size).ToDecimal().Div(e.positionFactor)
+ fee, reward := e.applyDiscountsAndRewards(taker, maker, tradeValueForFee, e.calculateContinuousModeFees(trade), referral, volumeDiscountService, volumeRebateService)
e.feesStats.RegisterMakerFee(maker, taker, fee.MakerFee)
@@ -221,6 +233,47 @@ func (e *Engine) CalculateForContinuousMode(
Type: types.TransferTypeMakerFeeReceive,
})
+ if !fee.HighVolumeMakerFee.IsZero() {
+ // create a transfer for the aggressor
+ transfers = append(transfers, &types.Transfer{
+ Owner: taker,
+ Amount: &types.FinancialAmount{
+ Asset: e.asset,
+ Amount: fee.HighVolumeMakerFee.Clone(),
+ },
+ Type: types.TransferTypeHighMakerRebatePay,
+ })
+ // create a transfer for the maker
+ transfersRecv = append(transfersRecv, &types.Transfer{
+ Owner: maker,
+ Amount: &types.FinancialAmount{
+ Asset: e.asset,
+ Amount: fee.HighVolumeMakerFee.Clone(),
+ },
+ Type: types.TransferTypeHighMakerRebateReceive,
+ })
+ }
+
+ // 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
}
@@ -284,6 +337,7 @@ func (e *Engine) CalculateForAuctionMode(
trades []*types.Trade,
referral ReferralDiscountRewardService,
volumeDiscount VolumeDiscountService,
+ volumeRebate VolumeRebateService,
) (events.FeesTransfer, error) {
if len(trades) <= 0 {
return nil, ErrEmptyTrades
@@ -299,7 +353,7 @@ func (e *Engine) CalculateForAuctionMode(
// for each trades both party needs to pay half of the fees
// no maker fees are to be paid here.
for _, v := range trades {
- buyerFess, sellerFees, newTransfers := e.getAuctionModeFeesAndTransfers(v, referral, volumeDiscount)
+ buyerFess, sellerFees, newTransfers := e.getAuctionModeFeesAndTransfers(v, referral, volumeDiscount, volumeRebate)
transfers = append(transfers, newTransfers...)
// increase the total fee for the parties
@@ -333,6 +387,7 @@ func (e *Engine) CalculateForFrequentBatchesAuctionMode(
trades []*types.Trade,
referral ReferralDiscountRewardService,
volumeDiscount VolumeDiscountService,
+ volumeRebate VolumeRebateService,
) (events.FeesTransfer, error) {
if len(trades) <= 0 {
return nil, ErrEmptyTrades
@@ -357,7 +412,7 @@ func (e *Engine) CalculateForFrequentBatchesAuctionMode(
)
// we are in the same auction, normal auction fees applies
if v.BuyerAuctionBatch == v.SellerAuctionBatch {
- v.BuyerFee, v.SellerFee, newTransfers = e.getAuctionModeFeesAndTransfers(v, referral, volumeDiscount)
+ v.BuyerFee, v.SellerFee, newTransfers = e.getAuctionModeFeesAndTransfers(v, referral, volumeDiscount, volumeRebate)
sellerTotalFee = num.Sum(v.BuyerFee.InfrastructureFee, v.BuyerFee.LiquidityFee)
buyerTotalFee = num.Sum(v.SellerFee.InfrastructureFee, v.SellerFee.LiquidityFee)
} else {
@@ -369,7 +424,7 @@ func (e *Engine) CalculateForFrequentBatchesAuctionMode(
}
// fees are being assign to the trade directly
// no need to do add them there as well
- ftrnsfr, _ := e.CalculateForContinuousMode([]*types.Trade{v}, referral, volumeDiscount)
+ ftrnsfr, _ := e.CalculateForContinuousMode([]*types.Trade{v}, referral, volumeDiscount, volumeRebate)
newTransfers = ftrnsfr.Transfers()
buyerTotalFee = ftrnsfr.TotalFeesAmountPerParty()[v.Buyer]
sellerTotalFee = ftrnsfr.TotalFeesAmountPerParty()[v.Seller]
@@ -510,6 +565,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 +599,41 @@ 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))
+func (e *Engine) applyDiscountsAndRewards(taker string, maker string, tradeValueForFeePurposes num.Decimal, fees *types.Fee, referral ReferralDiscountRewardService, volumeDiscount VolumeDiscountService, volumeRebate VolumeRebateService) (*types.Fee, *types.ReferrerReward) {
+ referralDiscountFactors := referral.ReferralDiscountFactorsForParty(types.PartyID(taker))
+ volumeDiscountFactors := volumeDiscount.VolumeDiscountFactorForParty(types.PartyID(taker))
+ highVolumeMakerFee := volumeRebate.VolumeRebateFactorForParty(types.PartyID(maker)).Mul(tradeValueForFeePurposes)
+ highVolumeMakerFeeI, _ := num.UintFromDecimal(highVolumeMakerFee)
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 +641,18 @@ 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())
+
+ var rebateDiscountFactor num.Decimal
+ bbAndTreasury := num.Sum(fees.BuyBackFee, fees.TreasuryFee).ToDecimal()
+ if !bbAndTreasury.IsZero() {
+ rebateDiscountFactor = num.DecimalOne().Sub(highVolumeMakerFee.Div(bbAndTreasury))
+ }
+
+ treasuryFee, _ := num.UintFromDecimal(fees.TreasuryFee.ToDecimal().Mul(rebateDiscountFactor))
+ buyBackFee, _ := num.UintFromDecimal(fees.BuyBackFee.ToDecimal().Mul(rebateDiscountFactor))
// apply volume discounts
mf = mf.Sub(mf, volumeMakerDiscount)
@@ -574,9 +660,12 @@ func (e *Engine) applyDiscountsAndRewards(taker string, fees *types.Fee, referra
lf = lf.Sub(lf, volumeLfDiscount)
f := &types.Fee{
+ HighVolumeMakerFee: highVolumeMakerFeeI,
MakerFee: mf,
LiquidityFee: lf,
InfrastructureFee: inf,
+ BuyBackFee: buyBackFee.Clone(),
+ TreasuryFee: treasuryFee.Clone(),
MakerFeeVolumeDiscount: volumeMakerDiscount,
InfrastructureFeeVolumeDiscount: volumeInfDiscount,
LiquidityFeeVolumeDiscount: volumeLfDiscount,
@@ -604,16 +693,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)
@@ -640,18 +729,19 @@ func (e *Engine) applyDiscountsAndRewards(taker string, fees *types.Fee, referra
return f, referrerReward
}
-func (e *Engine) getAuctionModeFeesAndTransfers(t *types.Trade, referral ReferralDiscountRewardService, volumeDiscount VolumeDiscountService) (*types.Fee, *types.Fee, []*types.Transfer) {
+func (e *Engine) getAuctionModeFeesAndTransfers(t *types.Trade, referral ReferralDiscountRewardService, volumeDiscount VolumeDiscountService, volumeRebate VolumeRebateService) (*types.Fee, *types.Fee, []*types.Transfer) {
fee := e.calculateAuctionModeFees(t)
- buyerFeers, buyerReferrerRewards := e.applyDiscountsAndRewards(t.Buyer, fee, referral, volumeDiscount)
- sellerFeers, sellerReferrerRewards := e.applyDiscountsAndRewards(t.Seller, fee, referral, volumeDiscount)
+ // in auction there is no maker so there is no rebate, so passing 0 as the trade value
+ buyerFees, buyerReferrerRewards := e.applyDiscountsAndRewards(t.Buyer, t.Buyer, num.DecimalZero(), fee, referral, volumeDiscount, volumeRebate)
+ sellerFees, sellerReferrerRewards := e.applyDiscountsAndRewards(t.Seller, t.Seller, num.DecimalZero(), fee, referral, volumeDiscount, volumeRebate)
transfers := make([]*types.Transfer, 0, 12)
transfers = append(transfers,
e.getAuctionModeFeeTransfers(
- sellerFeers.InfrastructureFee, sellerFeers.LiquidityFee, t.Seller)...)
+ sellerFees.InfrastructureFee, sellerFees.LiquidityFee, sellerFees.BuyBackFee, sellerFees.TreasuryFee, t.Seller)...)
transfers = append(transfers,
e.getAuctionModeFeeTransfers(
- buyerFeers.InfrastructureFee, buyerFeers.LiquidityFee, t.Buyer)...)
+ buyerFees.InfrastructureFee, buyerFees.LiquidityFee, buyerFees.BuyBackFee, buyerFees.TreasuryFee, t.Buyer)...)
if buyerReferrerRewards != nil {
referrerParty, _ := referral.GetReferrer(types.PartyID(t.Buyer))
@@ -667,7 +757,7 @@ func (e *Engine) getAuctionModeFeesAndTransfers(t *types.Trade, referral Referra
num.Sum(sellerReferrerRewards.InfrastructureFeeReferrerReward, sellerReferrerRewards.LiquidityFeeReferrerReward), t.Seller, string(referrerParty))...)
}
- return buyerFeers, sellerFeers, transfers
+ return buyerFees, sellerFees, transfers
}
func (e *Engine) calculateContinuousModeFees(trade *types.Trade) *types.Fee {
@@ -677,10 +767,15 @@ 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,
+ MakerFee: mf,
+ InfrastructureFee: inf,
+ LiquidityFee: lf,
+ BuyBackFee: bbf,
+ TreasuryFee: tf,
+ HighVolumeMakerFee: num.UintZero(),
}
}
@@ -689,10 +784,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,
}
}
@@ -718,7 +817,7 @@ func (e *Engine) getAuctionModeFeeReferrerRewardTransfers(reward *num.Uint, p, r
}
}
-func (e *Engine) getAuctionModeFeeTransfers(infraFee, liquiFee *num.Uint, p string) []*types.Transfer {
+func (e *Engine) getAuctionModeFeeTransfers(infraFee, liquiFee, buyBackFee, treasuryFee *num.Uint, p string) []*types.Transfer {
// we return both transfer for the party in a slice
// always the infrastructure fee first
return []*types.Transfer{
@@ -738,6 +837,22 @@ func (e *Engine) getAuctionModeFeeTransfers(infraFee, liquiFee *num.Uint, p stri
},
Type: types.TransferTypeLiquidityFeePay,
},
+ {
+ Owner: p,
+ Amount: &types.FinancialAmount{
+ Asset: e.asset,
+ Amount: buyBackFee.Clone(),
+ },
+ Type: types.TransferTypeBuyBackFeePay,
+ },
+ {
+ Owner: p,
+ Amount: &types.FinancialAmount{
+ Asset: e.asset,
+ Amount: treasuryFee.Clone(),
+ },
+ Type: types.TransferTypeTreasuryPay,
+ },
}
}
@@ -760,6 +875,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..e9b145ceb54 100644
--- a/core/fee/engine_test.go
+++ b/core/fee/engine_test.go
@@ -35,13 +35,24 @@ const (
testAsset = "ETH"
)
-var testFees = types.Fees{
- Factors: &types.FeeFactors{
- LiquidityFee: num.DecimalFromFloat(0.1),
- InfrastructureFee: num.DecimalFromFloat(0.05),
- MakerFee: num.DecimalFromFloat(0.02),
- },
-}
+var (
+ testFees = types.Fees{
+ Factors: &types.FeeFactors{
+ LiquidityFee: num.DecimalFromFloat(0.1),
+ InfrastructureFee: num.DecimalFromFloat(0.05),
+ MakerFee: num.DecimalFromFloat(0.02),
+ },
+ }
+ extendedTestFees = types.Fees{
+ Factors: &types.FeeFactors{
+ LiquidityFee: num.DecimalFromFloat(0.1),
+ InfrastructureFee: num.DecimalFromFloat(0.05),
+ MakerFee: num.DecimalFromFloat(0.02),
+ BuyBackFee: num.DecimalFromFloat(0.002),
+ TreasuryFee: num.DecimalFromFloat(0.003),
+ },
+ }
+)
type testFee struct {
*fee.Engine
@@ -60,27 +71,47 @@ func getTestFee(t *testing.T) *testFee {
return &testFee{eng}
}
+func getExtendedTestFee(t *testing.T) *testFee {
+ t.Helper()
+ eng, err := fee.New(
+ logging.NewTestLogger(),
+ fee.NewDefaultConfig(),
+ extendedTestFees,
+ testAsset,
+ num.DecimalFromInt64(1),
+ )
+ assert.NoError(t, err)
+ return &testFee{eng}
+}
+
func TestFeeEngine(t *testing.T) {
t.Run("update fee factors with invalid input", testUpdateFeeFactorsError)
t.Run("update fee factors with valid input", testUpdateFeeFactors)
t.Run("calculate continuous trading fee empty trade", testCalcContinuousTradingErrorEmptyTrade)
t.Run("calculate continuous trading fee", testCalcContinuousTrading)
t.Run("calculate continuous trading fee + check amounts", testCalcContinuousTradingAndCheckAmounts)
-
t.Run("calculate continuous trading fee + check amounts with discounts and rewards", testCalcContinuousTradingAndCheckAmountsWithDiscount)
-
- t.Run("calculate continuous trading fee empty trade", testCalcContinuousTradingErrorEmptyTrade)
t.Run("calculate auction trading fee empty trade", testCalcAuctionTradingErrorEmptyTrade)
t.Run("calculate auction trading fee", testCalcAuctionTrading)
-
t.Run("calculate batch auction trading fee empty trade", testCalcBatchAuctionTradingErrorEmptyTrade)
t.Run("calculate batch auction trading fee same batch", testCalcBatchAuctionTradingSameBatch)
t.Run("calculate batch auction trading fee different batches", testCalcBatchAuctionTradingDifferentBatches)
-
t.Run("Build liquidity fee transfers with remainder", testBuildLiquidityFeesRemainder)
t.Run("calculate closeout fees", testCloseoutFees)
}
+func TestFeeEngineWithBuyBackAndTreasury(t *testing.T) {
+ t.Run("update fee factors with invalid input", testUpdateExtendedFeeFactorsError)
+ t.Run("update fee factors with valid input", testUpdateExtendedFeeFactors)
+ t.Run("calculate continuous trading fee empty trade", testCalcContinuousTradingErrorEmptyTrade)
+ t.Run("calculate continuous trading fee", testCalcContinuousTradingExtended)
+ t.Run("calculate continuous trading fee + check amounts", testCalcContinuousTradingAndCheckAmountsExtended)
+ t.Run("calculate continuous trading fee + check amounts with discounts and rewards", testCalcContinuousTradingAndCheckAmountsWithDiscountExtended)
+ t.Run("calculate auction trading fee empty trade", testCalcAuctionTradingErrorEmptyTrade)
+ t.Run("calculate auction trading fee", testCalcAuctionTradingExtended)
+ t.Run("calculate batch auction trading fee empty trade", testCalcBatchAuctionTradingErrorEmptyTrade)
+}
+
func testUpdateFeeFactors(t *testing.T) {
eng := getTestFee(t)
okFees := types.Fees{
@@ -94,6 +125,21 @@ func testUpdateFeeFactors(t *testing.T) {
assert.NoError(t, err)
}
+func testUpdateExtendedFeeFactors(t *testing.T) {
+ eng := getExtendedTestFee(t)
+ okFees := types.Fees{
+ Factors: &types.FeeFactors{
+ LiquidityFee: num.DecimalFromFloat(0.1),
+ InfrastructureFee: num.DecimalFromFloat(0.5),
+ MakerFee: num.DecimalFromFloat(0.25),
+ BuyBackFee: num.DecimalFromFloat(0.3),
+ TreasuryFee: num.DecimalFromFloat(0.4),
+ },
+ }
+ err := eng.UpdateFeeFactors(okFees)
+ assert.NoError(t, err)
+}
+
func testUpdateFeeFactorsError(t *testing.T) {
eng := getTestFee(t)
koFees := types.Fees{
@@ -126,13 +172,46 @@ func testUpdateFeeFactorsError(t *testing.T) {
assert.Error(t, err)
}
+func testUpdateExtendedFeeFactorsError(t *testing.T) {
+ eng := getExtendedTestFee(t)
+ koFees := types.Fees{
+ Factors: &types.FeeFactors{
+ LiquidityFee: num.DecimalFromFloat(0.1),
+ InfrastructureFee: num.DecimalFromFloat(0.5),
+ MakerFee: num.DecimalFromFloat(0.25),
+ BuyBackFee: num.DecimalFromFloat(-1),
+ TreasuryFee: num.DecimalFromFloat(0.4),
+ },
+ }
+ err := eng.UpdateFeeFactors(koFees)
+ assert.Error(t, err)
+
+ koFees = types.Fees{
+ Factors: &types.FeeFactors{
+ LiquidityFee: num.DecimalFromFloat(0.1),
+ InfrastructureFee: num.DecimalFromFloat(0.11),
+ MakerFee: num.DecimalFromFloat(0.25),
+ BuyBackFee: num.DecimalFromFloat(0.41),
+ TreasuryFee: num.DecimalFromFloat(-1),
+ },
+ }
+ err = eng.UpdateFeeFactors(koFees)
+ assert.Error(t, err)
+}
+
func testCalcContinuousTradingErrorEmptyTrade(t *testing.T) {
eng := getTestFee(t)
ctrl := gomock.NewController(t)
discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl)
volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl)
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes()
- _, err := eng.CalculateForContinuousMode([]*types.Trade{}, discountRewardService, volumeDiscountService)
+ _, err := eng.CalculateForContinuousMode([]*types.Trade{}, discountRewardService, volumeDiscountService, volumeRebateService)
+ assert.EqualError(t, err, fee.ErrEmptyTrades.Error())
+
+ eng = getExtendedTestFee(t)
+ _, err = eng.CalculateForContinuousMode([]*types.Trade{}, discountRewardService, volumeDiscountService, volumeRebateService)
assert.EqualError(t, err, fee.ErrEmptyTrades.Error())
}
@@ -141,9 +220,11 @@ 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()
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(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{
@@ -162,7 +243,7 @@ func testCalcContinuousTradingAndCheckAmounts(t *testing.T) {
},
}
- ft, err := eng.CalculateForContinuousMode(trades, discountRewardService, volumeDiscountService)
+ ft, err := eng.CalculateForContinuousMode(trades, discountRewardService, volumeDiscountService, volumeRebateService)
assert.NotNil(t, ft)
assert.Nil(t, err)
transfers := ft.Transfers()
@@ -244,14 +325,162 @@ func testCalcContinuousTradingAndCheckAmounts(t *testing.T) {
}, eng.GetFeesStatsOnEpochEnd(num.DecimalFromInt64(1)))
}
+func testCalcContinuousTradingAndCheckAmountsExtended(t *testing.T) {
+ eng := getExtendedTestFee(t)
+ ctrl := gomock.NewController(t)
+ discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl)
+ volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl)
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(types.PartyID("party2")).Return(num.DecimalFromFloat(0.0025)).AnyTimes()
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(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{
+ MakerFee: num.DecimalFromFloat(.000250),
+ InfrastructureFee: num.DecimalFromFloat(0.0005),
+ LiquidityFee: num.DecimalFromFloat(0.001),
+ BuyBackFee: num.DecimalFromFloat(0.002),
+ TreasuryFee: num.DecimalFromFloat(0.003),
+ },
+ }))
+ trades := []*types.Trade{
+ {
+ Aggressor: types.SideSell,
+ Seller: "party1",
+ Buyer: "party2",
+ Size: 5,
+ Price: num.NewUint(100000),
+ },
+ }
+
+ ft, err := eng.CalculateForContinuousMode(trades, discountRewardService, volumeDiscountService, volumeRebateService)
+ assert.NotNil(t, ft)
+ assert.Nil(t, err)
+ transfers := ft.Transfers()
+ var pay, recv, infra, liquidity, bb, treasury, hmp, hmr int
+ for _, v := range transfers {
+ if v.Type == types.TransferTypeLiquidityFeePay {
+ liquidity++
+ assert.Equal(t, num.NewUint(500), v.Amount.Amount)
+ }
+ if v.Type == types.TransferTypeInfrastructureFeePay {
+ infra++
+ assert.Equal(t, num.NewUint(250), v.Amount.Amount)
+ }
+ if v.Type == types.TransferTypeMakerFeeReceive {
+ recv++
+ assert.Equal(t, num.NewUint(125), v.Amount.Amount)
+ }
+ if v.Type == types.TransferTypeMakerFeePay {
+ pay++
+ assert.Equal(t, num.NewUint(125), v.Amount.Amount)
+ }
+ if v.Type == types.TransferTypeBuyBackFeePay {
+ bb++
+ assert.Equal(t, num.NewUint(500), v.Amount.Amount)
+ }
+ if v.Type == types.TransferTypeTreasuryPay {
+ treasury++
+ assert.Equal(t, num.NewUint(750), v.Amount.Amount)
+ }
+ if v.Type == types.TransferTypeHighMakerRebatePay {
+ hmp++
+ assert.Equal(t, num.NewUint(1250), v.Amount.Amount)
+ }
+ if v.Type == types.TransferTypeHighMakerRebateReceive {
+ hmr++
+ assert.Equal(t, num.NewUint(1250), v.Amount.Amount)
+ }
+ }
+
+ assert.Equal(t, liquidity, 1)
+ assert.Equal(t, infra, 1)
+ assert.Equal(t, bb, 1)
+ assert.Equal(t, treasury, 1)
+ assert.Equal(t, hmp, 1)
+ assert.Equal(t, hmr, 1)
+ assert.Equal(t, recv, len(trades))
+ assert.Equal(t, pay, len(trades))
+ assert.Equal(t, &eventspb.FeesStats{
+ Market: "",
+ Asset: testAsset,
+ EpochSeq: 0,
+ TotalRewardsReceived: []*eventspb.PartyAmount{},
+ ReferrerRewardsGenerated: []*eventspb.ReferrerRewardsGenerated{},
+ RefereesDiscountApplied: []*eventspb.PartyAmount{
+ {
+ Party: "party1",
+ Amount: "0",
+ QuantumAmount: "0",
+ },
+ },
+ VolumeDiscountApplied: []*eventspb.PartyAmount{
+ {
+ Party: "party1",
+ Amount: "0",
+ QuantumAmount: "0",
+ },
+ },
+ TotalMakerFeesReceived: []*eventspb.PartyAmount{
+ {
+ Party: "party2",
+ Amount: "125",
+ QuantumAmount: "125",
+ },
+ },
+ MakerFeesGenerated: []*eventspb.MakerFeesGenerated{
+ {
+ Taker: "party1",
+ MakerFeesPaid: []*eventspb.PartyAmount{
+ {
+ Party: "party2",
+ Amount: "125",
+ QuantumAmount: "125",
+ },
+ },
+ },
+ },
+ TotalFeesPaidAndReceived: []*eventspb.PartyAmount{
+ {
+ Party: "party1",
+ Amount: "875",
+ QuantumAmount: "875",
+ },
+ {
+ Party: "party2",
+ Amount: "125",
+ QuantumAmount: "125",
+ },
+ },
+ }, eng.GetFeesStatsOnEpochEnd(num.DecimalFromInt64(1)))
+}
+
func testCalcContinuousTradingAndCheckAmountsWithDiscount(t *testing.T) {
eng := getTestFee(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()
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalZero()).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{
@@ -270,7 +499,7 @@ func testCalcContinuousTradingAndCheckAmountsWithDiscount(t *testing.T) {
},
}
- ft, err := eng.CalculateForContinuousMode(trades, discountRewardService, volumeDiscountService)
+ ft, err := eng.CalculateForContinuousMode(trades, discountRewardService, volumeDiscountService, volumeRebateService)
assert.NotNil(t, ft)
assert.Nil(t, err)
transfers := ft.Transfers()
@@ -367,6 +596,166 @@ func testCalcContinuousTradingAndCheckAmountsWithDiscount(t *testing.T) {
}, eng.GetFeesStatsOnEpochEnd(num.DecimalFromInt64(1)))
}
+func testCalcContinuousTradingAndCheckAmountsWithDiscountExtended(t *testing.T) {
+ eng := getExtendedTestFee(t)
+ ctrl := gomock.NewController(t)
+ discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl)
+ volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl)
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalFromFloat(0.0025)).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{
+ MakerFee: num.DecimalFromFloat(.000250),
+ InfrastructureFee: num.DecimalFromFloat(0.0005),
+ LiquidityFee: num.DecimalFromFloat(0.001),
+ BuyBackFee: num.DecimalFromFloat(0.002),
+ TreasuryFee: num.DecimalFromFloat(0.003),
+ },
+ }))
+ trades := []*types.Trade{
+ {
+ Aggressor: types.SideSell,
+ Seller: "party1",
+ Buyer: "party2",
+ Size: 5,
+ Price: num.NewUint(100000),
+ },
+ }
+
+ ft, err := eng.CalculateForContinuousMode(trades, discountRewardService, volumeDiscountService, volumeRebateService)
+ assert.NotNil(t, ft)
+ assert.Nil(t, err)
+ transfers := ft.Transfers()
+ var pay, recv, infra, liquidity, bb, treasury, hmp, hmr int
+ for _, v := range transfers {
+ if v.Type == types.TransferTypeLiquidityFeePay {
+ liquidity++
+ assert.Equal(t, num.NewUint(252), v.Amount.Amount)
+ }
+ if v.Type == types.TransferTypeInfrastructureFeePay {
+ infra++
+ assert.Equal(t, num.NewUint(127), v.Amount.Amount)
+ }
+ if v.Type == types.TransferTypeMakerFeeReceive {
+ recv++
+ assert.Equal(t, num.NewUint(64), v.Amount.Amount)
+ }
+ if v.Type == types.TransferTypeMakerFeePay {
+ pay++
+ assert.Equal(t, num.NewUint(64), v.Amount.Amount)
+ }
+ if v.Type == types.TransferTypeBuyBackFeePay {
+ bb++
+ assert.Equal(t, num.NewUint(500), v.Amount.Amount)
+ }
+ if v.Type == types.TransferTypeTreasuryPay {
+ treasury++
+ assert.Equal(t, num.NewUint(750), v.Amount.Amount)
+ }
+ if v.Type == types.TransferTypeHighMakerRebatePay {
+ hmp++
+ assert.Equal(t, num.NewUint(1250), v.Amount.Amount)
+ }
+ if v.Type == types.TransferTypeHighMakerRebateReceive {
+ hmr++
+ assert.Equal(t, num.NewUint(1250), v.Amount.Amount)
+ }
+ }
+
+ assert.Equal(t, liquidity, 1)
+ assert.Equal(t, infra, 1)
+ assert.Equal(t, bb, 1)
+ assert.Equal(t, treasury, 1)
+ assert.Equal(t, hmp, 1)
+ assert.Equal(t, hmr, 1)
+ assert.Equal(t, recv, len(trades))
+ assert.Equal(t, pay, len(trades))
+ assert.Equal(t, &eventspb.FeesStats{
+ Asset: testAsset,
+ TotalRewardsReceived: []*eventspb.PartyAmount{
+ {
+ Party: "party3",
+ Amount: "110",
+ QuantumAmount: "110",
+ },
+ },
+ ReferrerRewardsGenerated: []*eventspb.ReferrerRewardsGenerated{
+ {
+ Referrer: "party3",
+ GeneratedReward: []*eventspb.PartyAmount{
+ {
+ Party: "party1",
+ Amount: "110",
+ QuantumAmount: "110",
+ },
+ },
+ },
+ },
+ RefereesDiscountApplied: []*eventspb.PartyAmount{
+ {
+ Party: "party1",
+ Amount: "262",
+ QuantumAmount: "262",
+ },
+ },
+ VolumeDiscountApplied: []*eventspb.PartyAmount{
+ {
+ Party: "party1",
+ Amount: "60",
+ QuantumAmount: "60",
+ },
+ },
+ TotalMakerFeesReceived: []*eventspb.PartyAmount{
+ {
+ Party: "party2",
+ Amount: "64",
+ QuantumAmount: "64",
+ },
+ },
+ MakerFeesGenerated: []*eventspb.MakerFeesGenerated{
+ {
+ Taker: "party1",
+ MakerFeesPaid: []*eventspb.PartyAmount{
+ {
+ Party: "party2",
+ Amount: "64",
+ QuantumAmount: "64",
+ },
+ },
+ },
+ },
+ TotalFeesPaidAndReceived: []*eventspb.PartyAmount{
+ {
+ Party: "party1",
+ Amount: "443",
+ QuantumAmount: "443",
+ },
+ {
+ Party: "party2",
+ Amount: "64",
+ QuantumAmount: "64",
+ },
+ },
+ }, eng.GetFeesStatsOnEpochEnd(num.DecimalFromInt64(1)))
+}
+
func testCalcContinuousTradingAndCheckAmountsWithDiscountsAndRewardsBySide(t *testing.T, aggressorSide types.Side) {
t.Helper()
eng := getTestFee(t)
@@ -374,6 +763,8 @@ func testCalcContinuousTradingAndCheckAmountsWithDiscountsAndRewardsBySide(t *te
discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl)
volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl)
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes()
eng.UpdateFeeFactors(types.Fees{
Factors: &types.FeeFactors{
@@ -398,13 +789,29 @@ 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)
+ ft, err := eng.CalculateForContinuousMode(trades, discountRewardService, volumeDiscountService, volumeRebateService)
assert.NotNil(t, ft)
assert.Nil(t, err)
transfers := ft.Transfers()
@@ -466,6 +873,8 @@ func testCalcContinuousTradingAndCheckAmountsWithDiscountsAndRewardsBySideMultip
discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl)
volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl)
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes()
eng.UpdateFeeFactors(types.Fees{
Factors: &types.FeeFactors{
@@ -504,14 +913,30 @@ 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)
+ ft, err := eng.CalculateForContinuousMode(trades, discountRewardService, volumeDiscountService, volumeRebateService)
assert.NotNil(t, ft)
assert.Nil(t, err)
transfers := ft.Transfers()
@@ -639,9 +1064,11 @@ 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()
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(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{
@@ -682,7 +1109,7 @@ func testCalcContinuousTrading(t *testing.T) {
},
}
- ft, err := eng.CalculateForContinuousMode(trades, discountRewardService, volumeDiscountService)
+ ft, err := eng.CalculateForContinuousMode(trades, discountRewardService, volumeDiscountService, volumeRebateService)
assert.NotNil(t, ft)
assert.Nil(t, err)
@@ -716,12 +1143,121 @@ func testCalcContinuousTrading(t *testing.T) {
assert.Equal(t, pay, len(trades))
}
+func testCalcContinuousTradingExtended(t *testing.T) {
+ eng := getExtendedTestFee(t)
+ ctrl := gomock.NewController(t)
+ discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl)
+ volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl)
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(types.PartyID("party2")).Return(num.DecimalFromFloat(0.00005)).AnyTimes()
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(types.PartyID("party3")).Return(num.DecimalZero()).AnyTimes()
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(types.PartyID("party4")).Return(num.DecimalZero()).AnyTimes()
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(types.PartyID("party5")).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{
+ {
+ Aggressor: types.SideSell,
+ Seller: "party1",
+ Buyer: "party2",
+ Size: 10,
+ Price: num.NewUint(10000),
+ },
+ {
+ Aggressor: types.SideSell,
+ Seller: "party1",
+ Buyer: "party3",
+ Size: 1,
+ Price: num.NewUint(10300),
+ },
+ {
+ Aggressor: types.SideSell,
+ Seller: "party1",
+ Buyer: "party4",
+ Size: 7,
+ Price: num.NewUint(10300),
+ },
+ {
+ Aggressor: types.SideSell,
+ Seller: "party1",
+ Buyer: "party2",
+ Size: 2,
+ Price: num.NewUint(10500),
+ },
+ {
+ Aggressor: types.SideSell,
+ Seller: "party1",
+ Buyer: "party5",
+ Size: 5,
+ Price: num.NewUint(11000),
+ },
+ }
+
+ ft, err := eng.CalculateForContinuousMode(trades, discountRewardService, volumeDiscountService, volumeRebateService)
+ assert.NotNil(t, ft)
+ assert.Nil(t, err)
+
+ // get the amounts map
+ feeAmounts := ft.TotalFeesAmountPerParty()
+ party1Amount, ok := feeAmounts["party1"]
+ assert.True(t, ok)
+ assert.Equal(t, num.NewUint(43928), party1Amount)
+
+ // get the transfer and check we have enough of each types
+ transfers := ft.Transfers()
+ var pay, recv, infra, liquidity, highMakerPay, highMakerReceive, bb, treasury int
+ for _, v := range transfers {
+ if v.Type == types.TransferTypeLiquidityFeePay {
+ liquidity++
+ }
+ if v.Type == types.TransferTypeInfrastructureFeePay {
+ infra++
+ }
+ if v.Type == types.TransferTypeMakerFeeReceive {
+ recv++
+ }
+ if v.Type == types.TransferTypeMakerFeePay {
+ pay++
+ }
+ if v.Type == types.TransferTypeHighMakerRebatePay {
+ highMakerPay++
+ }
+ if v.Type == types.TransferTypeHighMakerRebateReceive {
+ highMakerReceive++
+ }
+ if v.Type == types.TransferTypeBuyBackFeePay {
+ bb++
+ }
+ if v.Type == types.TransferTypeTreasuryPay {
+ treasury++
+ }
+ }
+
+ assert.Equal(t, liquidity, 1)
+ assert.Equal(t, infra, 1)
+ assert.Equal(t, highMakerPay, 2)
+ assert.Equal(t, highMakerReceive, 2)
+ assert.Equal(t, recv, len(trades))
+ assert.Equal(t, pay, len(trades))
+ assert.Equal(t, bb, len(trades))
+ assert.Equal(t, treasury, len(trades))
+}
+
func testCalcAuctionTradingErrorEmptyTrade(t *testing.T) {
eng := getTestFee(t)
ctrl := gomock.NewController(t)
discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl)
volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl)
- _, err := eng.CalculateForAuctionMode([]*types.Trade{}, discountRewardService, volumeDiscountService)
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes()
+ _, err := eng.CalculateForAuctionMode([]*types.Trade{}, discountRewardService, volumeDiscountService, volumeRebateService)
+ assert.EqualError(t, err, fee.ErrEmptyTrades.Error())
+
+ eng = getExtendedTestFee(t)
+ _, err = eng.CalculateForAuctionMode([]*types.Trade{}, discountRewardService, volumeDiscountService, volumeRebateService)
assert.EqualError(t, err, fee.ErrEmptyTrades.Error())
}
@@ -730,9 +1266,11 @@ 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()
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(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{
{
@@ -744,7 +1282,7 @@ func testCalcAuctionTrading(t *testing.T) {
},
}
- ft, err := eng.CalculateForAuctionMode(trades, discountRewardService, volumeDiscountService)
+ ft, err := eng.CalculateForAuctionMode(trades, discountRewardService, volumeDiscountService, volumeRebateService)
assert.NotNil(t, ft)
assert.Nil(t, err)
@@ -785,23 +1323,115 @@ func testCalcAuctionTrading(t *testing.T) {
assert.Equal(t, pay, 0)
}
+func testCalcAuctionTradingExtended(t *testing.T) {
+ eng := getExtendedTestFee(t)
+ ctrl := gomock.NewController(t)
+ discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl)
+ volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl)
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalFromFloat(0.0025)).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{
+ {
+ Aggressor: types.SideSell,
+ Seller: "party1",
+ Buyer: "party2",
+ Size: 1,
+ Price: num.NewUint(100),
+ },
+ }
+
+ ft, err := eng.CalculateForAuctionMode(trades, discountRewardService, volumeDiscountService, volumeRebateService)
+ assert.NotNil(t, ft)
+ assert.Nil(t, err)
+
+ // get the amounts map
+ feeAmounts := ft.TotalFeesAmountPerParty()
+ // fees are (100 * 0.1 + 100 * 0.05) = 15
+ // 15 / 2 = 7.5
+ // internally the engine Ceil all fees.
+ // so here we will expect 8 for each
+ party1Amount, ok := feeAmounts["party1"]
+ assert.True(t, ok)
+ assert.Equal(t, num.NewUint(8), party1Amount)
+ party2Amount, ok := feeAmounts["party2"]
+ assert.True(t, ok)
+ assert.Equal(t, num.NewUint(8), party2Amount)
+
+ // get the transfer and check we have enough of each types
+ transfers := ft.Transfers()
+ var pay, recv, infra, liquidity, hmp, hmr, bb, treasury int
+ for _, v := range transfers {
+ if v.Type == types.TransferTypeLiquidityFeePay {
+ liquidity++
+ }
+ if v.Type == types.TransferTypeInfrastructureFeePay {
+ infra++
+ }
+ if v.Type == types.TransferTypeMakerFeeReceive {
+ recv++
+ }
+ if v.Type == types.TransferTypeMakerFeePay {
+ pay++
+ }
+ if v.Type == types.TransferTypeHighMakerRebatePay {
+ hmp++
+ }
+ if v.Type == types.TransferTypeHighMakerRebateReceive {
+ hmr++
+ }
+ if v.Type == types.TransferTypeBuyBackFeePay {
+ bb++
+ }
+ if v.Type == types.TransferTypeTreasuryPay {
+ treasury++
+ }
+ }
+
+ assert.Equal(t, 2, liquidity)
+ assert.Equal(t, 2, infra)
+ assert.Equal(t, 0, recv)
+ assert.Equal(t, 0, pay)
+ assert.Equal(t, 0, hmp)
+ assert.Equal(t, 0, hmr)
+ assert.Equal(t, 2, bb)
+ assert.Equal(t, 2, treasury)
+}
+
func TestCalcAuctionTradingWithDiscountsAndRewards(t *testing.T) {
eng := getTestFee(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 {
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes()
+ 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 +1441,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{
{
@@ -824,7 +1458,7 @@ func TestCalcAuctionTradingWithDiscountsAndRewards(t *testing.T) {
},
}
- ft, err := eng.CalculateForAuctionMode(trades, discountRewardService, volumeDiscountService)
+ ft, err := eng.CalculateForAuctionMode(trades, discountRewardService, volumeDiscountService, volumeRebateService)
assert.NotNil(t, ft)
assert.Nil(t, err)
@@ -898,7 +1532,13 @@ func testCalcBatchAuctionTradingErrorEmptyTrade(t *testing.T) {
ctrl := gomock.NewController(t)
discountRewardService := mocks.NewMockReferralDiscountRewardService(ctrl)
volumeDiscountService := mocks.NewMockVolumeDiscountService(ctrl)
- _, err := eng.CalculateForFrequentBatchesAuctionMode([]*types.Trade{}, discountRewardService, volumeDiscountService)
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(gomock.Any()).Return(num.DecimalZero()).AnyTimes()
+ _, err := eng.CalculateForFrequentBatchesAuctionMode([]*types.Trade{}, discountRewardService, volumeDiscountService, volumeRebateService)
+ assert.EqualError(t, err, fee.ErrEmptyTrades.Error())
+
+ eng = getExtendedTestFee(t)
+ _, err = eng.CalculateForFrequentBatchesAuctionMode([]*types.Trade{}, discountRewardService, volumeDiscountService, volumeRebateService)
assert.EqualError(t, err, fee.ErrEmptyTrades.Error())
}
@@ -907,9 +1547,11 @@ 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()
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(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{
{
@@ -923,7 +1565,7 @@ func testCalcBatchAuctionTradingSameBatch(t *testing.T) {
},
}
- ft, err := eng.CalculateForFrequentBatchesAuctionMode(trades, discountRewardService, volumeDiscountService)
+ ft, err := eng.CalculateForFrequentBatchesAuctionMode(trades, discountRewardService, volumeDiscountService, volumeRebateService)
assert.NotNil(t, ft)
assert.Nil(t, err)
@@ -969,9 +1611,11 @@ 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()
+ volumeRebateService := mocks.NewMockVolumeRebateService(ctrl)
+ volumeRebateService.EXPECT().VolumeRebateFactorForParty(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{
{
@@ -985,7 +1629,7 @@ func testCalcBatchAuctionTradingDifferentBatches(t *testing.T) {
},
}
- ft, err := eng.CalculateForFrequentBatchesAuctionMode(trades, discountRewardService, volumeDiscountService)
+ ft, err := eng.CalculateForFrequentBatchesAuctionMode(trades, discountRewardService, volumeDiscountService, volumeRebateService)
assert.NotNil(t, ft)
assert.Nil(t, err)
@@ -1028,9 +1672,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 +1711,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..b6cbae9005c 100644
--- a/core/fee/mocks/mocks.go
+++ b/core/fee/mocks/mocks.go
@@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT.
-// Source: code.vegaprotocol.io/vega/core/fee (interfaces: ReferralDiscountRewardService,VolumeDiscountService)
+// Source: code.vegaprotocol.io/vega/core/fee (interfaces: ReferralDiscountRewardService,VolumeDiscountService,VolumeRebateService)
// Package mocks is a generated GoMock package.
package mocks
@@ -50,32 +50,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 +102,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
}
@@ -114,3 +114,40 @@ func (mr *MockVolumeDiscountServiceMockRecorder) VolumeDiscountFactorForParty(ar
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VolumeDiscountFactorForParty", reflect.TypeOf((*MockVolumeDiscountService)(nil).VolumeDiscountFactorForParty), arg0)
}
+
+// MockVolumeRebateService is a mock of VolumeRebateService interface.
+type MockVolumeRebateService struct {
+ ctrl *gomock.Controller
+ recorder *MockVolumeRebateServiceMockRecorder
+}
+
+// MockVolumeRebateServiceMockRecorder is the mock recorder for MockVolumeRebateService.
+type MockVolumeRebateServiceMockRecorder struct {
+ mock *MockVolumeRebateService
+}
+
+// NewMockVolumeRebateService creates a new mock instance.
+func NewMockVolumeRebateService(ctrl *gomock.Controller) *MockVolumeRebateService {
+ mock := &MockVolumeRebateService{ctrl: ctrl}
+ mock.recorder = &MockVolumeRebateServiceMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockVolumeRebateService) EXPECT() *MockVolumeRebateServiceMockRecorder {
+ return m.recorder
+}
+
+// VolumeRebateFactorForParty mocks base method.
+func (m *MockVolumeRebateService) VolumeRebateFactorForParty(arg0 types.PartyID) decimal.Decimal {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "VolumeRebateFactorForParty", arg0)
+ ret0, _ := ret[0].(decimal.Decimal)
+ return ret0
+}
+
+// VolumeRebateFactorForParty indicates an expected call of VolumeRebateFactorForParty.
+func (mr *MockVolumeRebateServiceMockRecorder) VolumeRebateFactorForParty(arg0 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VolumeRebateFactorForParty", reflect.TypeOf((*MockVolumeRebateService)(nil).VolumeRebateFactorForParty), arg0)
+}
diff --git a/core/governance/engine.go b/core/governance/engine.go
index 87c8fc57446..ece08bc28aa 100644
--- a/core/governance/engine.go
+++ b/core/governance/engine.go
@@ -296,6 +296,8 @@ func (e *Engine) preEnactProposal(ctx context.Context, p *proposal) (te *ToEnact
te.referralProgramChanges = updatedReferralProgramFromProposal(p)
case types.ProposalTermsTypeUpdateVolumeDiscountProgram:
te.volumeDiscountProgram = updatedVolumeDiscountProgramFromProposal(p)
+ case types.ProposalTermsTypeUpdateVolumeRebateProgram:
+ te.volumeRebateProgram = updatedVolumeRebateProgramFromProposal(p)
}
return //nolint:nakedret
}
@@ -741,6 +743,8 @@ func (e *Engine) getProposalParams(proposalTerm types.ProposalTerm) (*types.Prop
return e.getReferralProgramNetworkParameters(), nil
case types.ProposalTermsTypeUpdateVolumeDiscountProgram:
return e.getVolumeDiscountProgramNetworkParameters(), nil
+ case types.ProposalTermsTypeUpdateVolumeRebateProgram:
+ return e.getVolumeRebateProgramNetworkParameters(), nil
default:
return nil, ErrUnsupportedProposalType
}
@@ -1091,6 +1095,8 @@ func (e *Engine) validateChange(terms *types.ProposalTerms) (types.ProposalError
return validateUpdateReferralProgram(e.netp, terms.GetUpdateReferralProgram(), terms.EnactmentTimestamp)
case types.ProposalTermsTypeUpdateVolumeDiscountProgram:
return validateUpdateVolumeDiscountProgram(e.netp, terms.GetUpdateVolumeDiscountProgram())
+ case types.ProposalTermsTypeUpdateVolumeRebateProgram:
+ return validateUpdateVolumeRebateProgram(e.netp, terms.GetUpdateVolumeRebateProgram())
default:
return types.ProposalErrorUnspecified, nil
}
diff --git a/core/governance/engine_test.go b/core/governance/engine_test.go
index 04bf7958afa..0485dc06452 100644
--- a/core/governance/engine_test.go
+++ b/core/governance/engine_test.go
@@ -2207,6 +2207,30 @@ func (e *tstEngine) newProposalForReferralProgramUpdate(partyID string, now time
return prop
}
+func (e *tstEngine) newProposalForVolumeRebateProgramUpdate(partyID string, now time.Time, configuration *types.VolumeRebateProgramChanges) types.Proposal {
+ id := e.newProposalID()
+ prop := types.Proposal{
+ ID: id,
+ Reference: "ref-" + id,
+ Party: partyID,
+ State: types.ProposalStateOpen,
+ Terms: &types.ProposalTerms{
+ ClosingTimestamp: now.Add(96 * time.Hour).Unix(),
+ EnactmentTimestamp: now.Add(4 * 48 * time.Hour).Unix(),
+ ValidationTimestamp: now.Add(2 * time.Hour).Unix(),
+ Change: &types.ProposalTermsUpdateVolumeRebateProgram{
+ UpdateVolumeRebateProgram: &types.UpdateVolumeRebateProgram{
+ Changes: configuration,
+ },
+ },
+ },
+ Rationale: &types.ProposalRationale{
+ Description: "some description",
+ },
+ }
+ return prop
+}
+
func (e *tstEngine) newProposalForVolumeDiscountProgramUpdate(partyID string, now time.Time, configuration *types.VolumeDiscountProgramChanges) types.Proposal {
id := e.newProposalID()
prop := types.Proposal{
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/engine_update_volume_rebate_program_test.go b/core/governance/engine_update_volume_rebate_program_test.go
new file mode 100644
index 00000000000..bedf365229b
--- /dev/null
+++ b/core/governance/engine_update_volume_rebate_program_test.go
@@ -0,0 +1,172 @@
+// Copyright (C) 2023 Gobalsky Labs Limited
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package governance_test
+
+import (
+ "testing"
+ "time"
+
+ "code.vegaprotocol.io/vega/core/events"
+ "code.vegaprotocol.io/vega/core/netparams"
+ "code.vegaprotocol.io/vega/core/types"
+ "code.vegaprotocol.io/vega/libs/num"
+ vgrand "code.vegaprotocol.io/vega/libs/rand"
+ vgtest "code.vegaprotocol.io/vega/libs/test"
+
+ "github.com/golang/mock/gomock"
+ "github.com/stretchr/testify/require"
+)
+
+func TestProposalForUpdateVolumeRebateProgram(t *testing.T) {
+ t.Run("Submitting a proposal for referral program update succeeds", testSubmittingProposalForVolumeRebateProgramUpdateSucceeds)
+ t.Run("Submitting a proposal for referral program update with too many tiers fails", testSubmittingProposalForVolumeRebateProgramUpdateWithTooManyTiersFails)
+ t.Run("Submitting a proposal for referral program update with too high rebate factor fails", testSubmittingProposalForVolumeRebateProgramUpdateWithTooHighRebateFactorFails)
+}
+
+func testSubmittingProposalForVolumeRebateProgramUpdateSucceeds(t *testing.T) {
+ now := time.Now()
+ ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64())
+ eng := getTestEngine(t, now)
+
+ // setup
+ eng.broker.EXPECT().Send(gomock.Any()).Times(3)
+ eng.netp.Update(ctx, netparams.GovernanceProposalVolumeRebateProgramMinClose, "48h")
+ eng.netp.Update(ctx, netparams.GovernanceProposalVolumeRebateProgramMinEnact, "48h")
+ eng.netp.Update(ctx, netparams.GovernanceProposalVolumeRebateProgramMinProposerBalance, "1000")
+
+ eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.VolumeRebateProgramMaxBenefitTiers, "2")).Times(1)
+ require.NoError(t, eng.netp.Update(ctx, netparams.VolumeRebateProgramMaxBenefitTiers, "2"))
+
+ // given
+ proposer := vgrand.RandomStr(5)
+ proposal := eng.newProposalForVolumeRebateProgramUpdate(proposer, now, &types.VolumeRebateProgramChanges{
+ EndOfProgramTimestamp: now.Add(4 * 48 * time.Hour),
+ WindowLength: 15,
+ VolumeRebateBenefitTiers: []*types.VolumeRebateBenefitTier{
+ {
+ MinimumPartyMakerVolumeFraction: num.DecimalFromFloat(0.1),
+ AdditionalMakerRebate: num.DecimalFromFloat(0.00001),
+ }, {
+ MinimumPartyMakerVolumeFraction: num.DecimalFromFloat(0.2),
+ AdditionalMakerRebate: num.DecimalFromFloat(0.00002),
+ },
+ },
+ })
+
+ // setup
+ eng.ensureTokenBalanceForParty(t, proposer, 1000)
+
+ // expect
+ eng.expectOpenProposalEvent(t, proposer, proposal.ID)
+
+ // when
+ toSubmit, err := eng.submitProposal(t, proposal)
+
+ // then
+ require.NoError(t, err)
+ require.NotNil(t, toSubmit)
+}
+
+func testSubmittingProposalForVolumeRebateProgramUpdateWithTooManyTiersFails(t *testing.T) {
+ now := time.Now()
+ ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64())
+ eng := getTestEngine(t, now)
+
+ // setup
+ eng.broker.EXPECT().Send(gomock.Any()).Times(3)
+ eng.netp.Update(ctx, netparams.GovernanceProposalVolumeRebateProgramMinClose, "48h")
+ eng.netp.Update(ctx, netparams.GovernanceProposalVolumeRebateProgramMinEnact, "48h")
+ eng.netp.Update(ctx, netparams.GovernanceProposalVolumeRebateProgramMinProposerBalance, "1000")
+
+ eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.VolumeRebateProgramMaxBenefitTiers, "1")).Times(1)
+ require.NoError(t, eng.netp.Update(ctx, netparams.VolumeRebateProgramMaxBenefitTiers, "1"))
+
+ // given
+ proposer := vgrand.RandomStr(5)
+ proposal := eng.newProposalForVolumeRebateProgramUpdate(proposer, now, &types.VolumeRebateProgramChanges{
+ EndOfProgramTimestamp: now.Add(4 * 48 * time.Hour),
+ WindowLength: 15,
+ VolumeRebateBenefitTiers: []*types.VolumeRebateBenefitTier{
+ {
+ MinimumPartyMakerVolumeFraction: num.DecimalFromFloat(0.1),
+ AdditionalMakerRebate: num.DecimalFromFloat(0.001),
+ }, {
+ MinimumPartyMakerVolumeFraction: num.DecimalFromFloat(0.2),
+ AdditionalMakerRebate: num.DecimalFromFloat(0.002),
+ },
+ },
+ })
+
+ // setup
+ eng.ensureTokenBalanceForParty(t, proposer, 1000)
+
+ // expect
+ eng.expectRejectedProposalEvent(t, proposer, proposal.ID, types.ProposalErrorInvalidVolumeRebateProgram)
+
+ // when
+ toSubmit, err := eng.submitProposal(t, proposal)
+
+ // then
+ require.Error(t, err)
+ require.Nil(t, toSubmit)
+}
+
+func testSubmittingProposalForVolumeRebateProgramUpdateWithTooHighRebateFactorFails(t *testing.T) {
+ now := time.Now()
+ ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64())
+ eng := getTestEngine(t, now)
+
+ // setup
+ eng.broker.EXPECT().Send(gomock.Any()).Times(3)
+ eng.netp.Update(ctx, netparams.GovernanceProposalVolumeRebateProgramMinClose, "48h")
+ eng.netp.Update(ctx, netparams.GovernanceProposalVolumeRebateProgramMinEnact, "48h")
+ eng.netp.Update(ctx, netparams.GovernanceProposalVolumeRebateProgramMinProposerBalance, "1000")
+
+ eng.broker.EXPECT().Send(events.NewNetworkParameterEvent(ctx, netparams.VolumeRebateProgramMaxBenefitTiers, "2")).Times(1)
+ require.NoError(t, eng.netp.Update(ctx, netparams.VolumeRebateProgramMaxBenefitTiers, "2"))
+
+ // given
+ proposer := vgrand.RandomStr(5)
+ proposal := eng.newProposalForVolumeRebateProgramUpdate(proposer, now, &types.VolumeRebateProgramChanges{
+ EndOfProgramTimestamp: now.Add(4 * 48 * time.Hour),
+ WindowLength: 15,
+ VolumeRebateBenefitTiers: []*types.VolumeRebateBenefitTier{
+ {
+ MinimumPartyMakerVolumeFraction: num.DecimalFromFloat(0.1),
+ AdditionalMakerRebate: num.DecimalFromFloat(0.01),
+ }, {
+ MinimumPartyMakerVolumeFraction: num.DecimalFromFloat(0.2),
+ AdditionalMakerRebate: num.DecimalFromFloat(0.02),
+ },
+ },
+ })
+
+ // setup
+ eng.ensureTokenBalanceForParty(t, proposer, 1000)
+
+ // expect
+ eng.expectRejectedProposalEvent(t, proposer, proposal.ID, types.ProposalErrorInvalidVolumeRebateProgram)
+
+ // when
+ toSubmit, err := eng.submitProposal(t, proposal)
+
+ // then
+ require.EqualError(t,
+ err,
+ "tier 1 defines an additional rebate factor higher than the maximum allowed by the network parameters: maximum is (0.0001+0.0001), but got 0.01",
+ )
+ require.Nil(t, toSubmit)
+}
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..8b1db22757a 100644
--- a/core/governance/market_cp_restore_test.go
+++ b/core/governance/market_cp_restore_test.go
@@ -201,19 +201,20 @@ func createExecutionEngine(t *testing.T, tm time.Time) (*execution.Engine, *gove
asset, _ := assets.New(context.Background(), log, assets.NewDefaultConfig(), getNodeWallet().Ethereum, nil, nil, broker, primaryBridgeView, secondaryBridgeView, notary, false)
teams := emocks.NewMockTeams(ctrl)
bc := emocks.NewMockAccountBalanceChecker(ctrl)
- marketTracker := common.NewMarketActivityTracker(log, teams, bc, broker)
+ marketTracker := common.NewMarketActivityTracker(log, teams, bc, broker, collateralService)
epochEngine.NotifyOnEpoch(marketTracker.OnEpochEvent, marketTracker.OnEpochRestore)
referralDiscountReward := fmocks.NewMockReferralDiscountRewardService(ctrl)
volumeDiscount := fmocks.NewMockVolumeDiscountService(ctrl)
+ volumeRebateService := fmocks.NewMockVolumeRebateService(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)
delayTarget := emocks.NewMockDelayTransactionsTarget(ctrl)
delayTarget.EXPECT().MarketDelayRequiredUpdated(gomock.Any(), gomock.Any()).AnyTimes()
- exec := execution.NewEngine(log, executionConfig, timeService, collateralService, oracleService, broker, statevar, marketTracker, asset, referralDiscountReward, volumeDiscount, execBanking, parties, delayTarget)
+ exec := execution.NewEngine(log, executionConfig, timeService, collateralService, oracleService, broker, statevar, marketTracker, asset, referralDiscountReward, volumeDiscount, volumeRebateService, execBanking, parties, delayTarget)
accounts := mocks.NewMockStakingAccounts(ctrl)
witness := mocks.NewMockWitness(ctrl)
diff --git a/core/governance/netparams.go b/core/governance/netparams.go
index 8075af2561a..2b5426496bb 100644
--- a/core/governance/netparams.go
+++ b/core/governance/netparams.go
@@ -139,6 +139,22 @@ func (e *Engine) getVolumeDiscountProgramNetworkParameters() *types.ProposalPara
)
}
+func (e *Engine) getVolumeRebateProgramNetworkParameters() *types.ProposalParameters {
+ return e.getProposalParametersFromNetParams(
+ netparams.GovernanceProposalVolumeRebateProgramMinClose,
+ netparams.GovernanceProposalVolumeRebateProgramMaxClose,
+ netparams.GovernanceProposalVolumeRebateProgramMinEnact,
+ netparams.GovernanceProposalVolumeRebateProgramMaxEnact,
+ netparams.GovernanceProposalVolumeRebateProgramRequiredParticipation,
+ netparams.GovernanceProposalVolumeRebateProgramRequiredMajority,
+ netparams.GovernanceProposalVolumeRebateProgramMinProposerBalance,
+ netparams.GovernanceProposalVolumeRebateProgramMinVoterBalance,
+ "0",
+ "0",
+ "0",
+ )
+}
+
func (e *Engine) getNewAssetProposalParameters() *types.ProposalParameters {
return e.getProposalParametersFromNetParams(
netparams.GovernanceProposalAssetMinClose,
diff --git a/core/governance/proposal.go b/core/governance/proposal.go
index 3ab67c7c7b1..fd2a1339afb 100644
--- a/core/governance/proposal.go
+++ b/core/governance/proposal.go
@@ -255,6 +255,7 @@ type ToEnact struct {
msu *ToEnactMarketStateUpdate
referralProgramChanges *types.ReferralProgram
volumeDiscountProgram *types.VolumeDiscountProgram
+ volumeRebateProgram *types.VolumeRebateProgram
}
type ToEnactMarketStateUpdate struct{}
@@ -278,6 +279,10 @@ func (t ToEnact) IsVolumeDiscountProgramUpdate() bool {
return t.volumeDiscountProgram != nil
}
+func (t ToEnact) IsVolumeRebateProgramUpdate() bool {
+ return t.volumeRebateProgram != nil
+}
+
func (t ToEnact) IsReferralProgramUpdate() bool {
return t.referralProgramChanges != nil
}
@@ -363,6 +368,10 @@ func (t *ToEnact) VolumeDiscountProgramUpdate() *types.VolumeDiscountProgram {
return t.volumeDiscountProgram
}
+func (t *ToEnact) VolumeRebateProgramUpdate() *types.VolumeRebateProgram {
+ return t.volumeRebateProgram
+}
+
func (t *ToEnact) UpdateMarket() *types.Market {
return t.updatedMarket
}
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/governance/volume_rebate_program.go b/core/governance/volume_rebate_program.go
new file mode 100644
index 00000000000..7760f45e090
--- /dev/null
+++ b/core/governance/volume_rebate_program.go
@@ -0,0 +1,53 @@
+// Copyright (C) 2023 Gobalsky Labs Limited
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package governance
+
+import (
+ "fmt"
+
+ "code.vegaprotocol.io/vega/core/netparams"
+ "code.vegaprotocol.io/vega/core/types"
+)
+
+func validateUpdateVolumeRebateProgram(netp NetParams, p *types.UpdateVolumeRebateProgram) (types.ProposalError, error) {
+ maxTiers, _ := netp.GetUint(netparams.VolumeRebateProgramMaxBenefitTiers)
+ if len(p.Changes.VolumeRebateBenefitTiers) > int(maxTiers.Uint64()) {
+ return types.ProposalErrorInvalidVolumeRebateProgram, fmt.Errorf("the number of tiers in the proposal is higher than the maximum allowed by the network parameter %q: maximum is %s, but got %d", netparams.VolumeRebateProgramMaxBenefitTiers, maxTiers.String(), len(p.Changes.VolumeRebateBenefitTiers))
+ }
+
+ treasuryFee, _ := netp.GetDecimal(netparams.MarketFeeFactorsTreasuryFee)
+ buybackFee, _ := netp.GetDecimal(netparams.MarketFeeFactorsBuyBackFee)
+ maxRebate := treasuryFee.Add(buybackFee)
+
+ for i, tier := range p.Changes.VolumeRebateBenefitTiers {
+ if tier.AdditionalMakerRebate.GreaterThan(maxRebate) {
+ return types.ProposalErrorInvalidVolumeRebateProgram, fmt.Errorf("tier %d defines an additional rebate factor higher than the maximum allowed by the network parameters: maximum is (%s+%s), but got %s", i+1, buybackFee.String(), treasuryFee.String(), tier.AdditionalMakerRebate.String())
+ }
+ }
+ return 0, nil
+}
+
+func updatedVolumeRebateProgramFromProposal(p *proposal) *types.VolumeRebateProgram {
+ terms := p.Terms.GetUpdateVolumeRebateProgram()
+
+ return &types.VolumeRebateProgram{
+ ID: p.ID,
+ Version: terms.Changes.Version,
+ EndOfProgramTimestamp: terms.Changes.EndOfProgramTimestamp,
+ WindowLength: terms.Changes.WindowLength,
+ VolumeRebateBenefitTiers: terms.Changes.VolumeRebateBenefitTiers,
+ }
+}
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