@@ -19,8 +19,9 @@ abstract contract StakeBase is StakerTestBase {
1919 uint256 _rewardAmount ,
2020 uint256 _percentDuration
2121 ) public virtual {
22- vm.assume (_depositor != address (0 ) && _delegatee != address (0 ) && _amount != 0 );
23- vm.assume (_depositor != address (staker));
22+ _assumeNotZeroAddressOrStaker (_depositor);
23+ vm.assume (_delegatee != address (0 ) && _amount != 0 );
24+
2425 _mintStakeToken (_depositor, _amount);
2526 _rewardAmount = _boundToRealisticReward (_rewardAmount);
2627 _percentDuration = bound (_percentDuration, 1 , 100 );
@@ -37,6 +38,99 @@ abstract contract StakeBase is StakerTestBase {
3738
3839 assertLteWithinOneUnit (unclaimedRewards, _earnedRewards);
3940 }
41+
42+ function testForkFuzz_TwoDepositorsEarnRewardsOverSinglePeriod (
43+ address _depositor1 ,
44+ address _depositor2 ,
45+ uint96 _amount ,
46+ address _delegatee ,
47+ uint256 _rewardAmount ,
48+ uint256 _percentDuration1 ,
49+ uint256 _percentDuration2
50+ ) public {
51+ _assumeNotZeroAddressOrStaker (_depositor1);
52+ _assumeNotZeroAddressOrStaker (_depositor2);
53+ vm.assume (_depositor1 != _depositor2 && _delegatee != address (0 ) && _amount != 0 );
54+
55+ _mintStakeToken (_depositor1, _amount);
56+ _mintStakeToken (_depositor2, _amount);
57+ _rewardAmount = _boundToRealisticReward (_rewardAmount);
58+ _percentDuration1 = bound (_percentDuration1, 1 , 100 );
59+ _percentDuration2 = bound (_percentDuration2, 0 , 100 - _percentDuration1);
60+
61+ Staker.DepositIdentifier _depositId1 = _stake (_depositor1, _amount, _delegatee);
62+ Staker.DepositIdentifier _depositId2 = _stake (_depositor2, _amount, _delegatee);
63+ _notifyRewardAmount (_rewardAmount);
64+
65+ _jumpAheadByPercentOfRewardDuration (_percentDuration1);
66+ uint256 unclaimedRewards1 = staker.unclaimedReward (_depositId1);
67+ Staker.Deposit memory _deposit1 = _fetchDeposit (_depositId1);
68+ uint256 _earnedRewards1 =
69+ _calculateEarnedRewards (_deposit1.earningPower, _rewardAmount, _percentDuration1);
70+
71+ _jumpAheadByPercentOfRewardDuration (_percentDuration2);
72+ uint256 unclaimedRewards2 = staker.unclaimedReward (_depositId2);
73+ Staker.Deposit memory _deposit2 = _fetchDeposit (_depositId2);
74+ uint256 _earnedRewards2 = _calculateEarnedRewards (
75+ _deposit2.earningPower, _rewardAmount, _percentDuration1 + _percentDuration2
76+ );
77+
78+ assertLteWithinOneUnit (unclaimedRewards1, _earnedRewards1);
79+ assertLteWithinOneUnit (unclaimedRewards2, _earnedRewards2);
80+ }
81+
82+ function testForkFuzz_TwoDepositorsEarnRewardsOverMultiplePeriods (
83+ address _depositor1 ,
84+ address _depositor2 ,
85+ uint96 _amount ,
86+ address _delegatee ,
87+ uint256 _rewardAmount ,
88+ uint256 _percentDuration1 ,
89+ uint256 _percentDuration2
90+ ) public {
91+ _assumeNotZeroAddressOrStaker (_depositor1);
92+ _assumeNotZeroAddressOrStaker (_depositor2);
93+ vm.assume (_depositor1 != _depositor2 && _delegatee != address (0 ) && _amount != 0 );
94+
95+ _mintStakeToken (_depositor1, _amount);
96+ _mintStakeToken (_depositor2, _amount);
97+ _rewardAmount = _boundToRealisticReward (_rewardAmount);
98+ _percentDuration1 = bound (_percentDuration1, 1 , 100 );
99+ _percentDuration2 = bound (_percentDuration2, 1 , 100 );
100+
101+ Staker.DepositIdentifier _depositId1 = _stake (_depositor1, _amount, _delegatee);
102+ Staker.DepositIdentifier _depositId2 = _stake (_depositor2, _amount, _delegatee);
103+
104+ _notifyRewardAmount (_rewardAmount);
105+ _jumpAheadByPercentOfRewardDuration (_percentDuration1);
106+
107+ _notifyRewardAmount (_rewardAmount);
108+ _jumpAheadByPercentOfRewardDuration (_percentDuration2);
109+
110+ uint256 _remainingFirstPeriodRewards = _percentOf (_rewardAmount, 100 - _percentDuration1);
111+ uint256 unclaimedRewards1 = staker.unclaimedReward (_depositId1);
112+ uint256 unclaimedRewards2 = staker.unclaimedReward (_depositId2);
113+ Staker.Deposit memory _deposit1 = _fetchDeposit (_depositId1);
114+ Staker.Deposit memory _deposit2 = _fetchDeposit (_depositId2);
115+ uint256 _earnedRewards1 = _calculateEarnedRewards (
116+ _deposit1.earningPower, _rewardAmount, _percentDuration1
117+ )
118+ + _calculateEarnedRewards (
119+ _deposit2.earningPower, _rewardAmount + _remainingFirstPeriodRewards, _percentDuration2
120+ );
121+ uint256 _earnedRewards2 = _calculateEarnedRewards (
122+ _deposit2.earningPower, _rewardAmount, _percentDuration1
123+ )
124+ + _calculateEarnedRewards (
125+ _deposit2.earningPower, _rewardAmount + _remainingFirstPeriodRewards, _percentDuration2
126+ );
127+
128+ // because we summed 2 amounts, the rounding error can be as much as 2 units
129+ assertApproxEqAbs (unclaimedRewards1, _earnedRewards1, 2 );
130+ assertLe (unclaimedRewards1, _earnedRewards1);
131+ assertApproxEqAbs (unclaimedRewards2, _earnedRewards2, 2 );
132+ assertLe (unclaimedRewards2, _earnedRewards2);
133+ }
40134}
41135
42136abstract contract WithdrawBase is StakerTestBase {
0 commit comments