code.vegaprotocol.io/vega@v0.79.0/core/rewards/reward_distribution_test.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package rewards
    17  
    18  import (
    19  	"testing"
    20  
    21  	"code.vegaprotocol.io/vega/core/types"
    22  	"code.vegaprotocol.io/vega/libs/num"
    23  	"code.vegaprotocol.io/vega/protos/vega"
    24  
    25  	"github.com/stretchr/testify/require"
    26  )
    27  
    28  func TestAdjustForNegatives(t *testing.T) {
    29  	adjustedNoNegatives := adjustScoreForNegative([]*types.PartyContributionScore{
    30  		{Party: "p1", Score: num.DecimalFromFloat(1)},
    31  		{Party: "p2", Score: num.DecimalFromFloat(2)},
    32  		{Party: "p3", Score: num.DecimalFromFloat(3)},
    33  		{Party: "p4", Score: num.DecimalFromFloat(4)},
    34  	})
    35  	require.Equal(t, 4, len(adjustedNoNegatives))
    36  	require.Equal(t, "1", adjustedNoNegatives[0].Score.String())
    37  	require.Equal(t, "2", adjustedNoNegatives[1].Score.String())
    38  	require.Equal(t, "3", adjustedNoNegatives[2].Score.String())
    39  	require.Equal(t, "4", adjustedNoNegatives[3].Score.String())
    40  
    41  	adjustedMinEqMax := adjustScoreForNegative([]*types.PartyContributionScore{
    42  		{Party: "p1", Score: num.DecimalFromFloat(4)},
    43  		{Party: "p2", Score: num.DecimalFromFloat(4)},
    44  		{Party: "p3", Score: num.DecimalFromFloat(4)},
    45  		{Party: "p4", Score: num.DecimalFromFloat(4)},
    46  	})
    47  	require.Equal(t, 4, len(adjustedMinEqMax))
    48  	require.Equal(t, "4", adjustedMinEqMax[0].Score.String())
    49  	require.Equal(t, "4", adjustedMinEqMax[1].Score.String())
    50  	require.Equal(t, "4", adjustedMinEqMax[2].Score.String())
    51  	require.Equal(t, "4", adjustedMinEqMax[3].Score.String())
    52  
    53  	adjustedAllNeg := adjustScoreForNegative([]*types.PartyContributionScore{
    54  		{Party: "p1", Score: num.DecimalFromFloat(-4)},
    55  		{Party: "p2", Score: num.DecimalFromFloat(-3)},
    56  		{Party: "p3", Score: num.DecimalFromFloat(-2)},
    57  		{Party: "p4", Score: num.DecimalFromFloat(-1)},
    58  	})
    59  	require.Equal(t, 3, len(adjustedAllNeg))
    60  	require.Equal(t, "1", adjustedAllNeg[0].Score.String())
    61  	require.Equal(t, "2", adjustedAllNeg[1].Score.String())
    62  	require.Equal(t, "3", adjustedAllNeg[2].Score.String())
    63  
    64  	adjustedSomeNeg := adjustScoreForNegative([]*types.PartyContributionScore{
    65  		{Party: "p1", Score: num.DecimalFromFloat(1)},
    66  		{Party: "p2", Score: num.DecimalFromFloat(-1)},
    67  		{Party: "p3", Score: num.DecimalFromFloat(2)},
    68  		{Party: "p4", Score: num.DecimalFromFloat(-2)},
    69  		{Party: "p5", Score: num.DecimalFromFloat(3)},
    70  		{Party: "p6", Score: num.DecimalFromFloat(-3)},
    71  		{Party: "p7", Score: num.DecimalFromFloat(4)},
    72  		{Party: "p8", Score: num.DecimalFromFloat(-4)},
    73  	})
    74  	require.Equal(t, 7, len(adjustedSomeNeg))
    75  	require.Equal(t, "5", adjustedSomeNeg[0].Score.String())
    76  	require.Equal(t, "p1", adjustedSomeNeg[0].Party)
    77  	require.Equal(t, "3", adjustedSomeNeg[1].Score.String())
    78  	require.Equal(t, "p2", adjustedSomeNeg[1].Party)
    79  	require.Equal(t, "6", adjustedSomeNeg[2].Score.String())
    80  	require.Equal(t, "p3", adjustedSomeNeg[2].Party)
    81  	require.Equal(t, "2", adjustedSomeNeg[3].Score.String())
    82  	require.Equal(t, "p4", adjustedSomeNeg[3].Party)
    83  	require.Equal(t, "7", adjustedSomeNeg[4].Score.String())
    84  	require.Equal(t, "p5", adjustedSomeNeg[4].Party)
    85  	require.Equal(t, "1", adjustedSomeNeg[5].Score.String())
    86  	require.Equal(t, "p6", adjustedSomeNeg[5].Party)
    87  	require.Equal(t, "8", adjustedSomeNeg[6].Score.String())
    88  	require.Equal(t, "p7", adjustedSomeNeg[6].Party)
    89  }
    90  
    91  func TestFindRank(t *testing.T) {
    92  	rankingTable := []*vega.Rank{
    93  		{StartRank: 1, ShareRatio: 10},
    94  		{StartRank: 2, ShareRatio: 5},
    95  		{StartRank: 4, ShareRatio: 2},
    96  		{StartRank: 10, ShareRatio: 1},
    97  		{StartRank: 20, ShareRatio: 0},
    98  	}
    99  	require.Equal(t, uint32(10), findRank(rankingTable, 1))
   100  	require.Equal(t, uint32(5), findRank(rankingTable, 2))
   101  	require.Equal(t, uint32(5), findRank(rankingTable, 3))
   102  	require.Equal(t, uint32(2), findRank(rankingTable, 4))
   103  	require.Equal(t, uint32(2), findRank(rankingTable, 5))
   104  	require.Equal(t, uint32(2), findRank(rankingTable, 6))
   105  	require.Equal(t, uint32(1), findRank(rankingTable, 10))
   106  	require.Equal(t, uint32(1), findRank(rankingTable, 15))
   107  	require.Equal(t, uint32(0), findRank(rankingTable, 20))
   108  	require.Equal(t, uint32(0), findRank(rankingTable, 21))
   109  }
   110  
   111  func TestRankingRewardCalculator(t *testing.T) {
   112  	rankingTable := []*vega.Rank{
   113  		{StartRank: 1, ShareRatio: 10},
   114  		{StartRank: 2, ShareRatio: 5},
   115  		{StartRank: 4, ShareRatio: 0},
   116  	}
   117  
   118  	require.Equal(t, 0, len(rankingRewardCalculator([]*types.PartyContributionScore{}, rankingTable, map[string]num.Decimal{})))
   119  
   120  	partyContribution := []*types.PartyContributionScore{
   121  		{Party: "p1", Score: num.DecimalFromFloat(0.6)},
   122  		{Party: "p2", Score: num.DecimalFromFloat(0.5)},
   123  		{Party: "p3", Score: num.DecimalFromFloat(0.1)},
   124  		{Party: "p4", Score: num.DecimalFromFloat(0.6)},
   125  		{Party: "p5", Score: num.DecimalFromFloat(0.05)},
   126  	}
   127  
   128  	rankingResult := rankingRewardCalculator(partyContribution, rankingTable, map[string]num.Decimal{"p1": num.DecimalFromInt64(2), "p2": num.DecimalFromInt64(4)})
   129  	// p1 is at the 1st rank => share ratio = 10. reward_multiplier = 2 => d_i = 20 => s_i = 20/50 = 0.4
   130  	// p4 is at the 1st rank => share ratio = 10. reward_multiplier = 1 => d_i = 10 => 2_i = 10/50 = 0.2
   131  	// p2 is at the 3rd rank => share ratio = 5. reward_multiplier = 4 => d_i => 20 => s_i = 20/50 = 0.4
   132  	// p3 is at the 4th rank => share ratio = 0
   133  	// p5 is at the 5th rank => share ratio = 0
   134  	require.Equal(t, 3, len(rankingResult))
   135  	require.Equal(t, "p1", rankingResult[0].Party)
   136  	require.Equal(t, "0.4", rankingResult[0].Score.String())
   137  	require.Equal(t, "p4", rankingResult[1].Party)
   138  	require.Equal(t, "0.2", rankingResult[1].Score.String())
   139  	require.Equal(t, "p2", rankingResult[2].Party)
   140  	require.Equal(t, "0.4", rankingResult[2].Score.String())
   141  }
   142  
   143  func TestProRataRewardCalculator(t *testing.T) {
   144  	require.Equal(t, 0, len(proRataRewardCalculator([]*types.PartyContributionScore{}, map[string]num.Decimal{})))
   145  
   146  	partyContribution := []*types.PartyContributionScore{
   147  		{Party: "p1", Score: num.DecimalFromFloat(0.6)},
   148  		{Party: "p2", Score: num.DecimalFromFloat(0.5)},
   149  		{Party: "p3", Score: num.DecimalFromFloat(0.1)},
   150  		{Party: "p4", Score: num.DecimalFromFloat(0.6)},
   151  		{Party: "p5", Score: num.DecimalFromFloat(0.05)},
   152  	}
   153  	rewardMultipliers := map[string]num.Decimal{"p2": num.DecimalFromFloat(2.5), "p3": num.DecimalFromInt64(5), "p4": num.DecimalFromFloat(2.5), "p5": num.DecimalFromInt64(3)}
   154  	prorataResult := proRataRewardCalculator(partyContribution, rewardMultipliers)
   155  	require.Equal(t, 5, len(prorataResult))
   156  
   157  	// p1: 0.6 * 1 = 0.6
   158  	// p2: 0.5 * 2.5 = 1.25
   159  	// p3: 0.1 * 5 = 0.5
   160  	// p4: 0.6 * 2.5  = 1.5
   161  	// p5: 0.05 * 3 = 0.15
   162  	// total = 4
   163  	// s_1 = 0.6/4 = 0.15
   164  	// s_2 = 1.25/4 = 0.3125
   165  	// s_3 = 0.5/4 = 0.125
   166  	// s_4 = 1.5/4 = 0.375
   167  	// s_5 = 0.15/4 = 0.0375
   168  	require.Equal(t, "p1", prorataResult[0].Party)
   169  	require.Equal(t, "0.15", prorataResult[0].Score.String())
   170  	require.Equal(t, "p2", prorataResult[1].Party)
   171  	require.Equal(t, "0.3125", prorataResult[1].Score.String())
   172  	require.Equal(t, "p3", prorataResult[2].Party)
   173  	require.Equal(t, "0.125", prorataResult[2].Score.String())
   174  	require.Equal(t, "p4", prorataResult[3].Party)
   175  	require.Equal(t, "0.375", prorataResult[3].Score.String())
   176  	require.Equal(t, "p5", prorataResult[4].Party)
   177  	require.Equal(t, "0.0375", prorataResult[4].Score.String())
   178  }
   179  
   180  func TestCapAtOne(t *testing.T) {
   181  	partyRewardScores := []*types.PartyContributionScore{{Party: "p1", Score: num.DecimalFromFloat(0.1)}, {Party: "p2", Score: num.MustDecimalFromString("0.900000001")}}
   182  	total := num.DecimalFromFloat(0.1).Add(num.MustDecimalFromString("0.900000001"))
   183  
   184  	capAtOne(partyRewardScores, total)
   185  	require.Equal(t, "p2", partyRewardScores[0].Party)
   186  	require.Equal(t, "0.9", partyRewardScores[0].Score.String())
   187  	require.Equal(t, "p1", partyRewardScores[1].Party)
   188  	require.Equal(t, "0.1", partyRewardScores[1].Score.String())
   189  }