From 429799ceec11e50442b0ed86f3bfaed06c94321e Mon Sep 17 00:00:00 2001 From: fnanni-0 Date: Mon, 27 Dec 2021 01:48:17 -0300 Subject: [PATCH 01/10] refactor: add kleros v1 governor proxy --- CHANGELOG.md | 13 +- contracts/src/kleros-v1/IKlerosLiquid.sol | 92 +++++++ contracts/src/kleros-v1/ITokenController.sol | 33 +++ contracts/src/kleros-v1/KlerosV1Governor.sol | 239 +++++++++++++++++++ 4 files changed, 373 insertions(+), 4 deletions(-) create mode 100644 contracts/src/kleros-v1/IKlerosLiquid.sol create mode 100644 contracts/src/kleros-v1/ITokenController.sol create mode 100644 contracts/src/kleros-v1/KlerosV1Governor.sol diff --git a/CHANGELOG.md b/CHANGELOG.md index 007f79389..49eba83c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.1.0 (2021-12-17) +## 0.1.0 (2021-12-27) - refactor: add arbitrator data index getter ([47a1623](https://github.com/kleros/kleros-v2/commit/47a1623)) - refactor: add evidence contracts ([09a34f3](https://github.com/kleros/kleros-v2/commit/09a34f3)) @@ -6,14 +6,17 @@ - refactor: add simple evidence home contract ([1b82f62](https://github.com/kleros/kleros-v2/commit/1b82f62)) - refactor: fix contract name ([6eb744a](https://github.com/kleros/kleros-v2/commit/6eb744a)) - refactor: remove foreign evidence interface ([ff8c50c](https://github.com/kleros/kleros-v2/commit/ff8c50c)) +- refactor(bridge): use ArbRetryableTx#getSubmissionPrice ([61bc2f3](https://github.com/kleros/kleros-v2/commit/61bc2f3)) - refactor(sdk): rename ([3241d10](https://github.com/kleros/kleros-v2/commit/3241d10)) -- test: add evidence contract tests ([590d800](https://github.com/kleros/kleros-v2/commit/590d800)) -- test: added a test for IncrementalNG ([65a996b](https://github.com/kleros/kleros-v2/commit/65a996b)) -- test(EvidenceModule): add test file ([9f00f98](https://github.com/kleros/kleros-v2/commit/9f00f98)) +- chore: .gitignore ([0ed4d74](https://github.com/kleros/kleros-v2/commit/0ed4d74)) +- chore: .gitignore and removal of unnecessary yarn cache as we are using "zero installs" ([a6cfdd0](https://github.com/kleros/kleros-v2/commit/a6cfdd0)) - chore: added GitHub code scanning ([4a70475](https://github.com/kleros/kleros-v2/commit/4a70475)) - chore: added the hardhat config for layer 2 networks, added hardhat-deploy and mocha ([a12ea0e](https://github.com/kleros/kleros-v2/commit/a12ea0e)) - chore: gitignore typechain ([b50f777](https://github.com/kleros/kleros-v2/commit/b50f777)) - chore(typechain): clean generated files ([775ddd0](https://github.com/kleros/kleros-v2/commit/775ddd0)) +- test: add evidence contract tests ([590d800](https://github.com/kleros/kleros-v2/commit/590d800)) +- test: added a test for IncrementalNG ([65a996b](https://github.com/kleros/kleros-v2/commit/65a996b)) +- test(EvidenceModule): add test file ([9f00f98](https://github.com/kleros/kleros-v2/commit/9f00f98)) - fix: according to evidence standard + comments ([5c95828](https://github.com/kleros/kleros-v2/commit/5c95828)) - fix: unused code ([26b5dc3](https://github.com/kleros/kleros-v2/commit/26b5dc3)) - fix(Arbitrator): memory to calldata ([4770b1f](https://github.com/kleros/kleros-v2/commit/4770b1f)) @@ -22,6 +25,8 @@ - fix(IArbitrator): change name to arbitration cost ([0ba4f29](https://github.com/kleros/kleros-v2/commit/0ba4f29)) - fix(IArbitrator): interface simplification ([e81fb8b](https://github.com/kleros/kleros-v2/commit/e81fb8b)) - fix(IArbitrator): replaced appealCost with fundingStatus ([f189dd9](https://github.com/kleros/kleros-v2/commit/f189dd9)) +- feat: add arbitrum L1 bridge and dependencies ([b412772](https://github.com/kleros/kleros-v2/commit/b412772)) +- feat: add arbitrum L2 bridge ([457b060](https://github.com/kleros/kleros-v2/commit/457b060)) - feat: modern toolchain setup and simple RNG smart contracts ([17f6a76](https://github.com/kleros/kleros-v2/commit/17f6a76)) - feat(Arbitration): standard update ([ed930de](https://github.com/kleros/kleros-v2/commit/ed930de)) - docs: initial commit ([23356e7](https://github.com/kleros/kleros-v2/commit/23356e7)) diff --git a/contracts/src/kleros-v1/IKlerosLiquid.sol b/contracts/src/kleros-v1/IKlerosLiquid.sol new file mode 100644 index 000000000..004450aa7 --- /dev/null +++ b/contracts/src/kleros-v1/IKlerosLiquid.sol @@ -0,0 +1,92 @@ +pragma solidity ^0.8; + +import "../arbitration/IArbitrator.sol"; + +interface IKlerosLiquid is IArbitrator { + enum Period { + evidence, // Evidence can be submitted. This is also when drawing has to take place. + commit, // Jurors commit a hashed vote. This is skipped for courts without hidden votes. + vote, // Jurors reveal/cast their vote depending on whether the court has hidden votes or not. + appeal, // The dispute can be appealed. + execution // Tokens are redistributed and the ruling is executed. + } + + struct Dispute { + // Note that appeal `0` is equivalent to the first round of the dispute. + uint96 subcourtID; // The ID of the subcourt the dispute is in. + address arbitrated; // The arbitrated arbitrable contract. + // The number of choices jurors have when voting. This does not include choice `0` which is reserved for "refuse to arbitrate"/"no ruling". + uint256 numberOfChoices; + Period period; // The current period of the dispute. + uint256 lastPeriodChange; // The last time the period was changed. + uint256 drawsInRound; // A counter of draws made in the current round. + uint256 commitsInRound; // A counter of commits made in the current round. + bool ruled; // True if the ruling has been executed, false otherwise. + } + struct Juror { + uint256 stakedTokens; // The juror's total amount of tokens staked in subcourts. + uint256 lockedTokens; // The juror's total amount of tokens locked in disputes. + } + + function lockInsolventTransfers() external view returns (bool); + + function pinakion() external view returns (address); + + function disputes(uint256 _index) external view returns (Dispute memory); + + function jurors(address _account) external view returns (Juror memory); + + function passPeriod(uint256 _disputeID) external; + + function drawJurors(uint256 _disputeID, uint256 _iterations) external; + + function execute( + uint256 _disputeID, + uint256 _appeal, + uint256 _iterations + ) external; + + function changeSubcourtMinStake(uint96 _subcourtID, uint256 _minStake) external; + + function changeSubcourtAlpha(uint96 _subcourtID, uint256 _alpha) external; + + function changeSubcourtTimesPerPeriod(uint96 _subcourtID, uint256[4] calldata _timesPerPeriod) external; + + function executeGovernorProposal( + address _destination, + uint256 _amount, + bytes calldata _data + ) external; + + // Getters + function getVote( + uint256 _disputeID, + uint256 _appeal, + uint256 _voteID + ) + external + view + returns ( + address account, + bytes32 commit, + uint256 choice, + bool voted + ); + + function getDispute(uint256 _disputeID) + external + view + returns ( + uint256[] memory votesLengths, + uint256[] memory tokensAtStakePerJuror, + uint256[] memory totalFeesForJurors, + uint256[] memory votesInEachRound, + uint256[] memory repartitionsInEachRound, + uint256[] memory penaltiesInEachRound + ); + + function getSubcourt(uint96 _subcourtID) + external + view + returns (uint256[] memory children, uint256[4] memory timesPerPeriod); +} diff --git a/contracts/src/kleros-v1/ITokenController.sol b/contracts/src/kleros-v1/ITokenController.sol new file mode 100644 index 000000000..cddb9287c --- /dev/null +++ b/contracts/src/kleros-v1/ITokenController.sol @@ -0,0 +1,33 @@ +pragma solidity ^0.8; + +/// @dev The token controller contract must implement these functions. See https://github.com/Giveth/minime/blob/master/contracts/TokenController.sol +interface ITokenController { + /// @notice Called when `_owner` sends ether to the MiniMe Token contract + /// @param _owner The address that sent the ether to create tokens + /// @return True if the ether is accepted, false if it throws + function proxyPayment(address _owner) external payable returns (bool); + + /// @notice Notifies the controller about a token transfer allowing the + /// controller to react if desired + /// @param _from The origin of the transfer + /// @param _to The destination of the transfer + /// @param _amount The amount of the transfer + /// @return False if the controller does not authorize the transfer + function onTransfer( + address _from, + address _to, + uint256 _amount + ) external returns (bool); + + /// @notice Notifies the controller about an approval allowing the + /// controller to react if desired + /// @param _owner The address that calls `approve()` + /// @param _spender The spender in the `approve()` call + /// @param _amount The amount in the `approve()` call + /// @return False if the controller does not authorize the approval + function onApprove( + address _owner, + address _spender, + uint256 _amount + ) external returns (bool); +} diff --git a/contracts/src/kleros-v1/KlerosV1Governor.sol b/contracts/src/kleros-v1/KlerosV1Governor.sol new file mode 100644 index 000000000..ab8c38ba9 --- /dev/null +++ b/contracts/src/kleros-v1/KlerosV1Governor.sol @@ -0,0 +1,239 @@ +pragma solidity ^0.8; + +import "./IKlerosLiquid.sol"; +import "./ITokenController.sol"; +import "../arbitration/IArbitrable.sol"; +import "../arbitration/IArbitrator.sol"; +import "../evidence/IEvidence.sol"; + +/** + * @title ERC20 interface + */ +interface IPinakion { + function balanceOf(address who) external view returns (uint256); +} + +contract KlerosV1Governor is IArbitrable, IEvidence, ITokenController { + struct DisputeData { + uint256 klerosLiquidDisputeID; + uint256 ruling; + bool ruled; + bool relayed; + } + + address public governor; + IArbitrator public foreignGateway; + IKlerosLiquid public klerosLiquid; + + mapping(uint256 => uint256) public klerosLiquidDisputeIDtoGatewayDisputeID; + mapping(uint256 => DisputeData) public disputes; // disputes[gatewayDisputeID] + mapping(address => uint256) public frozenTokens; // frozenTokens[account] locked token which shouldn't have been blocked. + mapping(uint256 => mapping(uint256 => bool)) public isDisputeNotified; // isDisputeNotified[disputeID][roundID] used to track the notification of frozen tokens. + + modifier onlyByGovernor() { + require(governor == msg.sender); + _; + } + + /** @dev Constructor. + * @param _klerosLiquid The trusted arbitrator to resolve potential disputes. + * @param _governor The trusted governor of the contract. + */ + constructor( + IKlerosLiquid _klerosLiquid, + address _governor, + IArbitrator _foreignGateway + ) { + klerosLiquid = _klerosLiquid; + governor = _governor; + foreignGateway = _foreignGateway; + } + + /** @dev Lets the governor call anything on behalf of the contract. + * @param _destination The destination of the call. + * @param _amount The value sent with the call. + * @param _data The data sent with the call. + */ + function executeGovernorProposal( + address _destination, + uint256 _amount, + bytes calldata _data + ) external onlyByGovernor { + (bool success, ) = _destination.call{value: _amount}(_data); // solium-disable-line security/no-call-value + require(success, "Call execution failed."); + } + + function startMigration() external { + uint256[4] memory timesPerPeriod; + for (uint96 subcourtID = 0; subcourtID <= 23; subcourtID++) { + // Set evidence periods to infinity + (, timesPerPeriod) = klerosLiquid.getSubcourt(subcourtID); + + klerosLiquid.changeSubcourtTimesPerPeriod( + subcourtID, + [type(uint256).max, timesPerPeriod[1], timesPerPeriod[2], timesPerPeriod[3]] + ); + } + } + + function relayDispute(uint256 _disputeID) external { + require(klerosLiquidDisputeIDtoGatewayDisputeID[_disputeID] == 0, "Dispute already relayed"); + IKlerosLiquid.Dispute memory KlerosLiquidDispute = klerosLiquid.disputes(_disputeID); + ( + uint256[] memory votesLengths, + uint256[] memory tokensAtStakePerJuror, + uint256[] memory totalFeesForJurors, + , + , + + ) = klerosLiquid.getDispute(_disputeID); + + // Check that no juror was yet drawn. Add a function to finalize the juror drawing and move the dispute to vote. + uint256 round = votesLengths.length - 1; + require(round == 0, "Cannot relay. Evidence period cannot be locked."); + require(KlerosLiquidDispute.period == IKlerosLiquid.Period.evidence, "Invalid dispute period."); + require(tokensAtStakePerJuror[round] == 0, "Jurors can get their PNK locked."); + + klerosLiquid.executeGovernorProposal(address(this), totalFeesForJurors[round], ""); + + uint256 minJurors = votesLengths[round]; + bytes memory extraData = abi.encode(KlerosLiquidDispute.subcourtID, minJurors); + uint256 arbitrationCost = foreignGateway.arbitrationCost(extraData); + require(totalFeesForJurors[round] >= arbitrationCost, "Fees not high enough."); // If this doesn't hold at some point, it could be a big issue. + uint256 gatewayDisputeID = foreignGateway.createDispute(KlerosLiquidDispute.numberOfChoices, extraData); + klerosLiquidDisputeIDtoGatewayDisputeID[_disputeID] = gatewayDisputeID; + + DisputeData storage dispute = disputes[gatewayDisputeID]; + dispute.klerosLiquidDisputeID = _disputeID; + } + + /** @dev Give a ruling for a dispute. Can only be called by the arbitrator. TRUSTED. + * Account for the situation where the winner loses a case due to paying less appeal fees than expected. + * @param _disputeID ID of the dispute in the arbitrator contract. + * @param _ruling Ruling given by the arbitrator. Note that 0 is reserved for "Refused to arbitrate". + */ + function rule(uint256 _disputeID, uint256 _ruling) public { + require(msg.sender == address(foreignGateway), "Not the arbitrator."); + DisputeData storage dispute = disputes[_disputeID]; + require(dispute.klerosLiquidDisputeID != 0, "Dispute does not exist."); + require(!dispute.ruled, "Dispute already ruled."); + + dispute.ruled = true; + dispute.ruling = _ruling; + + emit Ruling(foreignGateway, _disputeID, _ruling); + } + + function executeRuling(uint256 _disputeID, uint256 _ruling) external { + DisputeData storage dispute = disputes[_disputeID]; + IKlerosLiquid.Dispute memory klerosLiquidDispute = klerosLiquid.disputes(dispute.klerosLiquidDisputeID); + require(!dispute.relayed, "Ruling already sent."); + dispute.relayed = true; + + bytes4 functionSelector = IArbitrable.rule.selector; + bytes memory data = abi.encodeWithSelector(functionSelector, dispute.klerosLiquidDisputeID, _ruling); + klerosLiquid.executeGovernorProposal(klerosLiquidDispute.arbitrated, 0, data); + } + + function notifyFrozenTokens(uint256 _disputeID) external { + require(klerosLiquidDisputeIDtoGatewayDisputeID[_disputeID] != 0, "Dispute not relayed."); + (uint256[] memory votesLengths, uint256[] memory tokensAtStakePerJuror, , , , ) = klerosLiquid.getDispute( + _disputeID + ); + + for (uint256 round = 0; round < votesLengths.length; round++) { + if (isDisputeNotified[_disputeID][round]) continue; + + for (uint256 voteID = 0; voteID < votesLengths[round]; voteID++) { + (address account, , , ) = klerosLiquid.getVote(_disputeID, round, voteID); + frozenTokens[account] += tokensAtStakePerJuror[round]; + } + isDisputeNotified[_disputeID][round] = true; + } + } + + /** @dev Called when `_owner` sends ether to the MiniMe Token contract. + * @param _owner The address that sent the ether to create tokens. + * @return allowed Whether the operation should be allowed or not. + */ + function proxyPayment(address _owner) external payable returns (bool allowed) { + allowed = false; + } + + /** @dev Notifies the controller about a token transfer allowing the controller to react if desired. + * @param _from The origin of the transfer. + * @param _to The destination of the transfer. + * @param _amount The amount of the transfer. + * @return allowed Whether the operation should be allowed or not. + */ + function onTransfer( + address _from, + address _to, + uint256 _amount + ) external returns (bool allowed) { + if (klerosLiquid.lockInsolventTransfers()) { + // Never block penalties or rewards. + IPinakion pinakion = IPinakion(klerosLiquid.pinakion()); + uint256 newBalance = pinakion.balanceOf(_from) - _amount; // Overflow already checked in the Minime token contract. + + IKlerosLiquid.Juror memory juror = klerosLiquid.jurors(_from); + + // frozenTokens <= lockedTokens always. + if (newBalance < juror.stakedTokens || newBalance < juror.lockedTokens - frozenTokens[_from]) return false; + } + allowed = true; + } + + /** @dev Notifies the controller about an approval allowing the controller to react if desired. + * @param _owner The address that calls `approve()`. + * @param _spender The spender in the `approve()` call. + * @param _amount The amount in the `approve()` call. + * @return allowed Whether the operation should be allowed or not. + */ + function onApprove( + address _owner, + address _spender, + uint256 _amount + ) external returns (bool allowed) { + allowed = true; + } + + function unstakeRandomJuror() external payable { + // This is dangerous during migration, because a juror could try to remove another one before a dispute is created. First set periods to infinity. + + uint256 minJurors = 1; + uint256 subcourtID = 0; // General Court + bytes memory extraData = abi.encode(subcourtID, minJurors); + + uint256 arbitrationCost = klerosLiquid.arbitrationCost(extraData); + require(msg.value >= arbitrationCost, "ETH not enough"); + + // Set minStake to zero (only possible with the General court) + klerosLiquid.changeSubcourtMinStake(uint96(subcourtID), 0); + + uint256 numberOfChoices = 0; + uint256 disputeID = klerosLiquid.createDispute(numberOfChoices, extraData); + + // Set minStake to infinity (only possible if the children's minStake are set to infinity) + klerosLiquid.changeSubcourtMinStake(uint96(subcourtID), type(uint256).max); + klerosLiquid.drawJurors(disputeID, minJurors); // Only one juror allowed. Will revert otherwise. + (address account, , , ) = klerosLiquid.getVote(disputeID, 0, 0); + require(account != address(this), "Cannot unstake itself."); + + klerosLiquid.changeSubcourtTimesPerPeriod(uint96(subcourtID), [uint256(0), uint256(0), uint256(0), uint256(0)]); + klerosLiquid.passPeriod(disputeID); // Evidence --> Vote + klerosLiquid.passPeriod(disputeID); // Vote --> Appeal + klerosLiquid.passPeriod(disputeID); // Appeal --> Execution + klerosLiquid.changeSubcourtTimesPerPeriod( + uint96(subcourtID), + [type(uint256).max, type(uint256).max, type(uint256).max, type(uint256).max] + ); + + klerosLiquid.execute(disputeID, 0, 1); + // There is no need to execute the ruling + + payable(msg.sender).send(arbitrationCost); + } + + receive() external payable {} +} From d250cf0f93f9a42da336fa287577ccf7d5fe52f8 Mon Sep 17 00:00:00 2001 From: fnanni-0 Date: Mon, 27 Dec 2021 01:55:33 -0300 Subject: [PATCH 02/10] refactor: clean contract --- CHANGELOG.md | 1 + contracts/src/kleros-v1/IKlerosLiquid.sol | 15 +----- contracts/src/kleros-v1/KlerosV1Governor.sol | 48 ++------------------ 3 files changed, 7 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49eba83c2..a7851bd21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - refactor: add arbitrator data index getter ([47a1623](https://github.com/kleros/kleros-v2/commit/47a1623)) - refactor: add evidence contracts ([09a34f3](https://github.com/kleros/kleros-v2/commit/09a34f3)) - refactor: add interfaces + capped math ([e25b21f](https://github.com/kleros/kleros-v2/commit/e25b21f)) +- refactor: add kleros v1 governor proxy ([429799c](https://github.com/kleros/kleros-v2/commit/429799c)) - refactor: add simple evidence home contract ([1b82f62](https://github.com/kleros/kleros-v2/commit/1b82f62)) - refactor: fix contract name ([6eb744a](https://github.com/kleros/kleros-v2/commit/6eb744a)) - refactor: remove foreign evidence interface ([ff8c50c](https://github.com/kleros/kleros-v2/commit/ff8c50c)) diff --git a/contracts/src/kleros-v1/IKlerosLiquid.sol b/contracts/src/kleros-v1/IKlerosLiquid.sol index 004450aa7..5632bfaa8 100644 --- a/contracts/src/kleros-v1/IKlerosLiquid.sol +++ b/contracts/src/kleros-v1/IKlerosLiquid.sol @@ -23,6 +23,7 @@ interface IKlerosLiquid is IArbitrator { uint256 commitsInRound; // A counter of commits made in the current round. bool ruled; // True if the ruling has been executed, false otherwise. } + struct Juror { uint256 stakedTokens; // The juror's total amount of tokens staked in subcourts. uint256 lockedTokens; // The juror's total amount of tokens locked in disputes. @@ -36,20 +37,6 @@ interface IKlerosLiquid is IArbitrator { function jurors(address _account) external view returns (Juror memory); - function passPeriod(uint256 _disputeID) external; - - function drawJurors(uint256 _disputeID, uint256 _iterations) external; - - function execute( - uint256 _disputeID, - uint256 _appeal, - uint256 _iterations - ) external; - - function changeSubcourtMinStake(uint96 _subcourtID, uint256 _minStake) external; - - function changeSubcourtAlpha(uint96 _subcourtID, uint256 _alpha) external; - function changeSubcourtTimesPerPeriod(uint96 _subcourtID, uint256[4] calldata _timesPerPeriod) external; function executeGovernorProposal( diff --git a/contracts/src/kleros-v1/KlerosV1Governor.sol b/contracts/src/kleros-v1/KlerosV1Governor.sol index ab8c38ba9..bf9bb73a4 100644 --- a/contracts/src/kleros-v1/KlerosV1Governor.sol +++ b/contracts/src/kleros-v1/KlerosV1Governor.sol @@ -89,17 +89,16 @@ contract KlerosV1Governor is IArbitrable, IEvidence, ITokenController { ) = klerosLiquid.getDispute(_disputeID); // Check that no juror was yet drawn. Add a function to finalize the juror drawing and move the dispute to vote. - uint256 round = votesLengths.length - 1; - require(round == 0, "Cannot relay. Evidence period cannot be locked."); + require(votesLengths.length == 1, "Cannot relay. Evidence period cannot be locked."); require(KlerosLiquidDispute.period == IKlerosLiquid.Period.evidence, "Invalid dispute period."); - require(tokensAtStakePerJuror[round] == 0, "Jurors can get their PNK locked."); + require(tokensAtStakePerJuror[0] == 0, "Jurors can get their PNK locked."); - klerosLiquid.executeGovernorProposal(address(this), totalFeesForJurors[round], ""); + klerosLiquid.executeGovernorProposal(address(this), totalFeesForJurors[0], ""); - uint256 minJurors = votesLengths[round]; + uint256 minJurors = votesLengths[0]; bytes memory extraData = abi.encode(KlerosLiquidDispute.subcourtID, minJurors); uint256 arbitrationCost = foreignGateway.arbitrationCost(extraData); - require(totalFeesForJurors[round] >= arbitrationCost, "Fees not high enough."); // If this doesn't hold at some point, it could be a big issue. + require(totalFeesForJurors[0] >= arbitrationCost, "Fees not high enough."); // If this doesn't hold at some point, it could be a big issue. uint256 gatewayDisputeID = foreignGateway.createDispute(KlerosLiquidDispute.numberOfChoices, extraData); klerosLiquidDisputeIDtoGatewayDisputeID[_disputeID] = gatewayDisputeID; @@ -198,42 +197,5 @@ contract KlerosV1Governor is IArbitrable, IEvidence, ITokenController { allowed = true; } - function unstakeRandomJuror() external payable { - // This is dangerous during migration, because a juror could try to remove another one before a dispute is created. First set periods to infinity. - - uint256 minJurors = 1; - uint256 subcourtID = 0; // General Court - bytes memory extraData = abi.encode(subcourtID, minJurors); - - uint256 arbitrationCost = klerosLiquid.arbitrationCost(extraData); - require(msg.value >= arbitrationCost, "ETH not enough"); - - // Set minStake to zero (only possible with the General court) - klerosLiquid.changeSubcourtMinStake(uint96(subcourtID), 0); - - uint256 numberOfChoices = 0; - uint256 disputeID = klerosLiquid.createDispute(numberOfChoices, extraData); - - // Set minStake to infinity (only possible if the children's minStake are set to infinity) - klerosLiquid.changeSubcourtMinStake(uint96(subcourtID), type(uint256).max); - klerosLiquid.drawJurors(disputeID, minJurors); // Only one juror allowed. Will revert otherwise. - (address account, , , ) = klerosLiquid.getVote(disputeID, 0, 0); - require(account != address(this), "Cannot unstake itself."); - - klerosLiquid.changeSubcourtTimesPerPeriod(uint96(subcourtID), [uint256(0), uint256(0), uint256(0), uint256(0)]); - klerosLiquid.passPeriod(disputeID); // Evidence --> Vote - klerosLiquid.passPeriod(disputeID); // Vote --> Appeal - klerosLiquid.passPeriod(disputeID); // Appeal --> Execution - klerosLiquid.changeSubcourtTimesPerPeriod( - uint96(subcourtID), - [type(uint256).max, type(uint256).max, type(uint256).max, type(uint256).max] - ); - - klerosLiquid.execute(disputeID, 0, 1); - // There is no need to execute the ruling - - payable(msg.sender).send(arbitrationCost); - } - receive() external payable {} } From b47f8016ca3a6d071de6b0d62a2629a6f33ba352 Mon Sep 17 00:00:00 2001 From: fnanni-0 Date: Mon, 27 Dec 2021 02:41:37 -0300 Subject: [PATCH 03/10] refactor: fixes + docs --- CHANGELOG.md | 1 + contracts/src/kleros-v1/KlerosV1Governor.sol | 68 ++++++++++++-------- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7851bd21..b59bb35e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - refactor: add interfaces + capped math ([e25b21f](https://github.com/kleros/kleros-v2/commit/e25b21f)) - refactor: add kleros v1 governor proxy ([429799c](https://github.com/kleros/kleros-v2/commit/429799c)) - refactor: add simple evidence home contract ([1b82f62](https://github.com/kleros/kleros-v2/commit/1b82f62)) +- refactor: clean contract ([d250cf0](https://github.com/kleros/kleros-v2/commit/d250cf0)) - refactor: fix contract name ([6eb744a](https://github.com/kleros/kleros-v2/commit/6eb744a)) - refactor: remove foreign evidence interface ([ff8c50c](https://github.com/kleros/kleros-v2/commit/ff8c50c)) - refactor(bridge): use ArbRetryableTx#getSubmissionPrice ([61bc2f3](https://github.com/kleros/kleros-v2/commit/61bc2f3)) diff --git a/contracts/src/kleros-v1/KlerosV1Governor.sol b/contracts/src/kleros-v1/KlerosV1Governor.sol index bf9bb73a4..48ea09de3 100644 --- a/contracts/src/kleros-v1/KlerosV1Governor.sol +++ b/contracts/src/kleros-v1/KlerosV1Governor.sol @@ -4,7 +4,6 @@ import "./IKlerosLiquid.sol"; import "./ITokenController.sol"; import "../arbitration/IArbitrable.sol"; import "../arbitration/IArbitrator.sol"; -import "../evidence/IEvidence.sol"; /** * @title ERC20 interface @@ -13,17 +12,19 @@ interface IPinakion { function balanceOf(address who) external view returns (uint256); } -contract KlerosV1Governor is IArbitrable, IEvidence, ITokenController { +contract KlerosV1Governor is IArbitrable, ITokenController { + uint256 private constant MAX_SUBCOURT_ID = 23; + struct DisputeData { uint256 klerosLiquidDisputeID; uint256 ruling; bool ruled; - bool relayed; + bool rulingRelayed; } + IArbitrator public immutable foreignGateway; + IKlerosLiquid public immutable klerosLiquid; address public governor; - IArbitrator public foreignGateway; - IKlerosLiquid public klerosLiquid; mapping(uint256 => uint256) public klerosLiquidDisputeIDtoGatewayDisputeID; mapping(uint256 => DisputeData) public disputes; // disputes[gatewayDisputeID] @@ -47,6 +48,17 @@ contract KlerosV1Governor is IArbitrable, IEvidence, ITokenController { klerosLiquid = _klerosLiquid; governor = _governor; foreignGateway = _foreignGateway; + + // Set evidence periods of subcourts to infinity. + uint256[4] memory timesPerPeriod; + for (uint96 subcourtID = 0; subcourtID <= MAX_SUBCOURT_ID; subcourtID++) { + (, timesPerPeriod) = klerosLiquid.getSubcourt(subcourtID); + + klerosLiquid.changeSubcourtTimesPerPeriod( + subcourtID, + [type(uint256).max, timesPerPeriod[1], timesPerPeriod[2], timesPerPeriod[3]] + ); + } } /** @dev Lets the governor call anything on behalf of the contract. @@ -63,35 +75,26 @@ contract KlerosV1Governor is IArbitrable, IEvidence, ITokenController { require(success, "Call execution failed."); } - function startMigration() external { - uint256[4] memory timesPerPeriod; - for (uint96 subcourtID = 0; subcourtID <= 23; subcourtID++) { - // Set evidence periods to infinity - (, timesPerPeriod) = klerosLiquid.getSubcourt(subcourtID); - - klerosLiquid.changeSubcourtTimesPerPeriod( - subcourtID, - [type(uint256).max, timesPerPeriod[1], timesPerPeriod[2], timesPerPeriod[3]] - ); - } + /** @dev Changes the `governor` storage variable. + * @param _governor The new value for the `governor` storage variable. + */ + function changeGovernor(address _governor) external onlyByGovernor { + governor = _governor; } + /** @dev Relays disputes from KlerosLiquid to Kleros v2. Only disputes in the evidence period of the initial round can be realyed. + * @param _disputeID The ID of the dispute as defined in KlerosLiquid. + */ function relayDispute(uint256 _disputeID) external { require(klerosLiquidDisputeIDtoGatewayDisputeID[_disputeID] == 0, "Dispute already relayed"); IKlerosLiquid.Dispute memory KlerosLiquidDispute = klerosLiquid.disputes(_disputeID); - ( - uint256[] memory votesLengths, - uint256[] memory tokensAtStakePerJuror, - uint256[] memory totalFeesForJurors, - , - , - - ) = klerosLiquid.getDispute(_disputeID); + (uint256[] memory votesLengths, , uint256[] memory totalFeesForJurors, , , ) = klerosLiquid.getDispute( + _disputeID + ); // Check that no juror was yet drawn. Add a function to finalize the juror drawing and move the dispute to vote. - require(votesLengths.length == 1, "Cannot relay. Evidence period cannot be locked."); require(KlerosLiquidDispute.period == IKlerosLiquid.Period.evidence, "Invalid dispute period."); - require(tokensAtStakePerJuror[0] == 0, "Jurors can get their PNK locked."); + require(votesLengths.length == 1, "Cannot relay appeals."); klerosLiquid.executeGovernorProposal(address(this), totalFeesForJurors[0], ""); @@ -123,17 +126,25 @@ contract KlerosV1Governor is IArbitrable, IEvidence, ITokenController { emit Ruling(foreignGateway, _disputeID, _ruling); } + /** @dev Triggers rule() from KlerosLiquid to the arbitrable contract which created the dispute. + * @param _disputeID ID of the dispute in the arbitrator contract. + * @param _ruling Ruling given by the arbitrator. Note that 0 is reserved for "Refused to arbitrate". + */ function executeRuling(uint256 _disputeID, uint256 _ruling) external { DisputeData storage dispute = disputes[_disputeID]; IKlerosLiquid.Dispute memory klerosLiquidDispute = klerosLiquid.disputes(dispute.klerosLiquidDisputeID); - require(!dispute.relayed, "Ruling already sent."); - dispute.relayed = true; + require(dispute.ruled, "Dispute ongoing."); + require(!dispute.rulingRelayed, "Ruling already sent."); + dispute.rulingRelayed = true; bytes4 functionSelector = IArbitrable.rule.selector; bytes memory data = abi.encodeWithSelector(functionSelector, dispute.klerosLiquidDisputeID, _ruling); klerosLiquid.executeGovernorProposal(klerosLiquidDispute.arbitrated, 0, data); } + /** @dev Registers jurors' tokens which where locked due to relaying a given dispute. These tokens don't count as locked. + * @param _disputeID The ID of the dispute as defined in KlerosLiquid. + */ function notifyFrozenTokens(uint256 _disputeID) external { require(klerosLiquidDisputeIDtoGatewayDisputeID[_disputeID] != 0, "Dispute not relayed."); (uint256[] memory votesLengths, uint256[] memory tokensAtStakePerJuror, , , , ) = klerosLiquid.getDispute( @@ -197,5 +208,6 @@ contract KlerosV1Governor is IArbitrable, IEvidence, ITokenController { allowed = true; } + /// @dev This contract should be able to receive arbitration fees from KlerosLiquid. receive() external payable {} } From 5dd72df59ad5c3c563908c9e6d067b1b7d874918 Mon Sep 17 00:00:00 2001 From: jaybuidl Date: Fri, 7 Jan 2022 16:32:36 +0000 Subject: [PATCH 04/10] chore(CHANGELOG): removal of changelog due to conflicts --- .husky/pre-commit | 4 +--- CHANGELOG.md | 37 ------------------------------------- 2 files changed, 1 insertion(+), 40 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/.husky/pre-commit b/.husky/pre-commit index d827c7000..dd535a8e0 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,6 +2,4 @@ . "$(dirname "$0")/_/husky.sh" yarn lint-staged \ - && yarn depcheck \ - && yarn changelog \ - && git add CHANGELOG.md + && yarn depcheck diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index b59bb35e3..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,37 +0,0 @@ -## 0.1.0 (2021-12-27) - -- refactor: add arbitrator data index getter ([47a1623](https://github.com/kleros/kleros-v2/commit/47a1623)) -- refactor: add evidence contracts ([09a34f3](https://github.com/kleros/kleros-v2/commit/09a34f3)) -- refactor: add interfaces + capped math ([e25b21f](https://github.com/kleros/kleros-v2/commit/e25b21f)) -- refactor: add kleros v1 governor proxy ([429799c](https://github.com/kleros/kleros-v2/commit/429799c)) -- refactor: add simple evidence home contract ([1b82f62](https://github.com/kleros/kleros-v2/commit/1b82f62)) -- refactor: clean contract ([d250cf0](https://github.com/kleros/kleros-v2/commit/d250cf0)) -- refactor: fix contract name ([6eb744a](https://github.com/kleros/kleros-v2/commit/6eb744a)) -- refactor: remove foreign evidence interface ([ff8c50c](https://github.com/kleros/kleros-v2/commit/ff8c50c)) -- refactor(bridge): use ArbRetryableTx#getSubmissionPrice ([61bc2f3](https://github.com/kleros/kleros-v2/commit/61bc2f3)) -- refactor(sdk): rename ([3241d10](https://github.com/kleros/kleros-v2/commit/3241d10)) -- chore: .gitignore ([0ed4d74](https://github.com/kleros/kleros-v2/commit/0ed4d74)) -- chore: .gitignore and removal of unnecessary yarn cache as we are using "zero installs" ([a6cfdd0](https://github.com/kleros/kleros-v2/commit/a6cfdd0)) -- chore: added GitHub code scanning ([4a70475](https://github.com/kleros/kleros-v2/commit/4a70475)) -- chore: added the hardhat config for layer 2 networks, added hardhat-deploy and mocha ([a12ea0e](https://github.com/kleros/kleros-v2/commit/a12ea0e)) -- chore: gitignore typechain ([b50f777](https://github.com/kleros/kleros-v2/commit/b50f777)) -- chore(typechain): clean generated files ([775ddd0](https://github.com/kleros/kleros-v2/commit/775ddd0)) -- test: add evidence contract tests ([590d800](https://github.com/kleros/kleros-v2/commit/590d800)) -- test: added a test for IncrementalNG ([65a996b](https://github.com/kleros/kleros-v2/commit/65a996b)) -- test(EvidenceModule): add test file ([9f00f98](https://github.com/kleros/kleros-v2/commit/9f00f98)) -- fix: according to evidence standard + comments ([5c95828](https://github.com/kleros/kleros-v2/commit/5c95828)) -- fix: unused code ([26b5dc3](https://github.com/kleros/kleros-v2/commit/26b5dc3)) -- fix(Arbitrator): memory to calldata ([4770b1f](https://github.com/kleros/kleros-v2/commit/4770b1f)) -- fix(EvidenceModule): typos + castings + imports ([789c022](https://github.com/kleros/kleros-v2/commit/789c022)) -- fix(IArbitrator): appeals removed from the standard ([02c20ce](https://github.com/kleros/kleros-v2/commit/02c20ce)) -- fix(IArbitrator): change name to arbitration cost ([0ba4f29](https://github.com/kleros/kleros-v2/commit/0ba4f29)) -- fix(IArbitrator): interface simplification ([e81fb8b](https://github.com/kleros/kleros-v2/commit/e81fb8b)) -- fix(IArbitrator): replaced appealCost with fundingStatus ([f189dd9](https://github.com/kleros/kleros-v2/commit/f189dd9)) -- feat: add arbitrum L1 bridge and dependencies ([b412772](https://github.com/kleros/kleros-v2/commit/b412772)) -- feat: add arbitrum L2 bridge ([457b060](https://github.com/kleros/kleros-v2/commit/457b060)) -- feat: modern toolchain setup and simple RNG smart contracts ([17f6a76](https://github.com/kleros/kleros-v2/commit/17f6a76)) -- feat(Arbitration): standard update ([ed930de](https://github.com/kleros/kleros-v2/commit/ed930de)) -- docs: initial commit ([23356e7](https://github.com/kleros/kleros-v2/commit/23356e7)) -- docs: license file added ([cb62d2c](https://github.com/kleros/kleros-v2/commit/cb62d2c)) -- docs: readme and spdx headers ([8a5b397](https://github.com/kleros/kleros-v2/commit/8a5b397)) -- docs: updated ([5b9a8f1](https://github.com/kleros/kleros-v2/commit/5b9a8f1)) From 036895eab8b9609aaf824a79ac796277779c52e4 Mon Sep 17 00:00:00 2001 From: fnanni-0 Date: Mon, 10 Jan 2022 00:05:22 -0300 Subject: [PATCH 05/10] fix: join rule and execute --- CHANGELOG.md | 3 ++- contracts/src/kleros-v1/KlerosV1Governor.sol | 15 +-------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b59bb35e3..1e734de23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.1.0 (2021-12-27) +## 0.1.0 (2022-01-10) - refactor: add arbitrator data index getter ([47a1623](https://github.com/kleros/kleros-v2/commit/47a1623)) - refactor: add evidence contracts ([09a34f3](https://github.com/kleros/kleros-v2/commit/09a34f3)) @@ -7,6 +7,7 @@ - refactor: add simple evidence home contract ([1b82f62](https://github.com/kleros/kleros-v2/commit/1b82f62)) - refactor: clean contract ([d250cf0](https://github.com/kleros/kleros-v2/commit/d250cf0)) - refactor: fix contract name ([6eb744a](https://github.com/kleros/kleros-v2/commit/6eb744a)) +- refactor: fixes + docs ([b47f801](https://github.com/kleros/kleros-v2/commit/b47f801)) - refactor: remove foreign evidence interface ([ff8c50c](https://github.com/kleros/kleros-v2/commit/ff8c50c)) - refactor(bridge): use ArbRetryableTx#getSubmissionPrice ([61bc2f3](https://github.com/kleros/kleros-v2/commit/61bc2f3)) - refactor(sdk): rename ([3241d10](https://github.com/kleros/kleros-v2/commit/3241d10)) diff --git a/contracts/src/kleros-v1/KlerosV1Governor.sol b/contracts/src/kleros-v1/KlerosV1Governor.sol index 48ea09de3..ff4908b79 100644 --- a/contracts/src/kleros-v1/KlerosV1Governor.sol +++ b/contracts/src/kleros-v1/KlerosV1Governor.sol @@ -17,9 +17,7 @@ contract KlerosV1Governor is IArbitrable, ITokenController { struct DisputeData { uint256 klerosLiquidDisputeID; - uint256 ruling; bool ruled; - bool rulingRelayed; } IArbitrator public immutable foreignGateway; @@ -110,7 +108,7 @@ contract KlerosV1Governor is IArbitrable, ITokenController { } /** @dev Give a ruling for a dispute. Can only be called by the arbitrator. TRUSTED. - * Account for the situation where the winner loses a case due to paying less appeal fees than expected. + * Triggers rule() from KlerosLiquid to the arbitrable contract which created the dispute. * @param _disputeID ID of the dispute in the arbitrator contract. * @param _ruling Ruling given by the arbitrator. Note that 0 is reserved for "Refused to arbitrate". */ @@ -121,21 +119,10 @@ contract KlerosV1Governor is IArbitrable, ITokenController { require(!dispute.ruled, "Dispute already ruled."); dispute.ruled = true; - dispute.ruling = _ruling; emit Ruling(foreignGateway, _disputeID, _ruling); - } - /** @dev Triggers rule() from KlerosLiquid to the arbitrable contract which created the dispute. - * @param _disputeID ID of the dispute in the arbitrator contract. - * @param _ruling Ruling given by the arbitrator. Note that 0 is reserved for "Refused to arbitrate". - */ - function executeRuling(uint256 _disputeID, uint256 _ruling) external { - DisputeData storage dispute = disputes[_disputeID]; IKlerosLiquid.Dispute memory klerosLiquidDispute = klerosLiquid.disputes(dispute.klerosLiquidDisputeID); - require(dispute.ruled, "Dispute ongoing."); - require(!dispute.rulingRelayed, "Ruling already sent."); - dispute.rulingRelayed = true; bytes4 functionSelector = IArbitrable.rule.selector; bytes memory data = abi.encodeWithSelector(functionSelector, dispute.klerosLiquidDisputeID, _ruling); From c0ecefcd5b66d33bb1d802f62e231a44f8aaf19a Mon Sep 17 00:00:00 2001 From: fnanni-0 Date: Mon, 10 Jan 2022 17:16:34 -0300 Subject: [PATCH 06/10] fix: notification of frozen tokens + init --- contracts/src/kleros-v1/KlerosV1Governor.sol | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/contracts/src/kleros-v1/KlerosV1Governor.sol b/contracts/src/kleros-v1/KlerosV1Governor.sol index ff4908b79..cfeee97a3 100644 --- a/contracts/src/kleros-v1/KlerosV1Governor.sol +++ b/contracts/src/kleros-v1/KlerosV1Governor.sol @@ -34,9 +34,10 @@ contract KlerosV1Governor is IArbitrable, ITokenController { _; } - /** @dev Constructor. + /** @dev Constructor. Before this contract is made the new governor of KlerosLiquid, the evidence period of all subcourts has to be set to uint(-1). * @param _klerosLiquid The trusted arbitrator to resolve potential disputes. * @param _governor The trusted governor of the contract. + * @param _foreignGateway The trusted gateway that acts as an arbitrator, relaying disputes to v2. */ constructor( IKlerosLiquid _klerosLiquid, @@ -46,17 +47,6 @@ contract KlerosV1Governor is IArbitrable, ITokenController { klerosLiquid = _klerosLiquid; governor = _governor; foreignGateway = _foreignGateway; - - // Set evidence periods of subcourts to infinity. - uint256[4] memory timesPerPeriod; - for (uint96 subcourtID = 0; subcourtID <= MAX_SUBCOURT_ID; subcourtID++) { - (, timesPerPeriod) = klerosLiquid.getSubcourt(subcourtID); - - klerosLiquid.changeSubcourtTimesPerPeriod( - subcourtID, - [type(uint256).max, timesPerPeriod[1], timesPerPeriod[2], timesPerPeriod[3]] - ); - } } /** @dev Lets the governor call anything on behalf of the contract. @@ -102,6 +92,7 @@ contract KlerosV1Governor is IArbitrable, ITokenController { require(totalFeesForJurors[0] >= arbitrationCost, "Fees not high enough."); // If this doesn't hold at some point, it could be a big issue. uint256 gatewayDisputeID = foreignGateway.createDispute(KlerosLiquidDispute.numberOfChoices, extraData); klerosLiquidDisputeIDtoGatewayDisputeID[_disputeID] = gatewayDisputeID; + require(gatewayDisputeID != 0, "ID must be greater than 0."); DisputeData storage dispute = disputes[gatewayDisputeID]; dispute.klerosLiquidDisputeID = _disputeID; @@ -143,6 +134,7 @@ contract KlerosV1Governor is IArbitrable, ITokenController { for (uint256 voteID = 0; voteID < votesLengths[round]; voteID++) { (address account, , , ) = klerosLiquid.getVote(_disputeID, round, voteID); + require(account != address(0x0), "Juror not drawn yet."); frozenTokens[account] += tokensAtStakePerJuror[round]; } isDisputeNotified[_disputeID][round] = true; From 0bc092b6752ac6e59b8193cd0b8c0e7c9a5b0858 Mon Sep 17 00:00:00 2001 From: fnanni-0 Date: Mon, 10 Jan 2022 17:20:53 -0300 Subject: [PATCH 07/10] refactor: remove unused constant --- contracts/src/kleros-v1/KlerosV1Governor.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/contracts/src/kleros-v1/KlerosV1Governor.sol b/contracts/src/kleros-v1/KlerosV1Governor.sol index cfeee97a3..a9772c2d9 100644 --- a/contracts/src/kleros-v1/KlerosV1Governor.sol +++ b/contracts/src/kleros-v1/KlerosV1Governor.sol @@ -13,8 +13,6 @@ interface IPinakion { } contract KlerosV1Governor is IArbitrable, ITokenController { - uint256 private constant MAX_SUBCOURT_ID = 23; - struct DisputeData { uint256 klerosLiquidDisputeID; bool ruled; From 647bdfe9d653390f04eda0a87d5e04697afc715b Mon Sep 17 00:00:00 2001 From: fnanni-0 Date: Wed, 12 Jan 2022 10:00:56 -0300 Subject: [PATCH 08/10] fix: pay arbitration fees --- contracts/src/kleros-v1/KlerosV1Governor.sol | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contracts/src/kleros-v1/KlerosV1Governor.sol b/contracts/src/kleros-v1/KlerosV1Governor.sol index a9772c2d9..d63d1a0d6 100644 --- a/contracts/src/kleros-v1/KlerosV1Governor.sol +++ b/contracts/src/kleros-v1/KlerosV1Governor.sol @@ -78,7 +78,6 @@ contract KlerosV1Governor is IArbitrable, ITokenController { _disputeID ); - // Check that no juror was yet drawn. Add a function to finalize the juror drawing and move the dispute to vote. require(KlerosLiquidDispute.period == IKlerosLiquid.Period.evidence, "Invalid dispute period."); require(votesLengths.length == 1, "Cannot relay appeals."); @@ -88,7 +87,10 @@ contract KlerosV1Governor is IArbitrable, ITokenController { bytes memory extraData = abi.encode(KlerosLiquidDispute.subcourtID, minJurors); uint256 arbitrationCost = foreignGateway.arbitrationCost(extraData); require(totalFeesForJurors[0] >= arbitrationCost, "Fees not high enough."); // If this doesn't hold at some point, it could be a big issue. - uint256 gatewayDisputeID = foreignGateway.createDispute(KlerosLiquidDispute.numberOfChoices, extraData); + uint256 gatewayDisputeID = foreignGateway.createDispute{value: arbitrationCost}( + KlerosLiquidDispute.numberOfChoices, + extraData + ); klerosLiquidDisputeIDtoGatewayDisputeID[_disputeID] = gatewayDisputeID; require(gatewayDisputeID != 0, "ID must be greater than 0."); From 2ad8d7ab2d6dd6864318f7eab132cbaeaf36bb34 Mon Sep 17 00:00:00 2001 From: fnanni-0 Date: Wed, 12 Jan 2022 15:26:44 -0300 Subject: [PATCH 09/10] fix: frozen tokens notification --- contracts/src/kleros-v1/IKlerosLiquid.sol | 10 ++++++++++ contracts/src/kleros-v1/KlerosV1Governor.sol | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/contracts/src/kleros-v1/IKlerosLiquid.sol b/contracts/src/kleros-v1/IKlerosLiquid.sol index 5632bfaa8..f55f67c8c 100644 --- a/contracts/src/kleros-v1/IKlerosLiquid.sol +++ b/contracts/src/kleros-v1/IKlerosLiquid.sol @@ -11,6 +11,12 @@ interface IKlerosLiquid is IArbitrator { execution // Tokens are redistributed and the ruling is executed. } + enum Phase { + staking, // Stake sum trees can be updated. Pass after `minStakingTime` passes and there is at least one dispute without jurors. + generating, // Waiting for a random number. Pass as soon as it is ready. + drawing // Jurors can be drawn. Pass after all disputes have jurors or `maxDrawingTime` passes. + } + struct Dispute { // Note that appeal `0` is equivalent to the first round of the dispute. uint96 subcourtID; // The ID of the subcourt the dispute is in. @@ -29,8 +35,12 @@ interface IKlerosLiquid is IArbitrator { uint256 lockedTokens; // The juror's total amount of tokens locked in disputes. } + function phase() external view returns (Phase); + function lockInsolventTransfers() external view returns (bool); + function minStakingTime() external view returns (uint256); + function pinakion() external view returns (address); function disputes(uint256 _index) external view returns (Dispute memory); diff --git a/contracts/src/kleros-v1/KlerosV1Governor.sol b/contracts/src/kleros-v1/KlerosV1Governor.sol index d63d1a0d6..e974d6427 100644 --- a/contracts/src/kleros-v1/KlerosV1Governor.sol +++ b/contracts/src/kleros-v1/KlerosV1Governor.sol @@ -129,12 +129,16 @@ contract KlerosV1Governor is IArbitrable, ITokenController { _disputeID ); + uint256 minStakingTime = klerosLiquid.minStakingTime(); + IKlerosLiquid.Phase phase = klerosLiquid.phase(); + bool isDrawingForbidden = phase == IKlerosLiquid.Phase.staking && minStakingTime == type(uint256).max; + for (uint256 round = 0; round < votesLengths.length; round++) { if (isDisputeNotified[_disputeID][round]) continue; for (uint256 voteID = 0; voteID < votesLengths[round]; voteID++) { (address account, , , ) = klerosLiquid.getVote(_disputeID, round, voteID); - require(account != address(0x0), "Juror not drawn yet."); + require(account != address(0x0) || isDrawingForbidden, "Juror not drawn yet."); frozenTokens[account] += tokensAtStakePerJuror[round]; } isDisputeNotified[_disputeID][round] = true; From c28a9d946c1f89c35a1d9e1fc3c7b5d13f6a56a1 Mon Sep 17 00:00:00 2001 From: fnanni-0 Date: Thu, 13 Jan 2022 16:53:54 -0300 Subject: [PATCH 10/10] fix: frozen tokens for null address --- contracts/src/kleros-v1/KlerosV1Governor.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/src/kleros-v1/KlerosV1Governor.sol b/contracts/src/kleros-v1/KlerosV1Governor.sol index e974d6427..484b1971f 100644 --- a/contracts/src/kleros-v1/KlerosV1Governor.sol +++ b/contracts/src/kleros-v1/KlerosV1Governor.sol @@ -139,7 +139,7 @@ contract KlerosV1Governor is IArbitrable, ITokenController { for (uint256 voteID = 0; voteID < votesLengths[round]; voteID++) { (address account, , , ) = klerosLiquid.getVote(_disputeID, round, voteID); require(account != address(0x0) || isDrawingForbidden, "Juror not drawn yet."); - frozenTokens[account] += tokensAtStakePerJuror[round]; + if (account != address(0x0)) frozenTokens[account] += tokensAtStakePerJuror[round]; } isDisputeNotified[_disputeID][round] = true; }