Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hvmr coverage #11678

Merged
merged 6 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion commands/proposal_submission.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ func checkVolumeRebateProgramChanges(changes *vegapb.VolumeRebateProgramChanges,

func checkVolumeRebateBenefitTier(index int, tier *vegapb.VolumeRebateBenefitTier) Errors {
errs := NewErrors()
propertyPath := fmt.Sprintf("update_volume_discount_program.changes.benefit_tiers.%d", index)
propertyPath := fmt.Sprintf("update_volume_rebate_program.changes.benefit_tiers.%d", index)
if len(tier.MinimumPartyMakerVolumeFraction) == 0 {
errs.AddForProperty(propertyPath+".minimum_party_maker_volume_fraction", ErrIsRequired)
} else {
Expand Down
173 changes: 173 additions & 0 deletions commands/proposal_submission_update_rebate_program_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// 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 <http://www.gnu.org/licenses/>.

package commands_test

import (
"testing"
"time"

"code.vegaprotocol.io/vega/commands"
types "code.vegaprotocol.io/vega/protos/vega"
commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1"

"github.com/stretchr/testify/assert"
)

func TestVolumeRebateSubmission(t *testing.T) {
t.Run("empty submission", testUpdateRebateProgram)
t.Run("0095-HVMR-001: invalid end timestamp", testInvalidEndTime)
t.Run("0095-HVMR-003: tier validation", testInvalidTiers)
t.Run("0095-HVMR-004: invalid window length", testInvalidWindowLength)
}

func testUpdateRebateProgram(t *testing.T) {
err := checkProposalSubmission(&commandspb.ProposalSubmission{
Terms: &types.ProposalTerms{
Change: &types.ProposalTerms_UpdateVolumeRebateProgram{},
},
})

assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_rebate_program"), commands.ErrIsRequired)
// missing changes, same problem
err = checkProposalSubmission(&commandspb.ProposalSubmission{
Terms: &types.ProposalTerms{
Change: &types.ProposalTerms_UpdateVolumeRebateProgram{
UpdateVolumeRebateProgram: &types.UpdateVolumeRebateProgram{},
},
},
})

assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_rebate_program.changes"), commands.ErrIsRequired)
}

// testInvalidEndTime covers 0095-HVMR-001.
func testInvalidEndTime(t *testing.T) {
end := time.Now()
enact := end.Add(time.Second)
prop := &commandspb.ProposalSubmission{
Terms: &types.ProposalTerms{
EnactmentTimestamp: enact.Unix(),
Change: &types.ProposalTerms_UpdateVolumeRebateProgram{
UpdateVolumeRebateProgram: &types.UpdateVolumeRebateProgram{
Changes: &types.VolumeRebateProgramChanges{
EndOfProgramTimestamp: end.Unix(),
},
},
},
},
}
err := checkProposalSubmission(prop)
assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_rebate_program.changes.end_of_program_timestamp"), commands.ErrMustBeGreaterThanEnactmentTimestamp)
}

// testInvalidWindowLength covers 0095-HVMR-004.
func testInvalidWindowLength(t *testing.T) {
enact := time.Now()
end := enact.Add(time.Second)
prop := &commandspb.ProposalSubmission{
Terms: &types.ProposalTerms{
EnactmentTimestamp: enact.Unix(),
Change: &types.ProposalTerms_UpdateVolumeRebateProgram{
UpdateVolumeRebateProgram: &types.UpdateVolumeRebateProgram{
Changes: &types.VolumeRebateProgramChanges{
EndOfProgramTimestamp: end.Unix(),
WindowLength: 0, // zero is invalid
},
},
},
},
}
err := checkProposalSubmission(prop)
assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_rebate_program.changes.window_length"), commands.ErrIsRequired)
// now too high of a value
prop = &commandspb.ProposalSubmission{
Terms: &types.ProposalTerms{
EnactmentTimestamp: enact.Unix(),
Change: &types.ProposalTerms_UpdateVolumeRebateProgram{
UpdateVolumeRebateProgram: &types.UpdateVolumeRebateProgram{
Changes: &types.VolumeRebateProgramChanges{
EndOfProgramTimestamp: end.Unix(),
WindowLength: 10000,
},
},
},
},
}
err = checkProposalSubmission(prop)
assert.Contains(t, err.Get("proposal_submission.terms.change.update_volume_rebate_program.changes.window_length"), commands.ErrMustBeAtMost200)
}

// testInvalidTiers covers 0095-HVMR-003.
func testInvalidTiers(t *testing.T) {
errMap := map[string]error{
"proposal_submission.terms.change.update_volume_rebate_program.changes.benefit_tiers.0.minimum_party_maker_volume_fraction": commands.ErrIsRequired,
"proposal_submission.terms.change.update_volume_rebate_program.changes.benefit_tiers.1.minimum_party_maker_volume_fraction": commands.ErrIsNotValidNumber,
"proposal_submission.terms.change.update_volume_rebate_program.changes.benefit_tiers.2.minimum_party_maker_volume_fraction": commands.ErrMustBePositive,
"proposal_submission.terms.change.update_volume_rebate_program.changes.benefit_tiers.3.minimum_party_maker_volume_fraction": commands.ErrMustBePositive,
"proposal_submission.terms.change.update_volume_rebate_program.changes.benefit_tiers.4.additional_maker_rebate": commands.ErrIsRequired,
"proposal_submission.terms.change.update_volume_rebate_program.changes.benefit_tiers.5.additional_maker_rebate": commands.ErrIsNotValidNumber,
"proposal_submission.terms.change.update_volume_rebate_program.changes.benefit_tiers.6.additional_maker_rebate": commands.ErrMustBePositiveOrZero,
}
enact := time.Now()
end := enact.Add(time.Second)
prop := &commandspb.ProposalSubmission{
Terms: &types.ProposalTerms{
EnactmentTimestamp: enact.Unix(),
Change: &types.ProposalTerms_UpdateVolumeRebateProgram{
UpdateVolumeRebateProgram: &types.UpdateVolumeRebateProgram{
Changes: &types.VolumeRebateProgramChanges{
EndOfProgramTimestamp: end.Unix(),
WindowLength: 10,
BenefitTiers: []*types.VolumeRebateBenefitTier{
{
MinimumPartyMakerVolumeFraction: "",
AdditionalMakerRebate: "0.1",
},
{
MinimumPartyMakerVolumeFraction: "invalid",
AdditionalMakerRebate: "0.1",
},
{
MinimumPartyMakerVolumeFraction: "-1",
AdditionalMakerRebate: "0.1",
},
{
MinimumPartyMakerVolumeFraction: "0",
AdditionalMakerRebate: "0.1",
},
{
MinimumPartyMakerVolumeFraction: "0.1",
AdditionalMakerRebate: "",
},
{
MinimumPartyMakerVolumeFraction: "0.1",
AdditionalMakerRebate: "invalid",
},
{
MinimumPartyMakerVolumeFraction: "0.1",
AdditionalMakerRebate: "-0.1",
},
},
},
},
},
},
}
err := checkProposalSubmission(prop)
for g, c := range errMap {
assert.Contains(t, err.Get(g), c, err.Error())
}
}
2 changes: 2 additions & 0 deletions core/governance/engine_update_referral_program_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ func testSubmittingProposalForReferralProgramUpdateSucceeds(t *testing.T) {
require.NotNil(t, toSubmit)
}

// testSubmittingProposalForReferralProgramUpdateWithTooManyTiersFails covers 0095-HVMR-002.
func testSubmittingProposalForReferralProgramUpdateWithTooManyTiersFails(t *testing.T) {
now := time.Now()
ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64())
Expand Down Expand Up @@ -324,6 +325,7 @@ func testSubmittingProposalForReferralProgramUpdateWithTooHighDiscountFactorFail
require.Nil(t, toSubmit)
}

// testSubmittingProposalForReferralProgramUpdateEndsBeforeEnactsFails covers 0095-HVMR-001.
func testSubmittingProposalForReferralProgramUpdateEndsBeforeEnactsFails(t *testing.T) {
now := time.Now()
ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomPositiveI64())
Expand Down
118 changes: 118 additions & 0 deletions core/integration/features/verified/finite-rewards.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
Feature: Team Rewards

Setup a maker fees received team game with a fee cap.

We want to make it so that one team is allocated rewards and the other team is allocated rewards.

- Team A should have also paid rewards and not have their rewards capped.
- Team B should not have paid rewards and have their rewards capped.

Question is what happens to the left over rewards.


Background:

And the average block duration is "1"
And the following network parameters are set:
| name | value |
| referralProgram.minStakedVegaTokens | 0 |
| market.fee.factors.makerFee | 0.01 |
| network.markPriceUpdateMaximumFrequency | 0s |
| validators.epoch.length | 60s |

# Initialise the markets
And the following assets are registered:
| id | decimal places | quantum |
| USD-0-1 | 0 | 1 |
And the markets:
| id | quote name | asset | risk model | margin calculator | auction duration | fees | price monitoring | data source config | linear slippage factor | quadratic slippage factor | sla params | decimal places | position decimal places |
| ETH/USD-0-1 | ETH | USD-0-1 | default-log-normal-risk-model | default-margin-calculator | 1 | default-none | default-none | default-eth-for-future | 1e-3 | 0 | default-futures | 0 | 0 |

# Initialise the parties
Given the parties deposit on asset's general account the following amount:
| party | asset | amount |
| aux1 | USD-0-1 | 1000000000000 |
| aux2 | USD-0-1 | 1000000000000 |
| party1 | USD-0-1 | 1000000000000 |
| party2 | USD-0-1 | 1000000000000 |
| a3c024b4e23230c89884a54a813b1ecb4cb0f827a38641c66eeca466da6b2ddf | USD-0-1 | 1000000000000 |

# Exit opening auctions
When the parties place the following orders:
| party | market id | side | volume | price | resulting trades | type | tif |
| aux1 | ETH/USD-0-1 | buy | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC |
| aux2 | ETH/USD-0-1 | sell | 1 | 1000 | 0 | TYPE_LIMIT | TIF_GTC |
And the opening auction period ends for market "ETH/USD-0-1"
And the trading mode should be "TRADING_MODE_CONTINUOUS" for the market "ETH/USD-0-1"

Given the parties create the following referral codes:
| party | code | is_team | team |
| party1 | referral-code-1 | true | team1 |
Given the parties create the following referral codes:
| party | code | is_team | team |
| party2 | referral-code-1 | true | team2 |

Scenario: Check a one-off pay out can be done with start epoch = end epoch

Given the current epoch is "0"
When the parties submit the following recurring transfers:
| id | from | from_account_type | to | to_account_type | entity_scope | asset | amount | start_epoch | end_epoch | factor | metric | metric_asset | markets | lock_period | window_length | ntop | cap_reward_fee_multiple |
| 1 | a3c024b4e23230c89884a54a813b1ecb4cb0f827a38641c66eeca466da6b2ddf | ACCOUNT_TYPE_GENERAL | 0000000000000000000000000000000000000000000000000000000000000000 | ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES | TEAMS | USD-0-1 | 100 | 1 | 2 | 1 | DISPATCH_METRIC_MAKER_FEES_RECEIVED | USD-0-1 | ETH/USD-0-1 | 10 | 1 | 1 | 1 |
Then the network moves ahead "1" epochs

## pary1
And the parties place the following orders:
| party | market id | side | volume | price | resulting trades | type | tif |
| aux1 | ETH/USD-0-1 | sell | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC |
| party1 | ETH/USD-0-1 | buy | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC |
| party1 | ETH/USD-0-1 | buy | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC |
| aux1 | ETH/USD-0-1 | sell | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC |
And the following trades should be executed:
| buyer | size | price | seller | aggressor side | buyer maker fee | seller maker fee |
| party1 | 10 | 1000 | aux1 | buy | 100 | 0 |
| party1 | 10 | 1000 | aux1 | sell | 0 | 100 |

# party2
And the parties place the following orders:
| party | market id | side | volume | price | resulting trades | type | tif |
| aux1 | ETH/USD-0-1 | sell | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC |
| party2 | ETH/USD-0-1 | buy | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC |
And the following trades should be executed:
| buyer | size | price | seller | aggressor side | buyer maker fee |
| party2 | 10 | 1000 | aux1 | buy | 100 |

When the network moves ahead "1" epochs
And parties should have the following vesting account balances:
| party | asset | balance |
| party1 | USD-0-1 | 100 |
| party2 | USD-0-1 | 0 |


## pary1
And the parties place the following orders:
| party | market id | side | volume | price | resulting trades | type | tif |
| aux1 | ETH/USD-0-1 | sell | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC |
| party1 | ETH/USD-0-1 | buy | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC |
| party1 | ETH/USD-0-1 | buy | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC |
| aux1 | ETH/USD-0-1 | sell | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC |
And the following trades should be executed:
| buyer | size | price | seller | aggressor side | buyer maker fee | seller maker fee |
| party1 | 10 | 1000 | aux1 | buy | 100 | 0 |
| party1 | 10 | 1000 | aux1 | sell | 0 | 100 |

# party2
And the parties place the following orders:
| party | market id | side | volume | price | resulting trades | type | tif |
| aux1 | ETH/USD-0-1 | sell | 10 | 1000 | 0 | TYPE_LIMIT | TIF_GTC |
| party2 | ETH/USD-0-1 | buy | 10 | 1000 | 1 | TYPE_LIMIT | TIF_GTC |
And the following trades should be executed:
| buyer | size | price | seller | aggressor side | buyer maker fee |
| party2 | 10 | 1000 | aux1 | buy | 100 |

When the network moves ahead "1" epochs
And parties should have the following vesting account balances:
| party | asset | balance |
| party1 | USD-0-1 | 200 |
| party2 | USD-0-1 | 0 |

Then debug transfers
Loading
Loading