Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions contracts/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ The format is based on [Common Changelog](https://common-changelog.org/).
- Bump `hardhat` to v2.26.2 ([#2069](https://github.com/kleros/kleros-v2/issues/2069))
- Bump `@kleros/vea-contracts` to v0.7.0 ([#2073](https://github.com/kleros/kleros-v2/issues/2073))

### Added

- Allow the dispute kits to force an early court jump and to override the number of votes after an appeal (future-proofing) ([#2110](https://github.com/kleros/kleros-v2/issues/2110))

### Fixed

- Do not pass to Voting period if all the commits are cast because it breaks the current Shutter auto-reveal process. ([#2085](https://github.com/kleros/kleros-v2/issues/2085))
Expand Down
2 changes: 1 addition & 1 deletion contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const config: HardhatUserConfig = {
viaIR: process.env.VIA_IR !== "false", // Defaults to true
optimizer: {
enabled: true,
runs: 10000,
runs: 2000,
},
outputSelection: {
"*": {
Expand Down
74 changes: 55 additions & 19 deletions contracts/src/arbitration/KlerosCoreBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -639,24 +639,17 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
Round storage round = dispute.rounds[dispute.rounds.length - 1];
if (msg.sender != address(disputeKits[round.disputeKitID])) revert DisputeKitOnly();

uint96 newCourtID = dispute.courtID;
uint256 newDisputeKitID = round.disputeKitID;

// Warning: the extra round must be created before calling disputeKit.createDispute()
Round storage extraRound = dispute.rounds.push();

if (round.nbVotes >= courts[newCourtID].jurorsForCourtJump) {
// Jump to parent court.
newCourtID = courts[newCourtID].parent;

if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {
// Switch to classic dispute kit if parent court doesn't support the current one.
newDisputeKitID = DISPUTE_KIT_CLASSIC;
}

if (newCourtID != dispute.courtID) {
emit CourtJump(_disputeID, dispute.rounds.length - 1, dispute.courtID, newCourtID);
}
(uint96 newCourtID, uint256 newDisputeKitID, bool courtJump, ) = _getCourtAndDisputeKitJumps(
dispute,
round,
courts[dispute.courtID],
_disputeID
);
if (courtJump) {
emit CourtJump(_disputeID, dispute.rounds.length - 1, dispute.courtID, newCourtID);
}

dispute.courtID = newCourtID;
Expand Down Expand Up @@ -934,17 +927,25 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
Dispute storage dispute = disputes[_disputeID];
Round storage round = dispute.rounds[dispute.rounds.length - 1];
Court storage court = courts[dispute.courtID];
if (round.nbVotes >= court.jurorsForCourtJump) {

(, uint256 newDisputeKitID, bool courtJump, ) = _getCourtAndDisputeKitJumps(dispute, round, court, _disputeID);

uint256 nbVotesAfterAppeal = disputeKits[newDisputeKitID].getNbVotesAfterAppeal(
disputeKits[round.disputeKitID],
round.nbVotes
);

if (courtJump) {
// Jump to parent court.
if (dispute.courtID == GENERAL_COURT) {
// TODO: Handle the forking when appealed in General court.
cost = NON_PAYABLE_AMOUNT; // Get the cost of the parent court.
} else {
cost = courts[court.parent].feeForJuror * ((round.nbVotes * 2) + 1);
cost = courts[court.parent].feeForJuror * nbVotesAfterAppeal;
}
} else {
// Stay in current court.
cost = court.feeForJuror * ((round.nbVotes * 2) + 1);
cost = court.feeForJuror * nbVotesAfterAppeal;
}
}

Expand Down Expand Up @@ -1033,7 +1034,7 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
Round storage round = dispute.rounds[dispute.rounds.length - 1];
Court storage court = courts[dispute.courtID];

if (round.nbVotes < court.jurorsForCourtJump) {
if (!_isCourtJumping(round, court, _disputeID)) {
return false;
}

Expand All @@ -1053,6 +1054,41 @@ abstract contract KlerosCoreBase is IArbitratorV2, Initializable, UUPSProxiable
// * Internal * //
// ************************************* //

/// @dev Returns true if the round is jumping to a parent court.
/// @param _round The round to check.
/// @param _court The court to check.
/// @return Whether the round is jumping to a parent court or not.
function _isCourtJumping(
Round storage _round,
Court storage _court,
uint256 _disputeID
) internal view returns (bool) {
return
disputeKits[_round.disputeKitID].earlyCourtJump(_disputeID) || _round.nbVotes >= _court.jurorsForCourtJump;
}

function _getCourtAndDisputeKitJumps(
Dispute storage _dispute,
Round storage _round,
Court storage _court,
uint256 _disputeID
) internal view returns (uint96 newCourtID, uint256 newDisputeKitID, bool courtJump, bool disputeKitJump) {
newCourtID = _dispute.courtID;
newDisputeKitID = _round.disputeKitID;

if (!_isCourtJumping(_round, _court, _disputeID)) return (newCourtID, newDisputeKitID, false, false);

// Jump to parent court.
newCourtID = courts[newCourtID].parent;
courtJump = true;

if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {
// Switch to classic dispute kit if parent court doesn't support the current one.
newDisputeKitID = DISPUTE_KIT_CLASSIC;
disputeKitJump = true;
}
}

/// @dev Internal function to transfer fee tokens (ETH or ERC20)
/// @param _feeToken The token to transfer (NATIVE_CURRENCY for ETH).
/// @param _recipient The recipient address.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,22 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
((appealPeriodEnd - appealPeriodStart) * LOSER_APPEAL_PERIOD_MULTIPLIER) / ONE_BASIS_POINT);
}

/// @dev Returns true if the dispute is jumping to a parent court.
/// @return Whether the dispute is jumping to a parent court or not.
function earlyCourtJump(uint256 /* _coreDisputeID */) external pure override returns (bool) {
return false;
}

/// @dev Returns the number of votes after the appeal.
/// @param _currentNbVotes The number of votes before the appeal.
/// @return The number of votes after the appeal.
function getNbVotesAfterAppeal(
IDisputeKit /* _previousDisputeKit */,
uint256 _currentNbVotes
) external pure override returns (uint256) {
return (_currentNbVotes * 2) + 1;
}

/// @dev Returns true if the specified voter was active in this round.
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
/// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.
Expand Down
14 changes: 14 additions & 0 deletions contracts/src/arbitration/interfaces/IDisputeKit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,20 @@ interface IDisputeKit {
/// @return Whether the appeal funding is finished.
function isAppealFunded(uint256 _coreDisputeID) external view returns (bool);

/// @dev Returns true if the dispute is jumping to a parent court.
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
/// @return Whether the dispute is jumping to a parent court or not.
function earlyCourtJump(uint256 _coreDisputeID) external view returns (bool);

/// @dev Returns the number of votes after the appeal.
/// @param _previousDisputeKit The previous Dispute Kit.
/// @param _currentNbVotes The number of votes before the appeal.
/// @return The number of votes after the appeal.
function getNbVotesAfterAppeal(
IDisputeKit _previousDisputeKit,
uint256 _currentNbVotes
) external view returns (uint256); // TODO: remove previousDisputeKit

/// @dev Returns true if the specified voter was active in this round.
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
/// @param _coreRoundID The ID of the round in Kleros Core, not in the Dispute Kit.
Expand Down
Loading