Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
8 changes: 7 additions & 1 deletion contracts/src/arbitration/DisputeTemplateRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ contract DisputeTemplateRegistry is IDisputeTemplateRegistry, UUPSProxiable, Ini
// ************************************* //

modifier onlyByGovernor() {
require(governor == msg.sender, "Governor only");
if (governor != msg.sender) revert GovernorOnly();
_;
}

Expand Down Expand Up @@ -80,4 +80,10 @@ contract DisputeTemplateRegistry is IDisputeTemplateRegistry, UUPSProxiable, Ini
templateId = templates++;
emit DisputeTemplate(templateId, _templateTag, _templateData, _templateDataMappings);
}

// ************************************* //
// * Errors * //
// ************************************* //

error GovernorOnly();
}
61 changes: 42 additions & 19 deletions contracts/src/arbitration/KlerosGovernor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,18 @@ contract KlerosGovernor is IArbitrableV2 {

modifier duringSubmissionPeriod() {
uint256 offset = sessions[sessions.length - 1].durationOffset;
require(block.timestamp - lastApprovalTime <= submissionTimeout + offset, "Submission time has ended.");
if (block.timestamp - lastApprovalTime > submissionTimeout + offset) revert SubmissionTimeHasEnded();
_;
}

modifier duringApprovalPeriod() {
uint256 offset = sessions[sessions.length - 1].durationOffset;
require(block.timestamp - lastApprovalTime > submissionTimeout + offset, "Approval time not started yet.");
if (block.timestamp - lastApprovalTime <= submissionTimeout + offset) revert ApprovalTimeNotStarted();
_;
}

modifier onlyByGovernor() {
require(address(this) == msg.sender, "Only the governor allowed.");
if (address(this) != msg.sender) revert GovernorOnly();
_;
}

Expand Down Expand Up @@ -208,14 +208,14 @@ contract KlerosGovernor is IArbitrableV2 {
uint256[] memory _dataSize,
string memory _description
) external payable duringSubmissionPeriod {
require(_target.length == _value.length, "Wrong input: target and value");
require(_target.length == _dataSize.length, "Wrong input: target and datasize");
if (_target.length != _value.length) revert WrongInputTargetAndValue();
if (_target.length != _dataSize.length) revert WrongInputTargetAndDatasize();
Session storage session = sessions[sessions.length - 1];
Submission storage submission = submissions.push();
submission.submitter = payable(msg.sender);
// Do the assignment first to avoid creating a new variable and bypass a 'stack too deep' error.
submission.deposit = submissionBaseDeposit + arbitrator.arbitrationCost(arbitratorExtraData);
require(msg.value >= submission.deposit, "Not enough ETH to cover deposit");
if (msg.value < submission.deposit) revert InsufficientDeposit();

bytes32 listHash;
bytes32 currentTxHash;
Expand All @@ -233,7 +233,7 @@ contract KlerosGovernor is IArbitrableV2 {
currentTxHash = keccak256(abi.encodePacked(transaction.target, transaction.value, transaction.data));
listHash = keccak256(abi.encodePacked(currentTxHash, listHash));
}
require(!session.alreadySubmitted[listHash], "List already submitted");
if (session.alreadySubmitted[listHash]) revert ListAlreadySubmitted();
session.alreadySubmitted[listHash] = true;
submission.listHash = listHash;
submission.submissionTime = block.timestamp;
Expand All @@ -256,11 +256,11 @@ contract KlerosGovernor is IArbitrableV2 {
function withdrawTransactionList(uint256 _submissionID, bytes32 _listHash) external {
Session storage session = sessions[sessions.length - 1];
Submission storage submission = submissions[session.submittedLists[_submissionID]];
require(block.timestamp - lastApprovalTime <= submissionTimeout / 2, "Should be in first half");
// This require statement is an extra check to prevent _submissionID linking to the wrong list because of index swap during withdrawal.
require(submission.listHash == _listHash, "Wrong list hash");
require(submission.submitter == msg.sender, "Only submitter can withdraw");
require(block.timestamp - submission.submissionTime <= withdrawTimeout, "Withdrawing time has passed.");
if (block.timestamp - lastApprovalTime > submissionTimeout / 2) revert ShouldOnlyWithdrawInFirstHalf();
// This is an extra check to prevent _submissionID linking to the wrong list because of index swap during withdrawal.
if (submission.listHash != _listHash) revert WrongListHash();
if (submission.submitter != msg.sender) revert OnlySubmitterCanWithdraw();
if (block.timestamp - submission.submissionTime > withdrawTimeout) revert WithdrawingTimeHasPassed();
session.submittedLists[_submissionID] = session.submittedLists[session.submittedLists.length - 1];
session.alreadySubmitted[_listHash] = false;
session.submittedLists.pop();
Expand All @@ -273,7 +273,7 @@ contract KlerosGovernor is IArbitrableV2 {
/// If nothing was submitted changes session.
function executeSubmissions() external duringApprovalPeriod {
Session storage session = sessions[sessions.length - 1];
require(session.status == Status.NoDispute, "Already disputed");
if (session.status != Status.NoDispute) revert AlreadyDisputed();
if (session.submittedLists.length == 0) {
lastApprovalTime = block.timestamp;
session.status = Status.Resolved;
Expand Down Expand Up @@ -310,9 +310,9 @@ contract KlerosGovernor is IArbitrableV2 {
/// Note If the final ruling is "0" nothing is approved and deposits will stay locked in the contract.
function rule(uint256 _disputeID, uint256 _ruling) external override {
Session storage session = sessions[sessions.length - 1];
require(msg.sender == address(arbitrator), "Only arbitrator allowed");
require(session.status == Status.DisputeCreated, "Wrong status");
require(_ruling <= session.submittedLists.length, "Ruling is out of bounds.");
if (msg.sender != address(arbitrator)) revert OnlyArbitratorAllowed();
if (session.status != Status.DisputeCreated) revert NotDisputed();
if (_ruling > session.submittedLists.length) revert RulingOutOfBounds();

if (_ruling != 0) {
Submission storage submission = submissions[session.submittedLists[_ruling - 1]];
Expand All @@ -338,16 +338,16 @@ contract KlerosGovernor is IArbitrableV2 {
/// @param _count Number of transactions to execute. Executes until the end if set to "0" or number higher than number of transactions in the list.
function executeTransactionList(uint256 _listID, uint256 _cursor, uint256 _count) external {
Submission storage submission = submissions[_listID];
require(submission.approved, "Should be approved");
require(block.timestamp - submission.approvalTime <= executionTimeout, "Time to execute has passed");
if (!submission.approved) revert SubmissionNotApproved();
if (block.timestamp - submission.approvalTime > executionTimeout) revert TimeToExecuteHasPassed();
for (uint256 i = _cursor; i < submission.txs.length && (_count == 0 || i < _cursor + _count); i++) {
Transaction storage transaction = submission.txs[i];
uint256 expendableFunds = getExpendableFunds();
if (!transaction.executed && transaction.value <= expendableFunds) {
(bool callResult, ) = transaction.target.call{value: transaction.value}(transaction.data);
// An extra check to prevent re-entrancy through target call.
if (callResult == true) {
require(!transaction.executed, "Already executed");
if (transaction.executed) revert AlreadyExecuted();
transaction.executed = true;
}
}
Expand Down Expand Up @@ -407,4 +407,27 @@ contract KlerosGovernor is IArbitrableV2 {
function getCurrentSessionNumber() external view returns (uint256) {
return sessions.length - 1;
}

// ************************************* //
// * Errors * //
// ************************************* //

error SubmissionTimeHasEnded();
error ApprovalTimeNotStarted();
error GovernorOnly();
error WrongInputTargetAndValue();
error WrongInputTargetAndDatasize();
error InsufficientDeposit();
error ListAlreadySubmitted();
error ShouldOnlyWithdrawInFirstHalf();
error WrongListHash();
error OnlySubmitterCanWithdraw();
error WithdrawingTimeHasPassed();
error AlreadyDisputed();
error OnlyArbitratorAllowed();
error NotDisputed();
error RulingOutOfBounds();
error SubmissionNotApproved();
error TimeToExecuteHasPassed();
error AlreadyExecuted();
}
8 changes: 7 additions & 1 deletion contracts/src/arbitration/PolicyRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ contract PolicyRegistry is UUPSProxiable, Initializable {

/// @dev Requires that the sender is the governor.
modifier onlyByGovernor() {
require(governor == msg.sender, "No allowed: governor only");
if (governor != msg.sender) revert GovernorOnly();
_;
}

Expand Down Expand Up @@ -85,4 +85,10 @@ contract PolicyRegistry is UUPSProxiable, Initializable {
policies[_courtID] = _policy;
emit PolicyUpdate(_courtID, _courtName, policies[_courtID]);
}

// ************************************* //
// * Errors * //
// ************************************* //

error GovernorOnly();
}
49 changes: 31 additions & 18 deletions contracts/src/arbitration/SortitionModuleBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,12 @@ abstract contract SortitionModuleBase is ISortitionModule, Initializable, UUPSPr
// ************************************* //

modifier onlyByGovernor() {
require(address(governor) == msg.sender, "Access not allowed: Governor only.");
if (governor != msg.sender) revert GovernorOnly();
_;
}

modifier onlyByCore() {
require(address(core) == msg.sender, "Access not allowed: KlerosCore only.");
if (address(core) != msg.sender) revert KlerosCoreOnly();
_;
}

Expand Down Expand Up @@ -171,23 +171,19 @@ abstract contract SortitionModuleBase is ISortitionModule, Initializable, UUPSPr

function passPhase() external {
if (phase == Phase.staking) {
require(
block.timestamp - lastPhaseChange >= minStakingTime,
"The minimum staking time has not passed yet."
);
require(disputesWithoutJurors > 0, "There are no disputes that need jurors.");
if (block.timestamp - lastPhaseChange < minStakingTime) revert MinStakingTimeNotPassed();
if (disputesWithoutJurors == 0) revert NoDisputesThatNeedJurors();
rng.requestRandomness(block.number + rngLookahead);
randomNumberRequestBlock = block.number;
phase = Phase.generating;
} else if (phase == Phase.generating) {
randomNumber = rng.receiveRandomness(randomNumberRequestBlock + rngLookahead);
require(randomNumber != 0, "Random number is not ready yet");
if (randomNumber == 0) revert RandomNumberNotReady();
phase = Phase.drawing;
} else if (phase == Phase.drawing) {
require(
disputesWithoutJurors == 0 || block.timestamp - lastPhaseChange >= maxDrawingTime,
"There are still disputes without jurors and the maximum drawing time has not passed yet."
);
if (disputesWithoutJurors > 0 && block.timestamp - lastPhaseChange < maxDrawingTime) {
revert DisputesWithoutJurorsAndMaxDrawingTimeNotPassed();
}
phase = Phase.staking;
}

Expand All @@ -201,17 +197,17 @@ abstract contract SortitionModuleBase is ISortitionModule, Initializable, UUPSPr
function createTree(bytes32 _key, bytes memory _extraData) external override onlyByCore {
SortitionSumTree storage tree = sortitionSumTrees[_key];
uint256 K = _extraDataToTreeK(_extraData);
require(tree.K == 0, "Tree already exists.");
require(K > 1, "K must be greater than one.");
if (tree.K != 0) revert TreeAlreadyExists();
if (K <= 1) revert KMustBeGreaterThanOne();
tree.K = K;
tree.nodes.push(0);
}

/// @dev Executes the next delayed stakes.
/// @param _iterations The number of delayed stakes to execute.
function executeDelayedStakes(uint256 _iterations) external {
require(phase == Phase.staking, "Should be in Staking phase.");
require(delayedStakeWriteIndex >= delayedStakeReadIndex, "No delayed stake to execute.");
if (phase != Phase.staking) revert NotStakingPhase();
if (delayedStakeWriteIndex < delayedStakeReadIndex) revert NoDelayedStakeToExecute();

uint256 actualIterations = (delayedStakeReadIndex + _iterations) - 1 > delayedStakeWriteIndex
? (delayedStakeWriteIndex - delayedStakeReadIndex) + 1
Expand Down Expand Up @@ -420,7 +416,7 @@ abstract contract SortitionModuleBase is ISortitionModule, Initializable, UUPSPr
// Can withdraw the leftover PNK if fully unstaked, has no tokens locked and has positive balance.
// This withdrawal can't be triggered by calling setStake() in KlerosCore because current stake is technically 0, thus it is done via separate function.
uint256 amount = getJurorLeftoverPNK(_account);
require(amount > 0, "Not eligible for withdrawal.");
if (amount == 0) revert NotEligibleForWithdrawal();
jurors[_account].stakedPnk = 0;
core.transferBySortitionModule(_account, amount);
emit LeftoverPNKWithdrawn(_account, amount);
Expand All @@ -444,7 +440,7 @@ abstract contract SortitionModuleBase is ISortitionModule, Initializable, UUPSPr
uint256 _coreDisputeID,
uint256 _nonce
) public view override returns (address drawnAddress) {
require(phase == Phase.drawing, "Wrong phase.");
if (phase != Phase.drawing) revert NotDrawingPhase();
SortitionSumTree storage tree = sortitionSumTrees[_key];

if (tree.nodes[0] == 0) {
Expand Down Expand Up @@ -692,4 +688,21 @@ abstract contract SortitionModuleBase is ISortitionModule, Initializable, UUPSPr
stakePathID := mload(ptr)
}
}

// ************************************* //
// * Errors * //
// ************************************* //

error GovernorOnly();
error KlerosCoreOnly();
error MinStakingTimeNotPassed();
error NoDisputesThatNeedJurors();
error RandomNumberNotReady();
error DisputesWithoutJurorsAndMaxDrawingTimeNotPassed();
error TreeAlreadyExists();
error KMustBeGreaterThanOne();
error NotStakingPhase();
error NoDelayedStakeToExecute();
error NotEligibleForWithdrawal();
error NotDrawingPhase();
}
23 changes: 17 additions & 6 deletions contracts/src/arbitration/arbitrables/ArbitrableExample.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ contract ArbitrableExample is IArbitrableV2 {
// ************************************* //

modifier onlyByGovernor() {
require(msg.sender == governor, "Only the governor allowed.");
if (governor != msg.sender) revert GovernorOnly();
_;
}

Expand Down Expand Up @@ -126,8 +126,8 @@ contract ArbitrableExample is IArbitrableV2 {
uint256 localDisputeID = disputes.length;
disputes.push(DisputeStruct({isRuled: false, ruling: 0, numberOfRulingOptions: numberOfRulingOptions}));

require(weth.safeTransferFrom(msg.sender, address(this), _feeInWeth), "Transfer failed");
require(weth.increaseAllowance(address(arbitrator), _feeInWeth), "Allowance increase failed");
if (!weth.safeTransferFrom(msg.sender, address(this), _feeInWeth)) revert TransferFailed();
if (!weth.increaseAllowance(address(arbitrator), _feeInWeth)) revert AllowanceIncreaseFailed();

disputeID = arbitrator.createDispute(numberOfRulingOptions, arbitratorExtraData, weth, _feeInWeth);
externalIDtoLocalID[disputeID] = localDisputeID;
Expand All @@ -142,13 +142,24 @@ contract ArbitrableExample is IArbitrableV2 {
function rule(uint256 _arbitratorDisputeID, uint256 _ruling) external override {
uint256 localDisputeID = externalIDtoLocalID[_arbitratorDisputeID];
DisputeStruct storage dispute = disputes[localDisputeID];
require(msg.sender == address(arbitrator), "Only the arbitrator can execute this.");
require(_ruling <= dispute.numberOfRulingOptions, "Invalid ruling.");
require(dispute.isRuled == false, "This dispute has been ruled already.");
if (msg.sender != address(arbitrator)) revert ArbitratorOnly();
if (_ruling > dispute.numberOfRulingOptions) revert RulingOutOfBounds();
if (dispute.isRuled) revert DisputeAlreadyRuled();

dispute.isRuled = true;
dispute.ruling = _ruling;

emit Ruling(IArbitratorV2(msg.sender), _arbitratorDisputeID, dispute.ruling);
}

// ************************************* //
// * Errors * //
// ************************************* //

error GovernorOnly();
error TransferFailed();
error AllowanceIncreaseFailed();
error ArbitratorOnly();
error RulingOutOfBounds();
error DisputeAlreadyRuled();
}
24 changes: 17 additions & 7 deletions contracts/src/arbitration/arbitrables/DisputeResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,17 @@ contract DisputeResolver is IArbitrableV2 {
/// @dev Changes the governor.
/// @param _governor The address of the new governor.
function changeGovernor(address _governor) external {
require(governor == msg.sender, "Access not allowed: Governor only.");
if (governor != msg.sender) revert GovernorOnly();
governor = _governor;
}

function changeArbitrator(IArbitratorV2 _arbitrator) external {
require(governor == msg.sender, "Access not allowed: Governor only.");
if (governor != msg.sender) revert GovernorOnly();
arbitrator = _arbitrator;
}

function changeTemplateRegistry(IDisputeTemplateRegistry _templateRegistry) external {
require(governor == msg.sender, "Access not allowed: Governor only.");
if (governor != msg.sender) revert GovernorOnly();
templateRegistry = _templateRegistry;
}

Expand Down Expand Up @@ -109,9 +109,9 @@ contract DisputeResolver is IArbitrableV2 {
function rule(uint256 _arbitratorDisputeID, uint256 _ruling) external override {
uint256 localDisputeID = arbitratorDisputeIDToLocalID[_arbitratorDisputeID];
DisputeStruct storage dispute = disputes[localDisputeID];
require(msg.sender == address(arbitrator), "Only the arbitrator can execute this.");
require(_ruling <= dispute.numberOfRulingOptions, "Invalid ruling.");
require(!dispute.isRuled, "This dispute has been ruled already.");
if (msg.sender != address(arbitrator)) revert ArbitratorOnly();
if (_ruling > dispute.numberOfRulingOptions) revert RulingOutOfBounds();
if (dispute.isRuled) revert DisputeAlreadyRuled();

dispute.isRuled = true;
dispute.ruling = _ruling;
Expand All @@ -130,7 +130,7 @@ contract DisputeResolver is IArbitrableV2 {
string memory _disputeTemplateUri,
uint256 _numberOfRulingOptions
) internal virtual returns (uint256 arbitratorDisputeID) {
require(_numberOfRulingOptions > 1, "Should be at least 2 ruling options.");
if (_numberOfRulingOptions <= 1) revert ShouldBeAtLeastTwoRulingOptions();

arbitratorDisputeID = arbitrator.createDispute{value: msg.value}(_numberOfRulingOptions, _arbitratorExtraData);
uint256 localDisputeID = disputes.length;
Expand All @@ -146,4 +146,14 @@ contract DisputeResolver is IArbitrableV2 {
uint256 templateId = templateRegistry.setDisputeTemplate("", _disputeTemplate, _disputeTemplateDataMappings);
emit DisputeRequest(arbitrator, arbitratorDisputeID, localDisputeID, templateId, _disputeTemplateUri);
}

// ************************************* //
// * Errors * //
// ************************************* //

error GovernorOnly();
error ArbitratorOnly();
error RulingOutOfBounds();
error DisputeAlreadyRuled();
error ShouldBeAtLeastTwoRulingOptions();
}
Loading
Loading