Skip to content

Commit fac9901

Browse files
committed
feat: delegate the next round settings logic to the dispute kit
1 parent c40c12c commit fac9901

File tree

9 files changed

+159
-127
lines changed

9 files changed

+159
-127
lines changed

contracts/hardhat.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const config: HardhatUserConfig = {
3232
viaIR: process.env.VIA_IR !== "false", // Defaults to true
3333
optimizer: {
3434
enabled: true,
35-
runs: 800, // Constrained by the size of the KlerosCore contract
35+
runs: 1000, // Constrained by the size of the KlerosCore contract
3636
},
3737
outputSelection: {
3838
"*": {

contracts/src/arbitration/KlerosCore.sol

Lines changed: 60 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ contract KlerosCore is IArbitratorV2, Initializable, UUPSProxiable {
785785
Round storage extraRound = dispute.rounds.push();
786786
uint256 extraRoundID = dispute.rounds.length - 1;
787787

788-
(uint96 newCourtID, uint256 newDisputeKitID, bool courtJump, ) = _getCourtAndDisputeKitJumps(
788+
(uint96 newCourtID, uint256 newDisputeKitID, , bool courtJump, ) = _getCourtAndDisputeKitJumps(
789789
dispute,
790790
round,
791791
courts[dispute.courtID],
@@ -1086,11 +1086,11 @@ contract KlerosCore is IArbitratorV2, Initializable, UUPSProxiable {
10861086
Round storage round = dispute.rounds[dispute.rounds.length - 1];
10871087
Court storage court = courts[dispute.courtID];
10881088

1089-
(, uint256 newDisputeKitID, bool courtJump, ) = _getCourtAndDisputeKitJumps(dispute, round, court, _disputeID);
1090-
1091-
uint256 nbVotesAfterAppeal = disputeKits[newDisputeKitID].getNbVotesAfterAppeal(
1092-
disputeKits[round.disputeKitID],
1093-
round.nbVotes
1089+
(, , uint256 nbVotesAfterAppeal, bool courtJump, ) = _getCourtAndDisputeKitJumps(
1090+
dispute,
1091+
round,
1092+
court,
1093+
_disputeID
10941094
);
10951095

10961096
if (courtJump) {
@@ -1180,20 +1180,36 @@ contract KlerosCore is IArbitratorV2, Initializable, UUPSProxiable {
11801180
return dispute.rounds[dispute.rounds.length - 1].nbVotes;
11811181
}
11821182

1183-
/// @notice Returns true if the dispute kit will be switched to a parent DK.
1184-
/// @param _disputeID The ID of the dispute.
1185-
/// @return Whether DK will be switched or not.
1186-
function isDisputeKitJumping(uint256 _disputeID) external view returns (bool) {
1183+
/// @notice Checks whether a dispute will jump to new court/DK and enforces a compatibility check.
1184+
/// @param _disputeID Dispute ID.
1185+
/// @return newCourtID Court ID after jump.
1186+
/// @return newDisputeKitID Dispute kit ID after jump.
1187+
/// @return newRoundNbVotes The number of votes in the new round.
1188+
/// @return courtJump Whether the dispute jumps to a new court or not.
1189+
/// @return disputeKitJump Whether the dispute jumps to a new dispute kit or not.
1190+
function getCourtAndDisputeKitJumps(
1191+
uint256 _disputeID
1192+
)
1193+
external
1194+
view
1195+
returns (
1196+
uint96 newCourtID,
1197+
uint256 newDisputeKitID,
1198+
uint256 newRoundNbVotes,
1199+
bool courtJump,
1200+
bool disputeKitJump
1201+
)
1202+
{
11871203
Dispute storage dispute = disputes[_disputeID];
11881204
Round storage round = dispute.rounds[dispute.rounds.length - 1];
11891205
Court storage court = courts[dispute.courtID];
11901206

1191-
if (!_isCourtJumping(round, court, _disputeID)) {
1192-
return false;
1193-
}
1194-
1195-
// Jump if the parent court doesn't support the current DK.
1196-
return !courts[court.parent].supportedDisputeKits[round.disputeKitID];
1207+
(newCourtID, newDisputeKitID, newRoundNbVotes, courtJump, disputeKitJump) = _getCourtAndDisputeKitJumps(
1208+
dispute,
1209+
round,
1210+
court,
1211+
_disputeID
1212+
);
11971213
}
11981214

11991215
/// @notice Returns the length of disputeKits array.
@@ -1214,51 +1230,47 @@ contract KlerosCore is IArbitratorV2, Initializable, UUPSProxiable {
12141230
// * Internal * //
12151231
// ************************************* //
12161232

1217-
/// @notice Returns true if the round is jumping to a parent court.
1218-
/// @param _round The round to check.
1219-
/// @param _court The court to check.
1220-
/// @return Whether the round is jumping to a parent court or not.
1221-
function _isCourtJumping(
1222-
Round storage _round,
1223-
Court storage _court,
1224-
uint256 _disputeID
1225-
) internal view returns (bool) {
1226-
return
1227-
disputeKits[_round.disputeKitID].earlyCourtJump(_disputeID) || _round.nbVotes >= _court.jurorsForCourtJump;
1228-
}
1229-
1230-
/// @notice Checks whether a dispute will jump to new court/DK, and returns new court and DK.
1233+
/// @notice Checks whether a dispute will jump to new court/DK and enforces a compatibility check.
12311234
/// @param _dispute Dispute data.
12321235
/// @param _round Round ID.
12331236
/// @param _court Current court ID.
12341237
/// @param _disputeID Dispute ID.
12351238
/// @return newCourtID Court ID after jump.
12361239
/// @return newDisputeKitID Dispute kit ID after jump.
1240+
/// @return newRoundNbVotes The number of votes in the new round.
12371241
/// @return courtJump Whether the dispute jumps to a new court or not.
12381242
/// @return disputeKitJump Whether the dispute jumps to a new dispute kit or not.
12391243
function _getCourtAndDisputeKitJumps(
12401244
Dispute storage _dispute,
12411245
Round storage _round,
12421246
Court storage _court,
12431247
uint256 _disputeID
1244-
) internal view returns (uint96 newCourtID, uint256 newDisputeKitID, bool courtJump, bool disputeKitJump) {
1245-
newCourtID = _dispute.courtID;
1246-
newDisputeKitID = _round.disputeKitID;
1247-
1248-
if (!_isCourtJumping(_round, _court, _disputeID)) return (newCourtID, newDisputeKitID, false, false);
1249-
1250-
// Jump to parent court.
1251-
newCourtID = courts[newCourtID].parent;
1252-
courtJump = true;
1253-
1254-
if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {
1255-
// The current Dispute Kit is not compatible with the new court, jump to another Dispute Kit.
1256-
newDisputeKitID = disputeKits[_round.disputeKitID].getJumpDisputeKitID();
1257-
if (newDisputeKitID == NULL_DISPUTE_KIT || !courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {
1258-
// The new Dispute Kit is not defined or still not compatible, fall back to `DisputeKitClassic` which is always supported.
1259-
newDisputeKitID = DISPUTE_KIT_CLASSIC;
1260-
}
1261-
disputeKitJump = true;
1248+
)
1249+
internal
1250+
view
1251+
returns (
1252+
uint96 newCourtID,
1253+
uint256 newDisputeKitID,
1254+
uint256 newRoundNbVotes,
1255+
bool courtJump,
1256+
bool disputeKitJump
1257+
)
1258+
{
1259+
uint256 disputeKitID = _round.disputeKitID;
1260+
(newCourtID, newDisputeKitID, newRoundNbVotes, courtJump, disputeKitJump) = disputeKits[disputeKitID]
1261+
.getCourtAndDisputeKitJumps(
1262+
_disputeID,
1263+
_dispute.courtID,
1264+
_court.parent,
1265+
_court.jurorsForCourtJump,
1266+
_round.nbVotes
1267+
);
1268+
1269+
// Ensure compatibility between the next round's court and dispute kit.
1270+
if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID] || newDisputeKitID == NULL_DISPUTE_KIT) {
1271+
// Fall back to `DisputeKitClassic` which is always supported.
1272+
newDisputeKitID = DISPUTE_KIT_CLASSIC;
1273+
disputeKitJump = (newDisputeKitID != disputeKitID);
12621274
}
12631275
}
12641276

contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,8 @@ contract DisputeKitClassic is DisputeKitClassicBase {
2626
/// @param _owner The owner's address.
2727
/// @param _core The KlerosCore arbitrator.
2828
/// @param _wNative The wrapped native token address, typically wETH.
29-
/// @param _jumpDisputeKitID The ID of the dispute kit to switch to after the court jump.
30-
function initialize(
31-
address _owner,
32-
KlerosCore _core,
33-
address _wNative,
34-
uint256 _jumpDisputeKitID
35-
) external initializer {
36-
__DisputeKitClassicBase_initialize(_owner, _core, _wNative, _jumpDisputeKitID);
29+
function initialize(address _owner, KlerosCore _core, address _wNative) external initializer {
30+
__DisputeKitClassicBase_initialize(_owner, _core, _wNative);
3731
}
3832

3933
// ************************ //

contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol

Lines changed: 60 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
5858
bool currentRound; // True if the dispute's current round is active on this Dispute Kit. False if the dispute has jumped to another Dispute Kit.
5959
}
6060

61+
struct NextRoundSettings {
62+
uint256 nbVotes; // The number of votes in the next round.
63+
uint256 jumpDisputeKitID; // The ID of the dispute kit in Kleros Core disputeKits array that the dispute should jump to.
64+
uint96 jumpCourtID; // The ID of the court in Kleros Core courts array that the dispute should jump to.
65+
bool earlyDisputeKitJump; // True if the dispute should jump to a different dispute kit before jumping to an incompatible court, false otherwise.
66+
bool earlyCourtJump; // True if the court should jump to a different court before exceeding the current `court.jurorsForCourtJump` threshold, false otherwise.
67+
bool enabled; // True if the settings are enabled, false otherwise.
68+
}
69+
6170
// ************************************* //
6271
// * Storage * //
6372
// ************************************* //
@@ -73,7 +82,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
7382
bool public singleDrawPerJuror; // Whether each juror can only draw once per dispute, false by default.
7483
mapping(uint256 coreDisputeID => Active) public coreDisputeIDToActive; // Active status of the dispute and the current round.
7584
address public wNative; // The wrapped native token for safeSend().
76-
uint256 public jumpDisputeKitID; // The ID of the dispute kit in Kleros Core disputeKits array that the dispute should switch to after the court jump, in case the new court doesn't support this dispute kit.
85+
mapping(uint96 currentCourtID => NextRoundSettings) public courtIDToNextRoundSettings; // The settings for the next round.
7786

7887
uint256[50] private __gap; // Reserved slots for future upgrades.
7988

@@ -149,17 +158,14 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
149158
/// @param _owner The owner's address.
150159
/// @param _core The KlerosCore arbitrator.
151160
/// @param _wNative The wrapped native token address, typically wETH.
152-
/// @param _jumpDisputeKitID The ID of the dispute kit to switch to after the court jump.
153161
function __DisputeKitClassicBase_initialize(
154162
address _owner,
155163
KlerosCore _core,
156-
address _wNative,
157-
uint256 _jumpDisputeKitID
164+
address _wNative
158165
) internal onlyInitializing {
159166
owner = _owner;
160167
core = _core;
161168
wNative = _wNative;
162-
jumpDisputeKitID = _jumpDisputeKitID;
163169
}
164170

165171
// ************************ //
@@ -187,10 +193,14 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
187193
core = KlerosCore(_core);
188194
}
189195

190-
/// @notice Changes the dispute kit ID used for the jump.
191-
/// @param _jumpDisputeKitID The new value for the `jumpDisputeKitID` storage variable.
192-
function changeJumpDisputeKitID(uint256 _jumpDisputeKitID) external onlyByOwner {
193-
jumpDisputeKitID = _jumpDisputeKitID;
196+
/// @notice Changes the settings for the next round.
197+
/// @param _currentCourtID The ID of the current court.
198+
/// @param _nextRoundSettings The settings for the next round.
199+
function changeNextRoundSettings(
200+
uint96 _currentCourtID,
201+
NextRoundSettings memory _nextRoundSettings
202+
) external onlyByOwner {
203+
courtIDToNextRoundSettings[_currentCourtID] = _nextRoundSettings;
194204
}
195205

196206
// ************************************* //
@@ -420,7 +430,8 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
420430
// At least two sides are fully funded.
421431
round.feeRewards = round.feeRewards - appealCost;
422432

423-
if (core.isDisputeKitJumping(_coreDisputeID)) {
433+
(, , , , bool isDisputeKitJumping) = core.getCourtAndDisputeKitJumps(_coreDisputeID);
434+
if (isDisputeKitJumping) {
424435
// Don't create a new round in case of a jump, and remove local dispute from the flow.
425436
coreDisputeIDToActive[_coreDisputeID].currentRound = false;
426437
} else {
@@ -617,22 +628,45 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
617628
}
618629

619630
/// @inheritdoc IDisputeKit
620-
function earlyCourtJump(uint256 /* _coreDisputeID */) external pure override returns (bool) {
621-
return false;
622-
}
623-
624-
/// @inheritdoc IDisputeKit
625-
function getNbVotesAfterAppeal(
626-
IDisputeKit /* _previousDisputeKit */,
627-
uint256 _currentNbVotes
628-
) external pure override returns (uint256) {
629-
return (_currentNbVotes * 2) + 1;
630-
}
631-
632-
/// @inheritdoc IDisputeKit
633-
function getJumpDisputeKitID() external view override returns (uint256) {
634-
// Fall back to classic DK in case the jump ID is not defined.
635-
return jumpDisputeKitID == 0 ? DISPUTE_KIT_CLASSIC : jumpDisputeKitID;
631+
function getCourtAndDisputeKitJumps(
632+
uint256 /* _coreDisputeID */,
633+
uint96 _currentCourtID,
634+
uint96 _parentCourtID,
635+
uint256 _currentCourtJurorsForJump,
636+
uint256 _currentRoundNbVotes
637+
)
638+
public
639+
view
640+
virtual
641+
override
642+
returns (
643+
uint96 newCourtID,
644+
uint256 newDisputeKitID,
645+
uint256 newRoundNbVotes,
646+
bool courtJump,
647+
bool disputeKitJump
648+
)
649+
{
650+
NextRoundSettings storage nextRoundSettings = courtIDToNextRoundSettings[_currentCourtID];
651+
if (nextRoundSettings.enabled) {
652+
newRoundNbVotes = nextRoundSettings.nbVotes;
653+
newCourtID = nextRoundSettings.jumpCourtID;
654+
newDisputeKitID = nextRoundSettings.jumpDisputeKitID;
655+
courtJump = nextRoundSettings.earlyCourtJump;
656+
disputeKitJump = nextRoundSettings.earlyDisputeKitJump;
657+
}
658+
if (nextRoundSettings.nbVotes == 0) {
659+
newRoundNbVotes = (_currentRoundNbVotes * 2) + 1;
660+
}
661+
if (!courtJump) {
662+
courtJump = (newRoundNbVotes >= _currentCourtJurorsForJump);
663+
}
664+
if (newCourtID == 0) {
665+
newCourtID = courtJump ? _parentCourtID : _currentCourtID;
666+
}
667+
if (newDisputeKitID == 0) {
668+
newDisputeKitID = DISPUTE_KIT_CLASSIC;
669+
}
636670
}
637671

638672
/// @inheritdoc IDisputeKit

contracts/src/arbitration/dispute-kits/DisputeKitGated.sol

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,8 @@ contract DisputeKitGated is DisputeKitClassicBase {
5050
/// @param _owner The owner's address.
5151
/// @param _core The KlerosCore arbitrator.
5252
/// @param _wNative The wrapped native token address, typically wETH.
53-
/// @param _jumpDisputeKitID The ID of the dispute kit to switch to after the court jump.
54-
function initialize(
55-
address _owner,
56-
KlerosCore _core,
57-
address _wNative,
58-
uint256 _jumpDisputeKitID
59-
) external initializer {
60-
__DisputeKitClassicBase_initialize(_owner, _core, _wNative, _jumpDisputeKitID);
53+
function initialize(address _owner, KlerosCore _core, address _wNative) external initializer {
54+
__DisputeKitClassicBase_initialize(_owner, _core, _wNative);
6155
supportedTokens[NO_TOKEN_GATE] = true; // Allows disputes without token gating
6256
}
6357

contracts/src/arbitration/dispute-kits/DisputeKitGatedShutter.sol

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,8 @@ contract DisputeKitGatedShutter is DisputeKitClassicBase {
7979
/// @param _owner The owner's address.
8080
/// @param _core The KlerosCore arbitrator.
8181
/// @param _wNative The wrapped native token address, typically wETH.
82-
/// @param _jumpDisputeKitID The ID of the dispute kit to switch to after the court jump.
83-
function initialize(
84-
address _owner,
85-
KlerosCore _core,
86-
address _wNative,
87-
uint256 _jumpDisputeKitID
88-
) external initializer {
89-
__DisputeKitClassicBase_initialize(_owner, _core, _wNative, _jumpDisputeKitID);
82+
function initialize(address _owner, KlerosCore _core, address _wNative) external initializer {
83+
__DisputeKitClassicBase_initialize(_owner, _core, _wNative);
9084
supportedTokens[NO_TOKEN_GATE] = true; // Allows disputes without token gating
9185
}
9286

contracts/src/arbitration/dispute-kits/DisputeKitShutter.sol

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,8 @@ contract DisputeKitShutter is DisputeKitClassicBase {
6060
/// @param _owner The owner's address.
6161
/// @param _core The KlerosCore arbitrator.
6262
/// @param _wNative The wrapped native token address, typically wETH.
63-
/// @param _jumpDisputeKitID The ID of the dispute kit to switch to after the court jump.
64-
function initialize(
65-
address _owner,
66-
KlerosCore _core,
67-
address _wNative,
68-
uint256 _jumpDisputeKitID
69-
) external initializer {
70-
__DisputeKitClassicBase_initialize(_owner, _core, _wNative, _jumpDisputeKitID);
63+
function initialize(address _owner, KlerosCore _core, address _wNative) external initializer {
64+
__DisputeKitClassicBase_initialize(_owner, _core, _wNative);
7165
}
7266

7367
// ************************ //

contracts/src/arbitration/dispute-kits/DisputeKitSybilResistant.sol

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,13 @@ contract DisputeKitSybilResistant is DisputeKitClassicBase {
4040
/// @param _core The KlerosCore arbitrator.
4141
/// @param _poh The Proof of Humanity registry.
4242
/// @param _wNative The wrapped native token address, typically wETH.
43-
/// @param _jumpDisputeKitID The ID of the dispute kit to switch to after the court jump.
4443
function initialize(
4544
address _owner,
4645
KlerosCore _core,
4746
IProofOfHumanity _poh,
48-
address _wNative,
49-
uint256 _jumpDisputeKitID
47+
address _wNative
5048
) external initializer {
51-
__DisputeKitClassicBase_initialize(_owner, _core, _wNative, _jumpDisputeKitID);
49+
__DisputeKitClassicBase_initialize(_owner, _core, _wNative);
5250
poh = _poh;
5351
singleDrawPerJuror = true;
5452
}

0 commit comments

Comments
 (0)