Skip to content

Commit 1ba64db

Browse files
committed
Merge branch 'dev' into feat/dk-jump
2 parents 62b0a50 + a7cfba0 commit 1ba64db

16 files changed

+1388
-309
lines changed

contracts/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,18 @@ The format is based on [Common Changelog](https://common-changelog.org/).
1313
- **Breaking:** Rename the interface from `RNG` to `IRNG` ([#2054](https://github.com/kleros/kleros-v2/issues/2054))
1414
- **Breaking:** Remove the `_block` parameter from `IRNG.requestRandomness()` and `IRNG.receiveRandomness()`, not needed for the primary VRF-based RNG ([#2054](https://github.com/kleros/kleros-v2/issues/2054))
1515
- **Breaking:** Rename `governor` to `owner` in order to comply with the lightweight ownership standard [ERC-5313](https://eipsinsight.com/ercs/erc-5313) ([#2112](https://github.com/kleros/kleros-v2/issues/2112))
16+
- **Breaking:** Apply the penalties to the stakes in the Sortition Tree ([#2107](https://github.com/kleros/kleros-v2/issues/2107))
17+
- **Breaking:** Make `SortitionModule.getJurorBalance().stakedInCourt` include the penalties ([#2107](https://github.com/kleros/kleros-v2/issues/2107))
18+
- **Breaking:** Add a new field `drawnJurorFromCourtIDs` to the `Round` struct in `KlerosCoreBase` and `KlerosCoreUniversity` ([#2107](https://github.com/kleros/kleros-v2/issues/2107))
1619
- **Breaking:** Add a new state variable `jumpDisputeKitID` to the `DisputeKitClassicBase` contract ([#2114](https://github.com/kleros/kleros-v2/issues/2114))
20+
- Make `IDisputeKit.draw()` and `ISortitionModule.draw()` return the court ID from which the juror was drawn ([#2107](https://github.com/kleros/kleros-v2/issues/2107))
21+
- Rename `SortitionModule.setJurorInactive()` to `SortitionModule.forcedUnstakeAllCourts()` ([#2107](https://github.com/kleros/kleros-v2/issues/2107))
22+
- Allow stake changes to by-pass delayed stakes when initiated by the SortitionModule by setting the `_noDelay` parameter to `true` in `SortitionModule.validateStake()` ([#2107](https://github.com/kleros/kleros-v2/issues/2107))
1723
- Make the primary VRF-based RNG fall back to `BlockhashRNG` if the VRF request is not fulfilled within a timeout ([#2054](https://github.com/kleros/kleros-v2/issues/2054))
1824
- Authenticate the calls to the RNGs to prevent 3rd parties from depleting the Chainlink VRF subscription funds ([#2054](https://github.com/kleros/kleros-v2/issues/2054))
1925
- Use `block.timestamp` rather than `block.number` for `BlockhashRNG` for better reliability on Arbitrum as block production is sporadic depending on network conditions. ([#2054](https://github.com/kleros/kleros-v2/issues/2054))
26+
- Replace the `bytes32 _key` parameter in `SortitionTrees.createTree()` and `SortitionTrees.draw()` by `uint96 courtID` ([#2113](https://github.com/kleros/kleros-v2/issues/2113))
27+
- Extract the sortition sum trees logic into a library `SortitionTrees` ([#2113](https://github.com/kleros/kleros-v2/issues/2113))
2028
- Set the Hardhat Solidity version to v0.8.30 and enable the IR pipeline ([#2069](https://github.com/kleros/kleros-v2/issues/2069))
2129
- Set the Foundry Solidity version to v0.8.30 and enable the IR pipeline ([#2073](https://github.com/kleros/kleros-v2/issues/2073))
2230
- Widen the allowed solc version to any v0.8.x for the interfaces only ([#2083](https://github.com/kleros/kleros-v2/issues/2083))

contracts/src/arbitration/KlerosCoreBase.sol

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
6060
uint256 repartitions; // A counter of reward repartitions made in this round.
6161
uint256 pnkPenalties; // The amount of PNKs collected from penalties in this round.
6262
address[] drawnJurors; // Addresses of the jurors that were drawn in this round.
63+
uint96[] drawnJurorFromCourtIDs; // The courtIDs where the juror was drawn from, possibly their stake in a subcourt.
6364
uint256 sumFeeRewardPaid; // Total sum of arbitration fees paid to coherent jurors as a reward in this round.
6465
uint256 sumPnkRewardPaid; // Total sum of PNK paid to coherent jurors as a reward in this round.
6566
IERC20 feeToken; // The token used for paying fees in this round.
@@ -222,7 +223,7 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
222223
// FORKING_COURT
223224
// TODO: Fill the properties for the Forking court, emit CourtCreated.
224225
courts.push();
225-
sortitionModule.createTree(bytes32(uint256(FORKING_COURT)), _sortitionExtraData);
226+
sortitionModule.createTree(FORKING_COURT, _sortitionExtraData);
226227

227228
// GENERAL_COURT
228229
Court storage court = courts.push();
@@ -235,7 +236,7 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
235236
court.jurorsForCourtJump = _courtParameters[3];
236237
court.timesPerPeriod = _timesPerPeriod;
237238

238-
sortitionModule.createTree(bytes32(uint256(GENERAL_COURT)), _sortitionExtraData);
239+
sortitionModule.createTree(GENERAL_COURT, _sortitionExtraData);
239240

240241
uint256[] memory supportedDisputeKits = new uint256[](1);
241242
supportedDisputeKits[0] = DISPUTE_KIT_CLASSIC;
@@ -342,7 +343,7 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
342343
if (_supportedDisputeKits.length == 0) revert UnsupportedDisputeKit();
343344
if (_parent == FORKING_COURT) revert InvalidForkingCourtAsParent();
344345

345-
uint256 courtID = courts.length;
346+
uint96 courtID = uint96(courts.length);
346347
Court storage court = courts.push();
347348

348349
for (uint256 i = 0; i < _supportedDisputeKits.length; i++) {
@@ -363,7 +364,7 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
363364
court.jurorsForCourtJump = _jurorsForCourtJump;
364365
court.timesPerPeriod = _timesPerPeriod;
365366

366-
sortitionModule.createTree(bytes32(courtID), _sortitionExtraData);
367+
sortitionModule.createTree(courtID, _sortitionExtraData);
367368

368369
// Update the parent.
369370
courts[_parent].children.push(courtID);
@@ -463,16 +464,16 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
463464
/// @param _newStake The new stake.
464465
/// Note that the existing delayed stake will be nullified as non-relevant.
465466
function setStake(uint96 _courtID, uint256 _newStake) external virtual whenNotPaused {
466-
_setStake(msg.sender, _courtID, _newStake, OnError.Revert);
467+
_setStake(msg.sender, _courtID, _newStake, false, OnError.Revert);
467468
}
468469

469-
/// @dev Sets the stake of a specified account in a court, typically to apply a delayed stake or unstake inactive jurors.
470+
/// @dev Sets the stake of a specified account in a court without delaying stake changes, typically to apply a delayed stake or unstake inactive jurors.
470471
/// @param _account The account whose stake is being set.
471472
/// @param _courtID The ID of the court.
472473
/// @param _newStake The new stake.
473474
function setStakeBySortitionModule(address _account, uint96 _courtID, uint256 _newStake) external {
474475
if (msg.sender != address(sortitionModule)) revert SortitionModuleOnly();
475-
_setStake(_account, _courtID, _newStake, OnError.Return);
476+
_setStake(_account, _courtID, _newStake, true, OnError.Return);
476477
}
477478

478479
/// @dev Transfers PNK to the juror by SortitionModule.
@@ -606,13 +607,14 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
606607
uint256 startIndex = round.drawIterations; // for gas: less storage reads
607608
uint256 i;
608609
while (i < _iterations && round.drawnJurors.length < round.nbVotes) {
609-
address drawnAddress = disputeKit.draw(_disputeID, startIndex + i++);
610+
(address drawnAddress, uint96 fromSubcourtID) = disputeKit.draw(_disputeID, startIndex + i++);
610611
if (drawnAddress == address(0)) {
611612
continue;
612613
}
613614
sortitionModule.lockStake(drawnAddress, round.pnkAtStakePerJuror);
614615
emit Draw(drawnAddress, _disputeID, currentRound, round.drawnJurors.length);
615616
round.drawnJurors.push(drawnAddress);
617+
round.drawnJurorFromCourtIDs.push(fromSubcourtID != 0 ? fromSubcourtID : dispute.courtID);
616618
if (round.drawnJurors.length == round.nbVotes) {
617619
sortitionModule.postDrawHook(_disputeID, currentRound);
618620
}
@@ -775,7 +777,12 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
775777
sortitionModule.unlockStake(account, penalty);
776778

777779
// Apply the penalty to the staked PNKs.
778-
(uint256 pnkBalance, uint256 availablePenalty) = sortitionModule.penalizeStake(account, penalty);
780+
uint96 penalizedInCourtID = round.drawnJurorFromCourtIDs[_params.repartition];
781+
(uint256 pnkBalance, uint256 newCourtStake, uint256 availablePenalty) = sortitionModule.setStakePenalty(
782+
account,
783+
penalizedInCourtID,
784+
penalty
785+
);
779786
_params.pnkPenaltiesInRound += availablePenalty;
780787
emit TokenAndETHShift(
781788
account,
@@ -786,10 +793,15 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
786793
0,
787794
round.feeToken
788795
);
789-
// Unstake the juror from all courts if he was inactive or his balance can't cover penalties anymore.
796+
790797
if (pnkBalance == 0 || !disputeKit.isVoteActive(_params.disputeID, _params.round, _params.repartition)) {
791-
sortitionModule.setJurorInactive(account);
798+
// The juror is inactive or their balance is can't cover penalties anymore, unstake them from all courts.
799+
sortitionModule.forcedUnstakeAllCourts(account);
800+
} else if (newCourtStake < courts[penalizedInCourtID].minStake) {
801+
// The juror's balance fell below the court minStake, unstake them from the court.
802+
sortitionModule.forcedUnstake(account, penalizedInCourtID);
792803
}
804+
793805
if (_params.repartition == _params.numberOfVotesInRound - 1 && _params.coherentCount == 0) {
794806
// No one was coherent, send the rewards to the owner.
795807
_transferFeeToken(round.feeToken, payable(owner), round.totalFeesForJurors);
@@ -1130,9 +1142,16 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
11301142
/// @param _account The account to set the stake for.
11311143
/// @param _courtID The ID of the court to set the stake for.
11321144
/// @param _newStake The new stake.
1145+
/// @param _noDelay True if the stake change should not be delayed.
11331146
/// @param _onError Whether to revert or return false on error.
11341147
/// @return Whether the stake was successfully set or not.
1135-
function _setStake(address _account, uint96 _courtID, uint256 _newStake, OnError _onError) internal returns (bool) {
1148+
function _setStake(
1149+
address _account,
1150+
uint96 _courtID,
1151+
uint256 _newStake,
1152+
bool _noDelay,
1153+
OnError _onError
1154+
) internal returns (bool) {
11361155
if (_courtID == FORKING_COURT || _courtID >= courts.length) {
11371156
_stakingFailed(_onError, StakingResult.CannotStakeInThisCourt); // Staking directly into the forking court is not allowed.
11381157
return false;
@@ -1144,7 +1163,8 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
11441163
(uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) = sortitionModule.validateStake(
11451164
_account,
11461165
_courtID,
1147-
_newStake
1166+
_newStake,
1167+
_noDelay
11481168
);
11491169
if (stakingResult != StakingResult.Successful && stakingResult != StakingResult.Delayed) {
11501170
_stakingFailed(_onError, stakingResult);

contracts/src/arbitration/KlerosCoreNeo.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ contract KlerosCoreNeo is KlerosCoreBase {
108108
/// Note that the existing delayed stake will be nullified as non-relevant.
109109
function setStake(uint96 _courtID, uint256 _newStake) external override whenNotPaused {
110110
if (jurorNft.balanceOf(msg.sender) == 0) revert NotEligibleForStaking();
111-
super._setStake(msg.sender, _courtID, _newStake, OnError.Revert);
111+
super._setStake(msg.sender, _courtID, _newStake, false, OnError.Revert);
112112
}
113113

114114
// ************************************* //

0 commit comments

Comments
 (0)