@@ -483,14 +483,14 @@ contract KlerosCore is IArbitratorV2 {
483
483
484
484
/// @dev Sets the caller's stake in a court.
485
485
/// @param _courtID The ID of the court.
486
- /// @param _stake The new stake.
487
- function setStake (uint96 _courtID , uint256 _stake ) external {
488
- if (! _setStakeForAccount (msg .sender , _courtID, _stake )) revert StakingFailed ();
486
+ /// @param _newStake The new stake.
487
+ function setStake (uint96 _courtID , uint256 _newStake ) external {
488
+ if (! _setStakeForAccount (msg .sender , _courtID, _newStake )) revert StakingFailed ();
489
489
}
490
490
491
- function setStakeBySortitionModule (address _account , uint96 _courtID , uint256 _stake ) external {
491
+ function setStakeBySortitionModule (address _account , uint96 _courtID , uint256 _newStake ) external {
492
492
if (msg .sender != address (sortitionModule)) revert WrongCaller ();
493
- _setStakeForAccount (_account, _courtID, _stake );
493
+ _setStakeForAccount (_account, _courtID, _newStake );
494
494
}
495
495
496
496
/// @inheritdoc IArbitratorV2
@@ -611,17 +611,16 @@ contract KlerosCore is IArbitratorV2 {
611
611
IDisputeKit disputeKit = disputeKitNodes[round.disputeKitID].disputeKit;
612
612
613
613
uint256 startIndex = round.drawIterations;
614
- // TODO: cap the iterations?
615
- for (uint256 i = startIndex; i < startIndex + _iterations; i++ ) {
614
+ for (uint256 i = startIndex; i < startIndex + _iterations && round.drawnJurors.length < round.nbVotes; i++ ) {
616
615
address drawnAddress = disputeKit.draw (_disputeID, i);
617
- if (drawnAddress ! = address (0 )) {
618
- jurors[drawnAddress].lockedPnk += round.pnkAtStakePerJuror ;
619
- emit Draw (drawnAddress, _disputeID, currentRound, round.drawnJurors. length );
620
- round.drawnJurors. push (drawnAddress) ;
621
-
622
- if ( round.drawnJurors.length == round.nbVotes) {
623
- sortitionModule. postDrawHook (_disputeID, currentRound);
624
- }
616
+ if (drawnAddress = = address (0 )) {
617
+ continue ;
618
+ }
619
+ jurors[drawnAddress].lockedPnk += round.pnkAtStakePerJuror ;
620
+ emit Draw (drawnAddress, _disputeID, currentRound, round.drawnJurors. length );
621
+ round.drawnJurors.push (drawnAddress);
622
+ if (round.drawnJurors. length == round.nbVotes) {
623
+ sortitionModule. postDrawHook (_disputeID, currentRound);
625
624
}
626
625
}
627
626
round.drawIterations += _iterations;
@@ -1110,35 +1109,40 @@ contract KlerosCore is IArbitratorV2 {
1110
1109
/// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.
1111
1110
/// @param _account The address of the juror.
1112
1111
/// @param _courtID The ID of the court.
1113
- /// @param _stake The new stake.
1112
+ /// @param _newStake The new stake.
1114
1113
/// @return succeeded True if the call succeeded, false otherwise.
1115
- function _setStakeForAccount (address _account , uint96 _courtID , uint256 _stake ) internal returns (bool succeeded ) {
1114
+ function _setStakeForAccount (
1115
+ address _account ,
1116
+ uint96 _courtID ,
1117
+ uint256 _newStake
1118
+ ) internal returns (bool succeeded ) {
1116
1119
if (_courtID == FORKING_COURT || _courtID > courts.length ) return false ;
1117
1120
1118
1121
Juror storage juror = jurors[_account];
1119
1122
uint256 currentStake = juror.stakedPnkByCourt[_courtID];
1120
1123
1121
- if (_stake != 0 ) {
1122
- if (_stake < courts[_courtID].minStake) return false ;
1124
+ if (_newStake != 0 ) {
1125
+ if (_newStake < courts[_courtID].minStake) return false ;
1123
1126
} else if (currentStake == 0 ) {
1124
1127
return false ;
1125
1128
}
1126
1129
1127
- ISortitionModule.preStakeHookResult result = sortitionModule.preStakeHook (_account, _courtID, _stake );
1130
+ ISortitionModule.preStakeHookResult result = sortitionModule.preStakeHook (_account, _courtID, _newStake );
1128
1131
if (result == ISortitionModule.preStakeHookResult.failed) {
1129
1132
return false ;
1130
1133
} else if (result == ISortitionModule.preStakeHookResult.delayed) {
1131
- emit StakeDelayed (_account, _courtID, _stake );
1134
+ emit StakeDelayed (_account, _courtID, _newStake );
1132
1135
return true ;
1133
1136
}
1134
1137
1135
1138
uint256 transferredAmount;
1136
- if (_stake >= currentStake) {
1139
+ if (_newStake >= currentStake) {
1140
+ // Stake increase
1137
1141
// When stakedPnk becomes lower than lockedPnk count the locked tokens in when transferring tokens from juror.
1138
1142
// (E.g. stakedPnk = 0, lockedPnk = 150) which can happen if the juror unstaked fully while having some tokens locked.
1139
- uint256 previouslyLocked = (juror.lockedPnk >= juror.stakedPnk) ? juror.lockedPnk - juror.stakedPnk : 0 ;
1140
- transferredAmount = (_stake >= currentStake + previouslyLocked)
1141
- ? _stake - currentStake - previouslyLocked
1143
+ uint256 previouslyLocked = (juror.lockedPnk >= juror.stakedPnk) ? juror.lockedPnk - juror.stakedPnk : 0 ; // underflow guard
1144
+ transferredAmount = (_newStake >= currentStake + previouslyLocked) // underflow guard
1145
+ ? _newStake - currentStake - previouslyLocked
1142
1146
: 0 ;
1143
1147
if (transferredAmount > 0 ) {
1144
1148
if (! pinakion.safeTransferFrom (_account, address (this ), transferredAmount)) {
@@ -1149,49 +1153,36 @@ contract KlerosCore is IArbitratorV2 {
1149
1153
juror.courtIDs.push (_courtID);
1150
1154
}
1151
1155
} else {
1152
- if (_stake == 0 ) {
1153
- // Make sure locked tokens always stay in the contract. They can only be released during Execution.
1154
- if (juror.stakedPnk >= currentStake + juror.lockedPnk) {
1155
- // We have enough pnk staked to afford withdrawal of the current stake while keeping locked tokens.
1156
- transferredAmount = currentStake;
1157
- } else if (juror.stakedPnk >= juror.lockedPnk) {
1158
- // Can't afford withdrawing the current stake fully. Take whatever is available while keeping locked tokens.
1159
- transferredAmount = juror.stakedPnk - juror.lockedPnk;
1160
- }
1161
- if (transferredAmount > 0 ) {
1162
- if (! pinakion.safeTransfer (_account, transferredAmount)) {
1163
- return false ;
1164
- }
1156
+ // Stake decrease: make sure locked tokens always stay in the contract. They can only be released during Execution.
1157
+ if (juror.stakedPnk >= currentStake - _newStake + juror.lockedPnk) {
1158
+ // We have enough pnk staked to afford withdrawal while keeping locked tokens.
1159
+ transferredAmount = currentStake - _newStake;
1160
+ } else if (juror.stakedPnk >= juror.lockedPnk) {
1161
+ // Can't afford withdrawing the current stake fully. Take whatever is available while keeping locked tokens.
1162
+ transferredAmount = juror.stakedPnk - juror.lockedPnk;
1163
+ }
1164
+ if (transferredAmount > 0 ) {
1165
+ if (! pinakion.safeTransfer (_account, transferredAmount)) {
1166
+ return false ;
1165
1167
}
1168
+ }
1169
+ if (_newStake == 0 ) {
1166
1170
for (uint256 i = juror.courtIDs.length ; i > 0 ; i-- ) {
1167
1171
if (juror.courtIDs[i - 1 ] == _courtID) {
1168
1172
juror.courtIDs[i - 1 ] = juror.courtIDs[juror.courtIDs.length - 1 ];
1169
1173
juror.courtIDs.pop ();
1170
1174
break ;
1171
1175
}
1172
1176
}
1173
- } else {
1174
- if (juror.stakedPnk >= currentStake - _stake + juror.lockedPnk) {
1175
- // We have enough pnk staked to afford withdrawal while keeping locked tokens.
1176
- transferredAmount = currentStake - _stake;
1177
- } else if (juror.stakedPnk >= juror.lockedPnk) {
1178
- // Can't afford withdrawing the current stake fully. Take whatever is available while keeping locked tokens.
1179
- transferredAmount = juror.stakedPnk - juror.lockedPnk;
1180
- }
1181
- if (transferredAmount > 0 ) {
1182
- if (! pinakion.safeTransfer (_account, transferredAmount)) {
1183
- return false ;
1184
- }
1185
- }
1186
1177
}
1187
1178
}
1188
1179
1189
1180
// Note that stakedPnk can become async with currentStake (e.g. after penalty).
1190
- juror.stakedPnk = (juror.stakedPnk >= currentStake) ? juror.stakedPnk - currentStake + _stake : _stake ;
1191
- juror.stakedPnkByCourt[_courtID] = _stake ;
1181
+ juror.stakedPnk = (juror.stakedPnk >= currentStake) ? juror.stakedPnk - currentStake + _newStake : _newStake ;
1182
+ juror.stakedPnkByCourt[_courtID] = _newStake ;
1192
1183
1193
- sortitionModule.setStake (_account, _courtID, _stake );
1194
- emit StakeSet (_account, _courtID, _stake );
1184
+ sortitionModule.setStake (_account, _courtID, _newStake );
1185
+ emit StakeSet (_account, _courtID, _newStake );
1195
1186
return true ;
1196
1187
}
1197
1188
0 commit comments