@@ -23,7 +23,13 @@ import {IGovernance} from "../../common/governance/IGovernance.sol";
23
23
import {Initializable} from "../../common/mixin/Initializable.sol " ;
24
24
import {ValidatorAuction} from "./ValidatorAuction.sol " ;
25
25
26
- contract StakeManager is StakeManagerStorage , Initializable , IStakeManager , DelegateProxyForwarder , StakeManagerStorageExtension {
26
+ contract StakeManager is
27
+ StakeManagerStorage ,
28
+ Initializable ,
29
+ IStakeManager ,
30
+ DelegateProxyForwarder ,
31
+ StakeManagerStorageExtension
32
+ {
27
33
using SafeMath for uint256 ;
28
34
using Merkle for bytes32 ;
29
35
using RLPReader for bytes ;
@@ -105,7 +111,7 @@ contract StakeManager is StakeManagerStorage, Initializable, IStakeManager, Dele
105
111
Public View Methods
106
112
*/
107
113
108
- function getRegistry () public view returns (address ) {
114
+ function getRegistry () public view returns (address ) {
109
115
return registry;
110
116
}
111
117
@@ -213,12 +219,22 @@ contract StakeManager is StakeManagerStorage, Initializable, IStakeManager, Dele
213
219
CHECKPOINT_REWARD = newReward;
214
220
}
215
221
222
+ function updateCheckpointRewardParams (
223
+ uint256 _rewardDecreasePerCheckpoint ,
224
+ uint256 _maxSkippedCheckpoints ,
225
+ uint256 _checkpointRewardDelta
226
+ ) public onlyGovernance {
227
+ require (_maxSkippedCheckpoints.mul (_rewardDecreasePerCheckpoint) <= CHK_REWARD_PRECISION);
228
+ require (_checkpointRewardDelta <= CHK_REWARD_PRECISION);
229
+
230
+ rewardDecreasePerCheckpoint = _rewardDecreasePerCheckpoint;
231
+ maxSkippedCheckpoints = _maxSkippedCheckpoints;
232
+ checkpointRewardDelta = _checkpointRewardDelta;
233
+ }
234
+
216
235
// New implementation upgrade
217
236
218
- function migrateValidatorsData (
219
- uint256 validatorIdFrom ,
220
- uint256 validatorIdTo
221
- ) public onlyOwner {
237
+ function migrateValidatorsData (uint256 validatorIdFrom , uint256 validatorIdTo ) public onlyOwner {
222
238
for (uint256 i = validatorIdFrom; i < validatorIdTo; ++ i) {
223
239
ValidatorShare contractAddress = ValidatorShare (validators[i].contractAddress);
224
240
if (contractAddress != ValidatorShare (0 )) {
@@ -230,9 +246,7 @@ contract StakeManager is StakeManagerStorage, Initializable, IStakeManager, Dele
230
246
}
231
247
}
232
248
233
- function insertSigners (
234
- address [] calldata _signers
235
- ) external onlyOwner {
249
+ function insertSigners (address [] memory _signers ) public onlyOwner {
236
250
signers = _signers;
237
251
}
238
252
@@ -664,11 +678,12 @@ contract StakeManager is StakeManagerStorage, Initializable, IStakeManager, Dele
664
678
665
679
address delegationContract = validators[validatorId].contractAddress;
666
680
if (delegationContract != address (0x0 )) {
667
- uint256 delSlashedAmount = IValidatorShare (delegationContract).slash (
668
- validators[validatorId].amount,
669
- validators[validatorId].delegatedAmount,
670
- _amount
671
- );
681
+ uint256 delSlashedAmount =
682
+ IValidatorShare (delegationContract).slash (
683
+ validators[validatorId].amount,
684
+ validators[validatorId].delegatedAmount,
685
+ _amount
686
+ );
672
687
_amount = _amount.sub (delSlashedAmount);
673
688
}
674
689
@@ -790,6 +805,59 @@ contract StakeManager is StakeManagerStorage, Initializable, IStakeManager, Dele
790
805
return context;
791
806
}
792
807
808
+ function _calculateCheckpointReward (
809
+ uint256 blockInterval ,
810
+ uint256 signedStakePower ,
811
+ uint256 currentTotalStake
812
+ ) internal returns (uint256 ) {
813
+ // checkpoint rewards are based on BlockInterval multiplied on `CHECKPOINT_REWARD`
814
+ // for bigger checkpoints reward is reduced by rewardDecreasePerCheckpoint for each subsequent interval
815
+
816
+ // for smaller checkpoints
817
+ // if interval is 50% of checkPointBlockInterval then reward R is half of `CHECKPOINT_REWARD`
818
+ // and then stakePower is 90% of currentValidatorSetTotalStake then final reward is 90% of R
819
+
820
+ uint256 targetBlockInterval = checkPointBlockInterval;
821
+ uint256 ckpReward = CHECKPOINT_REWARD;
822
+ uint256 fullIntervals = Math.min (blockInterval / targetBlockInterval, maxSkippedCheckpoints);
823
+
824
+ // only apply to full checkpoints
825
+ if (fullIntervals > 0 && fullIntervals != prevBlockInterval) {
826
+ if (prevBlockInterval != 0 ) {
827
+ // give more reward for faster and less for slower checkpoint
828
+ uint256 delta = (ckpReward * checkpointRewardDelta / CHK_REWARD_PRECISION);
829
+
830
+ if (prevBlockInterval > fullIntervals) {
831
+ // checkpoint is faster
832
+ ckpReward += delta;
833
+ } else {
834
+ ckpReward -= delta;
835
+ }
836
+ }
837
+
838
+ prevBlockInterval = fullIntervals;
839
+ }
840
+
841
+ uint256 reward;
842
+
843
+ if (blockInterval > targetBlockInterval) {
844
+ // count how many full intervals
845
+ uint256 _rewardDecreasePerCheckpoint = rewardDecreasePerCheckpoint;
846
+
847
+ // calculate reward for full intervals
848
+ reward = ckpReward.mul (fullIntervals).sub (ckpReward.mul (((fullIntervals - 1 ) * fullIntervals / 2 ).mul (_rewardDecreasePerCheckpoint)).div (CHK_REWARD_PRECISION));
849
+ // adjust block interval, in case last interval is not full
850
+ blockInterval = blockInterval.sub (fullIntervals.mul (targetBlockInterval));
851
+ // adjust checkpoint reward by the amount it suppose to decrease
852
+ ckpReward = ckpReward.sub (ckpReward.mul (fullIntervals).mul (_rewardDecreasePerCheckpoint).div (CHK_REWARD_PRECISION));
853
+ }
854
+
855
+ // give proportionally less for the rest
856
+ reward = reward.add (blockInterval.mul (ckpReward).div (targetBlockInterval));
857
+ reward = reward.mul (signedStakePower).div (currentTotalStake);
858
+ return reward;
859
+ }
860
+
793
861
function _increaseRewardAndAssertConsensus (
794
862
uint256 blockInterval ,
795
863
address proposer ,
@@ -803,13 +871,7 @@ contract StakeManager is StakeManagerStorage, Initializable, IStakeManager, Dele
803
871
uint256 currentTotalStake = validatorState.amount;
804
872
require (signedStakePower >= currentTotalStake.mul (2 ).div (3 ).add (1 ), "2/3+1 non-majority! " );
805
873
806
- // checkpoint rewards are based on BlockInterval multiplied on `CHECKPOINT_REWARD`
807
- // for bigger checkpoints reward is capped at `CHECKPOINT_REWARD`
808
- // if interval is 50% of checkPointBlockInterval then reward R is half of `CHECKPOINT_REWARD`
809
- // and then stakePower is 90% of currentValidatorSetTotalStake then final reward is 90% of R
810
- uint256 reward = blockInterval.mul (CHECKPOINT_REWARD).div (checkPointBlockInterval);
811
- reward = reward.mul (signedStakePower).div (currentTotalStake);
812
- reward = Math.min (CHECKPOINT_REWARD, reward);
874
+ uint256 reward = _calculateCheckpointReward (blockInterval, signedStakePower, currentTotalStake);
813
875
814
876
uint256 _proposerBonus = reward.mul (proposerBonus).div (MAX_PROPOSER_BONUS);
815
877
uint256 proposerId = signerToValidator[proposer];
@@ -825,9 +887,8 @@ contract StakeManager is StakeManagerStorage, Initializable, IStakeManager, Dele
825
887
// update stateMerkleTree root for accounts balance on heimdall chain
826
888
accountStateRoot = stateRoot;
827
889
828
- uint256 newRewardPerStake = rewardPerStake.add (
829
- reward.sub (_proposerBonus).mul (REWARD_PRECISION).div (signedStakePower)
830
- );
890
+ uint256 newRewardPerStake =
891
+ rewardPerStake.add (reward.sub (_proposerBonus).mul (REWARD_PRECISION).div (signedStakePower));
831
892
832
893
// evaluate rewards for validator who did't sign and set latest reward per stake to new value to avoid them from getting new rewards.
833
894
_updateValidatorsRewards (unsignedValidators, totalUnsignedValidators, newRewardPerStake);
@@ -860,7 +921,7 @@ contract StakeManager is StakeManagerStorage, Initializable, IStakeManager, Dele
860
921
) private {
861
922
uint256 initialRewardPerStake = validators[validatorId].initialRewardPerStake;
862
923
863
- // attempt to save gas in case if rewards were updated previosuly
924
+ // attempt to save gas in case if rewards were updated previosuly
864
925
if (initialRewardPerStake < currentRewardPerStake) {
865
926
uint256 validatorsStake = validators[validatorId].amount;
866
927
uint256 delegatedAmount = validators[validatorId].delegatedAmount;
@@ -870,12 +931,22 @@ contract StakeManager is StakeManagerStorage, Initializable, IStakeManager, Dele
870
931
validatorId,
871
932
validatorsStake,
872
933
delegatedAmount,
873
- _getEligibleValidatorReward (validatorId, combinedStakePower, currentRewardPerStake, initialRewardPerStake)
934
+ _getEligibleValidatorReward (
935
+ validatorId,
936
+ combinedStakePower,
937
+ currentRewardPerStake,
938
+ initialRewardPerStake
939
+ )
874
940
);
875
941
} else {
876
942
_increaseValidatorReward (
877
943
validatorId,
878
- _getEligibleValidatorReward (validatorId, validatorsStake, currentRewardPerStake, initialRewardPerStake)
944
+ _getEligibleValidatorReward (
945
+ validatorId,
946
+ validatorsStake,
947
+ currentRewardPerStake,
948
+ initialRewardPerStake
949
+ )
879
950
);
880
951
}
881
952
}
@@ -910,12 +981,8 @@ contract StakeManager is StakeManagerStorage, Initializable, IStakeManager, Dele
910
981
uint256 reward
911
982
) private {
912
983
uint256 combinedStakePower = delegatedAmount.add (validatorsStake);
913
- (uint256 validatorReward , uint256 delegatorsReward ) = _getValidatorAndDelegationReward (
914
- validatorId,
915
- validatorsStake,
916
- reward,
917
- combinedStakePower
918
- );
984
+ (uint256 validatorReward , uint256 delegatorsReward ) =
985
+ _getValidatorAndDelegationReward (validatorId, validatorsStake, reward, combinedStakePower);
919
986
920
987
if (delegatorsReward > 0 ) {
921
988
validators[validatorId].delegatorsReward = validators[validatorId].delegatorsReward.add (delegatorsReward);
@@ -1134,7 +1201,7 @@ contract StakeManager is StakeManagerStorage, Initializable, IStakeManager, Dele
1134
1201
delete signers[totalSigners - 1 ];
1135
1202
1136
1203
// bubble last element to the beginning until target signer is met
1137
- for (uint i = totalSigners - 1 ; i > 0 ; -- i) {
1204
+ for (uint256 i = totalSigners - 1 ; i > 0 ; -- i) {
1138
1205
if (swapSigner == signerToDelete) {
1139
1206
break ;
1140
1207
}
0 commit comments