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 }