From 52aad1fbfaa0cb1cff93160f6fe45fdc507e10aa Mon Sep 17 00:00:00 2001 From: moebius <0xmoebius@tutanota.com> Date: Fri, 17 Nov 2023 01:05:36 +0100 Subject: [PATCH] perf: optimize left modules --- .../extensions/AccountingExtension.sol | 326 ++++----- .../extensions/BondEscalationAccounting.sol | 268 ++++---- .../modules/dispute/BondEscalationModule.sol | 619 +++++++++-------- .../modules/dispute/BondedDisputeModule.sol | 5 + .../modules/dispute/CircuitResolverModule.sol | 5 + .../dispute/RootVerificationModule.sol | 5 + .../modules/finality/CallbackModule.sol | 5 + .../finality/MultipleCallbacksModule.sol | 5 + .../request/ContractCallRequestModule.sol | 5 + .../modules/request/HttpRequestModule.sol | 5 + .../request/SparseMerkleTreeRequestModule.sol | 5 + .../modules/resolution/ArbitratorModule.sol | 5 + .../BondEscalationResolutionModule.sol | 626 ++++++++++-------- .../resolution/ERC20ResolutionModule.sol | 5 + .../PrivateERC20ResolutionModule.sol | 315 +++++---- .../modules/response/BondedResponseModule.sol | 5 + .../extensions/IBondEscalationAccounting.sol | 480 +++++++------- .../modules/dispute/IBondEscalationModule.sol | 504 +++++++------- .../IBondEscalationResolutionModule.sol | 618 ++++++++--------- .../IPrivateERC20ResolutionModule.sol | 423 ++++++------ .../ISequentialResolutionModule.sol | 8 +- yarn.lock | 18 +- 22 files changed, 2205 insertions(+), 2055 deletions(-) diff --git a/solidity/contracts/extensions/AccountingExtension.sol b/solidity/contracts/extensions/AccountingExtension.sol index abfec376..214251b0 100644 --- a/solidity/contracts/extensions/AccountingExtension.sol +++ b/solidity/contracts/extensions/AccountingExtension.sol @@ -1,163 +1,163 @@ -// // SPDX-License-Identifier: MIT -// pragma solidity ^0.8.19; - -// import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -// import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -// import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; -// import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; - -// import {IAccountingExtension} from '../../interfaces/extensions/IAccountingExtension.sol'; - -// contract AccountingExtension is IAccountingExtension { -// using SafeERC20 for IERC20; -// using EnumerableSet for EnumerableSet.AddressSet; - -// /// @inheritdoc IAccountingExtension -// IOracle public immutable ORACLE; - -// /// @inheritdoc IAccountingExtension -// mapping(address _bonder => mapping(IERC20 _token => uint256 _balance)) public balanceOf; - -// /// @inheritdoc IAccountingExtension -// mapping(address _bonder => mapping(IERC20 _token => mapping(bytes32 _requestId => uint256 _amount))) public -// bondedAmountOf; - -// /** -// * @notice Storing which modules have the users approved to bond their tokens. -// */ -// mapping(address _bonder => EnumerableSet.AddressSet _modules) internal _approvals; - -// constructor(IOracle _oracle) { -// ORACLE = _oracle; -// } - -// /** -// * @notice Checks that the caller is an allowed module used in the request. -// */ -// modifier onlyAllowedModule(bytes32 _requestId) { -// if (!ORACLE.allowedModule(_requestId, msg.sender)) revert AccountingExtension_UnauthorizedModule(); -// _; -// } - -// modifier onlyParticipant(bytes32 _requestId, address _user) { -// if (!ORACLE.isParticipant(_requestId, _user)) revert AccountingExtension_UnauthorizedUser(); -// _; -// } - -// /// @inheritdoc IAccountingExtension -// function deposit(IERC20 _token, uint256 _amount) external { -// _token.safeTransferFrom(msg.sender, address(this), _amount); -// balanceOf[msg.sender][_token] += _amount; -// emit Deposited(msg.sender, _token, _amount); -// } - -// /// @inheritdoc IAccountingExtension -// function withdraw(IERC20 _token, uint256 _amount) external { -// uint256 _balance = balanceOf[msg.sender][_token]; - -// if (_balance < _amount) revert AccountingExtension_InsufficientFunds(); - -// unchecked { -// balanceOf[msg.sender][_token] -= _amount; -// } - -// _token.safeTransfer(msg.sender, _amount); - -// emit Withdrew(msg.sender, _token, _amount); -// } - -// /// @inheritdoc IAccountingExtension -// function pay( -// bytes32 _requestId, -// address _payer, -// address _receiver, -// IERC20 _token, -// uint256 _amount -// ) external onlyAllowedModule(_requestId) onlyParticipant(_requestId, _payer) onlyParticipant(_requestId, _receiver) { -// if (bondedAmountOf[_payer][_token][_requestId] < _amount) { -// revert AccountingExtension_InsufficientFunds(); -// } - -// balanceOf[_receiver][_token] += _amount; - -// unchecked { -// bondedAmountOf[_payer][_token][_requestId] -= _amount; -// } - -// emit Paid({_requestId: _requestId, _beneficiary: _receiver, _payer: _payer, _token: _token, _amount: _amount}); -// } - -// /// @inheritdoc IAccountingExtension -// function bond( -// address _bonder, -// bytes32 _requestId, -// IERC20 _token, -// uint256 _amount -// ) external onlyAllowedModule(_requestId) onlyParticipant(_requestId, _bonder) { -// if (!_approvals[_bonder].contains(msg.sender)) revert AccountingExtension_InsufficientAllowance(); -// if (balanceOf[_bonder][_token] < _amount) revert AccountingExtension_InsufficientFunds(); - -// bondedAmountOf[_bonder][_token][_requestId] += _amount; - -// unchecked { -// balanceOf[_bonder][_token] -= _amount; -// } - -// emit Bonded(_requestId, _bonder, _token, _amount); -// } - -// /// @inheritdoc IAccountingExtension -// function bond( -// address _bonder, -// bytes32 _requestId, -// IERC20 _token, -// uint256 _amount, -// address _sender -// ) external onlyAllowedModule(_requestId) onlyParticipant(_requestId, _bonder) { -// if (!(_approvals[_bonder].contains(msg.sender) || _approvals[_bonder].contains(_sender))) { -// revert AccountingExtension_InsufficientAllowance(); -// } -// if (balanceOf[_bonder][_token] < _amount) revert AccountingExtension_InsufficientFunds(); - -// bondedAmountOf[_bonder][_token][_requestId] += _amount; - -// unchecked { -// balanceOf[_bonder][_token] -= _amount; -// } - -// emit Bonded(_requestId, _bonder, _token, _amount); -// } - -// /// @inheritdoc IAccountingExtension -// function release( -// address _bonder, -// bytes32 _requestId, -// IERC20 _token, -// uint256 _amount -// ) external onlyAllowedModule(_requestId) onlyParticipant(_requestId, _bonder) { -// if (bondedAmountOf[_bonder][_token][_requestId] < _amount) revert AccountingExtension_InsufficientFunds(); - -// balanceOf[_bonder][_token] += _amount; - -// unchecked { -// bondedAmountOf[_bonder][_token][_requestId] -= _amount; -// } - -// emit Released(_requestId, _bonder, _token, _amount); -// } - -// /// @inheritdoc IAccountingExtension -// function approveModule(address _module) external { -// _approvals[msg.sender].add(_module); -// } - -// /// @inheritdoc IAccountingExtension -// function revokeModule(address _module) external { -// _approvals[msg.sender].remove(_module); -// } - -// /// @inheritdoc IAccountingExtension -// function approvedModules(address _user) external view returns (address[] memory _approvedModules) { -// _approvedModules = _approvals[_user].values(); -// } -// } +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; +import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; +import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; + +import {IAccountingExtension} from '../../interfaces/extensions/IAccountingExtension.sol'; + +contract AccountingExtension is IAccountingExtension { + using SafeERC20 for IERC20; + using EnumerableSet for EnumerableSet.AddressSet; + + /// @inheritdoc IAccountingExtension + IOracle public immutable ORACLE; + + /// @inheritdoc IAccountingExtension + mapping(address _bonder => mapping(IERC20 _token => uint256 _balance)) public balanceOf; + + /// @inheritdoc IAccountingExtension + mapping(address _bonder => mapping(IERC20 _token => mapping(bytes32 _requestId => uint256 _amount))) public + bondedAmountOf; + + /** + * @notice Storing which modules have the users approved to bond their tokens. + */ + mapping(address _bonder => EnumerableSet.AddressSet _modules) internal _approvals; + + constructor(IOracle _oracle) { + ORACLE = _oracle; + } + + /** + * @notice Checks that the caller is an allowed module used in the request. + */ + modifier onlyAllowedModule(bytes32 _requestId) { + if (!ORACLE.allowedModule(_requestId, msg.sender)) revert AccountingExtension_UnauthorizedModule(); + _; + } + + modifier onlyParticipant(bytes32 _requestId, address _user) { + if (!ORACLE.isParticipant(_requestId, _user)) revert AccountingExtension_UnauthorizedUser(); + _; + } + + /// @inheritdoc IAccountingExtension + function deposit(IERC20 _token, uint256 _amount) external { + _token.safeTransferFrom(msg.sender, address(this), _amount); + balanceOf[msg.sender][_token] += _amount; + emit Deposited(msg.sender, _token, _amount); + } + + /// @inheritdoc IAccountingExtension + function withdraw(IERC20 _token, uint256 _amount) external { + uint256 _balance = balanceOf[msg.sender][_token]; + + if (_balance < _amount) revert AccountingExtension_InsufficientFunds(); + + unchecked { + balanceOf[msg.sender][_token] -= _amount; + } + + _token.safeTransfer(msg.sender, _amount); + + emit Withdrew(msg.sender, _token, _amount); + } + + /// @inheritdoc IAccountingExtension + function pay( + bytes32 _requestId, + address _payer, + address _receiver, + IERC20 _token, + uint256 _amount + ) external onlyAllowedModule(_requestId) onlyParticipant(_requestId, _payer) onlyParticipant(_requestId, _receiver) { + if (bondedAmountOf[_payer][_token][_requestId] < _amount) { + revert AccountingExtension_InsufficientFunds(); + } + + balanceOf[_receiver][_token] += _amount; + + unchecked { + bondedAmountOf[_payer][_token][_requestId] -= _amount; + } + + emit Paid({_requestId: _requestId, _beneficiary: _receiver, _payer: _payer, _token: _token, _amount: _amount}); + } + + /// @inheritdoc IAccountingExtension + function bond( + address _bonder, + bytes32 _requestId, + IERC20 _token, + uint256 _amount + ) external onlyAllowedModule(_requestId) onlyParticipant(_requestId, _bonder) { + if (!_approvals[_bonder].contains(msg.sender)) revert AccountingExtension_InsufficientAllowance(); + if (balanceOf[_bonder][_token] < _amount) revert AccountingExtension_InsufficientFunds(); + + bondedAmountOf[_bonder][_token][_requestId] += _amount; + + unchecked { + balanceOf[_bonder][_token] -= _amount; + } + + emit Bonded(_requestId, _bonder, _token, _amount); + } + + /// @inheritdoc IAccountingExtension + function bond( + address _bonder, + bytes32 _requestId, + IERC20 _token, + uint256 _amount, + address _sender + ) external onlyAllowedModule(_requestId) onlyParticipant(_requestId, _bonder) { + if (!(_approvals[_bonder].contains(msg.sender) || _approvals[_bonder].contains(_sender))) { + revert AccountingExtension_InsufficientAllowance(); + } + if (balanceOf[_bonder][_token] < _amount) revert AccountingExtension_InsufficientFunds(); + + bondedAmountOf[_bonder][_token][_requestId] += _amount; + + unchecked { + balanceOf[_bonder][_token] -= _amount; + } + + emit Bonded(_requestId, _bonder, _token, _amount); + } + + /// @inheritdoc IAccountingExtension + function release( + address _bonder, + bytes32 _requestId, + IERC20 _token, + uint256 _amount + ) external onlyAllowedModule(_requestId) onlyParticipant(_requestId, _bonder) { + if (bondedAmountOf[_bonder][_token][_requestId] < _amount) revert AccountingExtension_InsufficientFunds(); + + balanceOf[_bonder][_token] += _amount; + + unchecked { + bondedAmountOf[_bonder][_token][_requestId] -= _amount; + } + + emit Released(_requestId, _bonder, _token, _amount); + } + + /// @inheritdoc IAccountingExtension + function approveModule(address _module) external { + _approvals[msg.sender].add(_module); + } + + /// @inheritdoc IAccountingExtension + function revokeModule(address _module) external { + _approvals[msg.sender].remove(_module); + } + + /// @inheritdoc IAccountingExtension + function approvedModules(address _user) external view returns (address[] memory _approvedModules) { + _approvedModules = _approvals[_user].values(); + } +} diff --git a/solidity/contracts/extensions/BondEscalationAccounting.sol b/solidity/contracts/extensions/BondEscalationAccounting.sol index 3c75595d..3efe1e2a 100644 --- a/solidity/contracts/extensions/BondEscalationAccounting.sol +++ b/solidity/contracts/extensions/BondEscalationAccounting.sol @@ -1,134 +1,134 @@ -// // SPDX-License-Identifier: AGPL-3.0-only -// pragma solidity ^0.8.19; - -// import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -// import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; - -// import {AccountingExtension} from './AccountingExtension.sol'; - -// import {IBondEscalationAccounting} from '../../interfaces/extensions/IBondEscalationAccounting.sol'; -// import {IBondEscalationModule} from '../../interfaces/modules/dispute/IBondEscalationModule.sol'; - -// contract BondEscalationAccounting is AccountingExtension, IBondEscalationAccounting { -// /// @inheritdoc IBondEscalationAccounting -// mapping(bytes32 _disputeId => mapping(IERC20 _token => uint256 _amount)) public pledges; - -// /// @inheritdoc IBondEscalationAccounting -// mapping(bytes32 _disputeId => EscalationResult _result) public escalationResults; - -// /// @inheritdoc IBondEscalationAccounting -// mapping(bytes32 _requestId => mapping(address _pledger => bool)) public pledgerClaimed; - -// constructor(IOracle _oracle) AccountingExtension(_oracle) {} - -// /// @inheritdoc IBondEscalationAccounting -// function pledge( -// address _pledger, -// bytes32 _requestId, -// bytes32 _disputeId, -// IERC20 _token, -// uint256 _amount -// ) external onlyAllowedModule(_requestId) { -// if (balanceOf[_pledger][_token] < _amount) revert BondEscalationAccounting_InsufficientFunds(); - -// pledges[_disputeId][_token] += _amount; - -// unchecked { -// balanceOf[_pledger][_token] -= _amount; -// } - -// emit Pledged({_pledger: _pledger, _requestId: _requestId, _disputeId: _disputeId, _token: _token, _amount: _amount}); -// } - -// /// @inheritdoc IBondEscalationAccounting -// function onSettleBondEscalation( -// bytes32 _requestId, -// bytes32 _disputeId, -// bool _forVotesWon, -// IERC20 _token, -// uint256 _amountPerPledger, -// uint256 _winningPledgersLength -// ) external onlyAllowedModule(_requestId) { -// // TODO: check that flooring at _amountPerPledger calculation doesn't mess with this check -// if (pledges[_disputeId][_token] < _amountPerPledger * _winningPledgersLength) { -// revert BondEscalationAccounting_InsufficientFunds(); -// } - -// if (escalationResults[_disputeId].requestId != bytes32(0)) { -// revert BondEscalationAccounting_AlreadySettled(); -// } - -// escalationResults[_disputeId] = EscalationResult({ -// requestId: _requestId, -// forVotesWon: _forVotesWon, -// token: _token, -// amountPerPledger: _amountPerPledger, -// bondEscalationModule: IBondEscalationModule(msg.sender) -// }); - -// emit BondEscalationSettled({ -// _requestId: _requestId, -// _disputeId: _disputeId, -// _forVotesWon: _forVotesWon, -// _token: _token, -// _amountPerPledger: _amountPerPledger, -// _winningPledgersLength: _winningPledgersLength -// }); -// } - -// /// @inheritdoc IBondEscalationAccounting -// function claimEscalationReward(bytes32 _disputeId, address _pledger) external { -// EscalationResult memory _result = escalationResults[_disputeId]; -// if (_result.token == IERC20(address(0))) revert BondEscalationAccounting_NoEscalationResult(); -// bytes32 _requestId = _result.requestId; -// if (pledgerClaimed[_requestId][_pledger]) revert BondEscalationAccounting_AlreadyClaimed(); - -// uint256 _amountPerPledger = _result.amountPerPledger; -// uint256 _numberOfPledges = _result.forVotesWon -// ? _result.bondEscalationModule.pledgesForDispute(_requestId, _pledger) -// : _result.bondEscalationModule.pledgesAgainstDispute(_requestId, _pledger); - -// IERC20 _token = _result.token; -// uint256 _claimAmount = _amountPerPledger * _numberOfPledges; - -// pledgerClaimed[_requestId][_pledger] = true; -// balanceOf[_pledger][_token] += _claimAmount; - -// unchecked { -// pledges[_disputeId][_token] -= _claimAmount; -// } - -// emit EscalationRewardClaimed({ -// _requestId: _requestId, -// _disputeId: _disputeId, -// _pledger: _pledger, -// _token: _result.token, -// _amount: _claimAmount -// }); -// } - -// /// @inheritdoc IBondEscalationAccounting -// function releasePledge( -// bytes32 _requestId, -// bytes32 _disputeId, -// address _pledger, -// IERC20 _token, -// uint256 _amount -// ) external onlyAllowedModule(_requestId) { -// if (pledges[_disputeId][_token] < _amount) revert BondEscalationAccounting_InsufficientFunds(); - -// balanceOf[_pledger][_token] += _amount; - -// unchecked { -// pledges[_disputeId][_token] -= _amount; -// } - -// emit PledgeReleased({ -// _requestId: _requestId, -// _disputeId: _disputeId, -// _pledger: _pledger, -// _token: _token, -// _amount: _amount -// }); -// } -// } +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.19; + +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; + +import {AccountingExtension} from './AccountingExtension.sol'; + +import {IBondEscalationAccounting} from '../../interfaces/extensions/IBondEscalationAccounting.sol'; +import {IBondEscalationModule} from '../../interfaces/modules/dispute/IBondEscalationModule.sol'; + +contract BondEscalationAccounting is AccountingExtension, IBondEscalationAccounting { + /// @inheritdoc IBondEscalationAccounting + mapping(bytes32 _disputeId => mapping(IERC20 _token => uint256 _amount)) public pledges; + + /// @inheritdoc IBondEscalationAccounting + mapping(bytes32 _disputeId => EscalationResult _result) public escalationResults; + + /// @inheritdoc IBondEscalationAccounting + mapping(bytes32 _requestId => mapping(address _pledger => bool)) public pledgerClaimed; + + constructor(IOracle _oracle) AccountingExtension(_oracle) {} + + /// @inheritdoc IBondEscalationAccounting + function pledge( + address _pledger, + bytes32 _requestId, + bytes32 _disputeId, + IERC20 _token, + uint256 _amount + ) external onlyAllowedModule(_requestId) { + if (balanceOf[_pledger][_token] < _amount) revert BondEscalationAccounting_InsufficientFunds(); + + pledges[_disputeId][_token] += _amount; + + unchecked { + balanceOf[_pledger][_token] -= _amount; + } + + emit Pledged({_pledger: _pledger, _requestId: _requestId, _disputeId: _disputeId, _token: _token, _amount: _amount}); + } + + /// @inheritdoc IBondEscalationAccounting + function onSettleBondEscalation( + bytes32 _requestId, + bytes32 _disputeId, + bool _forVotesWon, + IERC20 _token, + uint256 _amountPerPledger, + uint256 _winningPledgersLength + ) external onlyAllowedModule(_requestId) { + // TODO: check that flooring at _amountPerPledger calculation doesn't mess with this check + if (pledges[_disputeId][_token] < _amountPerPledger * _winningPledgersLength) { + revert BondEscalationAccounting_InsufficientFunds(); + } + + if (escalationResults[_disputeId].requestId != bytes32(0)) { + revert BondEscalationAccounting_AlreadySettled(); + } + + escalationResults[_disputeId] = EscalationResult({ + requestId: _requestId, + forVotesWon: _forVotesWon, + token: _token, + amountPerPledger: _amountPerPledger, + bondEscalationModule: IBondEscalationModule(msg.sender) + }); + + emit BondEscalationSettled({ + _requestId: _requestId, + _disputeId: _disputeId, + _forVotesWon: _forVotesWon, + _token: _token, + _amountPerPledger: _amountPerPledger, + _winningPledgersLength: _winningPledgersLength + }); + } + + /// @inheritdoc IBondEscalationAccounting + function claimEscalationReward(bytes32 _disputeId, address _pledger) external { + EscalationResult memory _result = escalationResults[_disputeId]; + if (_result.token == IERC20(address(0))) revert BondEscalationAccounting_NoEscalationResult(); + bytes32 _requestId = _result.requestId; + if (pledgerClaimed[_requestId][_pledger]) revert BondEscalationAccounting_AlreadyClaimed(); + + uint256 _amountPerPledger = _result.amountPerPledger; + uint256 _numberOfPledges = _result.forVotesWon + ? _result.bondEscalationModule.pledgesForDispute(_requestId, _pledger) + : _result.bondEscalationModule.pledgesAgainstDispute(_requestId, _pledger); + + IERC20 _token = _result.token; + uint256 _claimAmount = _amountPerPledger * _numberOfPledges; + + pledgerClaimed[_requestId][_pledger] = true; + balanceOf[_pledger][_token] += _claimAmount; + + unchecked { + pledges[_disputeId][_token] -= _claimAmount; + } + + emit EscalationRewardClaimed({ + _requestId: _requestId, + _disputeId: _disputeId, + _pledger: _pledger, + _token: _result.token, + _amount: _claimAmount + }); + } + + /// @inheritdoc IBondEscalationAccounting + function releasePledge( + bytes32 _requestId, + bytes32 _disputeId, + address _pledger, + IERC20 _token, + uint256 _amount + ) external onlyAllowedModule(_requestId) { + if (pledges[_disputeId][_token] < _amount) revert BondEscalationAccounting_InsufficientFunds(); + + balanceOf[_pledger][_token] += _amount; + + unchecked { + pledges[_disputeId][_token] -= _amount; + } + + emit PledgeReleased({ + _requestId: _requestId, + _disputeId: _disputeId, + _pledger: _pledger, + _token: _token, + _amount: _amount + }); + } +} diff --git a/solidity/contracts/modules/dispute/BondEscalationModule.sol b/solidity/contracts/modules/dispute/BondEscalationModule.sol index ce44ec97..a47c25b7 100644 --- a/solidity/contracts/modules/dispute/BondEscalationModule.sol +++ b/solidity/contracts/modules/dispute/BondEscalationModule.sol @@ -1,314 +1,305 @@ -// // SPDX-License-Identifier: AGPL-3.0-only -// pragma solidity ^0.8.19; - -// // solhint-disable-next-line no-unused-import -// import {Module, IModule} from '@defi-wonderland/prophet-core-contracts/solidity/contracts/Module.sol'; -// import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; -// import {FixedPointMathLib} from 'solmate/utils/FixedPointMathLib.sol'; - -// import {IBondEscalationModule} from '../../../interfaces/modules/dispute/IBondEscalationModule.sol'; - -// contract BondEscalationModule is Module, IBondEscalationModule { -// /// @inheritdoc IBondEscalationModule -// mapping(bytes32 _requestId => mapping(address _pledger => uint256 pledges)) public pledgesForDispute; - -// /// @inheritdoc IBondEscalationModule -// mapping(bytes32 _requestId => mapping(address _pledger => uint256 pledges)) public pledgesAgainstDispute; - -// /** -// * @notice Struct containing all the data for a given escalation. -// */ -// mapping(bytes32 _requestId => BondEscalation) internal _escalations; - -// constructor(IOracle _oracle) Module(_oracle) {} - -// /// @inheritdoc IModule -// function moduleName() external pure returns (string memory _moduleName) { -// return 'BondEscalationModule'; -// } - -// /** -// * @notice Checks if the escalation parameters are valid -// * @param _data The encoded data for the request -// */ -// function _afterSetupRequest(bytes32, bytes calldata _data) internal pure override { -// RequestParameters memory _params = abi.decode(_data, (RequestParameters)); -// if (_params.maxNumberOfEscalations == 0 || _params.bondSize == 0) { -// revert BondEscalationModule_InvalidEscalationParameters(); -// } -// } - -// /// @inheritdoc IBondEscalationModule -// function disputeEscalated(bytes32 _disputeId) external onlyOracle { -// IOracle.Dispute memory _dispute = ORACLE.getDispute(_disputeId); -// bytes32 _requestId = _dispute.requestId; -// BondEscalation storage _escalation = _escalations[_requestId]; - -// if (_requestId == bytes32(0)) revert BondEscalationModule_DisputeDoesNotExist(); - -// if (_disputeId == _escalation.disputeId) { -// RequestParameters memory _params = decodeRequestData(_requestId); -// if (block.timestamp <= _params.bondEscalationDeadline) revert BondEscalationModule_BondEscalationNotOver(); - -// if ( -// _escalation.status != BondEscalationStatus.Active -// || _escalation.amountOfPledgesForDispute != _escalation.amountOfPledgesAgainstDispute -// ) { -// revert BondEscalationModule_NotEscalatable(); -// } - -// _escalation.status = BondEscalationStatus.Escalated; -// emit BondEscalationStatusUpdated(_requestId, _disputeId, BondEscalationStatus.Escalated); -// } -// } - -// /// @inheritdoc IBondEscalationModule -// function disputeResponse( -// bytes32 _requestId, -// bytes32 _responseId, -// address _disputer, -// address _proposer -// ) external onlyOracle returns (IOracle.Dispute memory _dispute) { -// RequestParameters memory _params = decodeRequestData(_requestId); -// IOracle.Response memory _response = ORACLE.getResponse(_responseId); - -// if (block.timestamp > _response.createdAt + _params.disputeWindow) { -// revert BondEscalationModule_DisputeWindowOver(); -// } - -// BondEscalation storage _escalation = _escalations[_requestId]; - -// // Only the first dispute of a request should go through the bond escalation -// // Consecutive disputes should be handled by the resolution module -// if (_escalation.status == BondEscalationStatus.None) { -// if (block.timestamp > _params.bondEscalationDeadline) revert BondEscalationModule_BondEscalationOver(); - -// // Note: this imitates the way _disputeId is calculated on the Oracle, it must always match -// bytes32 _disputeId = keccak256(abi.encodePacked(_disputer, _requestId, _responseId)); -// _escalation.status = BondEscalationStatus.Active; -// _escalation.disputeId = _disputeId; -// emit BondEscalationStatusUpdated(_requestId, _disputeId, BondEscalationStatus.Active); -// } - -// _dispute = IOracle.Dispute({ -// disputer: _disputer, -// responseId: _responseId, -// proposer: _proposer, -// requestId: _requestId, -// status: IOracle.DisputeStatus.Active, -// createdAt: block.timestamp -// }); - -// _params.accountingExtension.bond({ -// _bonder: _disputer, -// _requestId: _requestId, -// _token: _params.bondToken, -// _amount: _params.bondSize -// }); - -// emit ResponseDisputed(_requestId, _responseId, _disputer, _proposer); -// } - -// /// @inheritdoc IBondEscalationModule -// function onDisputeStatusChange(bytes32 _disputeId, IOracle.Dispute memory _dispute) external onlyOracle { -// RequestParameters memory _params = decodeRequestData(_dispute.requestId); - -// bool _won = _dispute.status == IOracle.DisputeStatus.Won; - -// _params.accountingExtension.pay({ -// _requestId: _dispute.requestId, -// _payer: _won ? _dispute.proposer : _dispute.disputer, -// _receiver: _won ? _dispute.disputer : _dispute.proposer, -// _token: _params.bondToken, -// _amount: _params.bondSize -// }); - -// if (_won) { -// _params.accountingExtension.release({ -// _requestId: _dispute.requestId, -// _bonder: _dispute.disputer, -// _token: _params.bondToken, -// _amount: _params.bondSize -// }); -// } - -// BondEscalation storage _escalation = _escalations[_dispute.requestId]; - -// if (_disputeId == _escalation.disputeId) { -// // The dispute has been escalated to the Resolution module -// if (_escalation.status == BondEscalationStatus.Escalated) { -// if (_escalation.amountOfPledgesAgainstDispute == 0) { -// return; -// } - -// BondEscalationStatus _newStatus = _won ? BondEscalationStatus.DisputerWon : BondEscalationStatus.DisputerLost; -// _escalation.status = _newStatus; - -// emit BondEscalationStatusUpdated(_dispute.requestId, _disputeId, _newStatus); - -// _params.accountingExtension.onSettleBondEscalation({ -// _requestId: _dispute.requestId, -// _disputeId: _disputeId, -// _forVotesWon: _won, -// _token: _params.bondToken, -// _amountPerPledger: _params.bondSize << 1, -// _winningPledgersLength: _won ? _escalation.amountOfPledgesForDispute : _escalation.amountOfPledgesAgainstDispute -// }); -// } else { -// // The status has changed to Won or Lost -// uint256 _pledgesForDispute = _escalation.amountOfPledgesForDispute; -// uint256 _pledgesAgainstDispute = _escalation.amountOfPledgesAgainstDispute; -// bool _disputersWon = _pledgesForDispute > _pledgesAgainstDispute; - -// uint256 _amountToPay = _disputersWon -// ? _params.bondSize + FixedPointMathLib.mulDivDown(_pledgesAgainstDispute, _params.bondSize, _pledgesForDispute) -// : _params.bondSize + FixedPointMathLib.mulDivDown(_pledgesForDispute, _params.bondSize, _pledgesAgainstDispute); - -// _params.accountingExtension.onSettleBondEscalation({ -// _requestId: _dispute.requestId, -// _disputeId: _escalation.disputeId, -// _forVotesWon: _disputersWon, -// _token: _params.bondToken, -// _amountPerPledger: _amountToPay, -// _winningPledgersLength: _disputersWon ? _pledgesForDispute : _pledgesAgainstDispute -// }); -// } -// } - -// emit DisputeStatusChanged({ -// _requestId: _dispute.requestId, -// _responseId: _dispute.responseId, -// _disputer: _dispute.disputer, -// _proposer: _dispute.proposer, -// _status: _dispute.status -// }); -// } - -// //////////////////////////////////////////////////////////////////// -// // Bond Escalation Exclusive Functions -// //////////////////////////////////////////////////////////////////// - -// /// @inheritdoc IBondEscalationModule -// function pledgeForDispute(bytes32 _disputeId) external { -// (bytes32 _requestId, RequestParameters memory _params) = _pledgeChecks(_disputeId, true); - -// _escalations[_requestId].amountOfPledgesForDispute += 1; -// pledgesForDispute[_requestId][msg.sender] += 1; -// _params.accountingExtension.pledge({ -// _pledger: msg.sender, -// _requestId: _requestId, -// _disputeId: _disputeId, -// _token: _params.bondToken, -// _amount: _params.bondSize -// }); - -// emit PledgedForDispute(_disputeId, msg.sender, _params.bondSize); -// } - -// /// @inheritdoc IBondEscalationModule -// function pledgeAgainstDispute(bytes32 _disputeId) external { -// (bytes32 _requestId, RequestParameters memory _params) = _pledgeChecks(_disputeId, false); - -// _escalations[_requestId].amountOfPledgesAgainstDispute += 1; -// pledgesAgainstDispute[_requestId][msg.sender] += 1; -// _params.accountingExtension.pledge({ -// _pledger: msg.sender, -// _requestId: _requestId, -// _disputeId: _disputeId, -// _token: _params.bondToken, -// _amount: _params.bondSize -// }); - -// emit PledgedAgainstDispute(_disputeId, msg.sender, _params.bondSize); -// } - -// /// @inheritdoc IBondEscalationModule -// function settleBondEscalation(bytes32 _requestId) external { -// RequestParameters memory _params = decodeRequestData(_requestId); -// BondEscalation storage _escalation = _escalations[_requestId]; - -// if (block.timestamp <= _params.bondEscalationDeadline + _params.tyingBuffer) { -// revert BondEscalationModule_BondEscalationNotOver(); -// } - -// if (_escalation.status != BondEscalationStatus.Active) { -// revert BondEscalationModule_BondEscalationCantBeSettled(); -// } - -// uint256 _pledgesForDispute = _escalation.amountOfPledgesForDispute; -// uint256 _pledgesAgainstDispute = _escalation.amountOfPledgesAgainstDispute; - -// if (_pledgesForDispute == _pledgesAgainstDispute) { -// revert BondEscalationModule_ShouldBeEscalated(); -// } - -// bool _disputersWon = _pledgesForDispute > _pledgesAgainstDispute; -// _escalation.status = _disputersWon ? BondEscalationStatus.DisputerWon : BondEscalationStatus.DisputerLost; - -// emit BondEscalationStatusUpdated(_requestId, _escalation.disputeId, _escalation.status); - -// ORACLE.updateDisputeStatus( -// _escalation.disputeId, _disputersWon ? IOracle.DisputeStatus.Won : IOracle.DisputeStatus.Lost -// ); -// } - -// /** -// * @notice Checks the necessary conditions for pledging -// * @param _disputeId The encoded data for the request -// * @return _requestId The ID of the request being disputed on -// * @return _params The decoded parameters for the request -// */ -// function _pledgeChecks( -// bytes32 _disputeId, -// bool _forDispute -// ) internal view returns (bytes32 _requestId, RequestParameters memory _params) { -// if (_disputeId == 0) revert BondEscalationModule_DisputeDoesNotExist(); - -// IOracle.Dispute memory _dispute = ORACLE.getDispute(_disputeId); -// _requestId = _dispute.requestId; -// BondEscalation memory _escalation = _escalations[_requestId]; - -// if (_disputeId != _escalation.disputeId) { -// revert BondEscalationModule_InvalidDispute(); -// } - -// _params = decodeRequestData(_requestId); - -// if (block.timestamp > _params.bondEscalationDeadline + _params.tyingBuffer) { -// revert BondEscalationModule_BondEscalationOver(); -// } - -// uint256 _numPledgersForDispute = _escalation.amountOfPledgesForDispute; -// uint256 _numPledgersAgainstDispute = _escalation.amountOfPledgesAgainstDispute; - -// if (_forDispute) { -// if (_numPledgersForDispute == _params.maxNumberOfEscalations) { -// revert BondEscalationModule_MaxNumberOfEscalationsReached(); -// } -// if (_numPledgersForDispute > _numPledgersAgainstDispute) revert BondEscalationModule_CanOnlySurpassByOnePledge(); -// } else { -// if (_numPledgersAgainstDispute == _params.maxNumberOfEscalations) { -// revert BondEscalationModule_MaxNumberOfEscalationsReached(); -// } -// if (_numPledgersAgainstDispute > _numPledgersForDispute) revert BondEscalationModule_CanOnlySurpassByOnePledge(); -// } - -// if (block.timestamp > _params.bondEscalationDeadline && _numPledgersForDispute == _numPledgersAgainstDispute) { -// revert BondEscalationModule_CannotBreakTieDuringTyingBuffer(); -// } -// } - -// //////////////////////////////////////////////////////////////////// -// // View Functions -// //////////////////////////////////////////////////////////////////// - -// /// @inheritdoc IBondEscalationModule -// function decodeRequestData(bytes32 _requestId) public view returns (RequestParameters memory _params) { -// _params = abi.decode(requestData[_requestId], (RequestParameters)); -// } - -// /// @inheritdoc IBondEscalationModule -// function getEscalation(bytes32 _requestId) public view returns (BondEscalation memory _escalation) { -// _escalation = _escalations[_requestId]; -// } -// } +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.19; + +// solhint-disable-next-line no-unused-import +import {Module, IModule} from '@defi-wonderland/prophet-core-contracts/solidity/contracts/Module.sol'; +import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; +import {FixedPointMathLib} from 'solmate/utils/FixedPointMathLib.sol'; + +import {IBondEscalationModule} from '../../../interfaces/modules/dispute/IBondEscalationModule.sol'; + +contract BondEscalationModule is Module, IBondEscalationModule { + /// @inheritdoc IBondEscalationModule + mapping(bytes32 _requestId => mapping(address _pledger => uint256 pledges)) public pledgesForDispute; + + /// @inheritdoc IBondEscalationModule + mapping(bytes32 _requestId => mapping(address _pledger => uint256 pledges)) public pledgesAgainstDispute; + + /** + * @notice Struct containing all the data for a given escalation. + */ + mapping(bytes32 _requestId => BondEscalation) internal _escalations; + + constructor(IOracle _oracle) Module(_oracle) {} + + // /// @inheritdoc IModule + function moduleName() external pure returns (string memory _moduleName) { + return 'BondEscalationModule'; + } + + /// @inheritdoc IBondEscalationModule + function disputeResponse( + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute + ) external onlyOracle { + RequestParameters memory _params = decodeRequestData(_request.disputeModuleData); + bytes32 _disputeId = _getId(_dispute); + // TODO: replace created at + // if (block.timestamp > _response.createdAt + _params.disputeWindow) { + // revert BondEscalationModule_DisputeWindowOver(); + // } + + BondEscalation storage _escalation = _escalations[_response.requestId]; + + // Only the first dispute of a request should go through the bond escalation + // Consecutive disputes should be handled by the resolution module + if (_escalation.status == BondEscalationStatus.None) { + if (block.timestamp > _params.bondEscalationDeadline) revert BondEscalationModule_BondEscalationOver(); + + // Note: this imitates the way _disputeId is calculated on the Oracle, it must always match + _escalation.status = BondEscalationStatus.Active; + _escalation.disputeId = _disputeId; + emit BondEscalationStatusUpdated(_response.requestId, _disputeId, BondEscalationStatus.Active); + } + + _params.accountingExtension.bond({ + _bonder: _dispute.disputer, + _requestId: _response.requestId, + _token: _params.bondToken, + _amount: _params.bondSize + }); + + emit ResponseDisputed(_response.requestId, _dispute.responseId, _disputeId, _dispute, block.number); + } + + /// @inheritdoc IBondEscalationModule + function onDisputeStatusChange( + bytes32 _disputeId, + IOracle.Request calldata _request, + IOracle.Response calldata, + IOracle.Dispute calldata _dispute + ) external onlyOracle { + RequestParameters memory _params = decodeRequestData(_request.disputeModuleData); + BondEscalation storage _escalation = _escalations[_dispute.requestId]; + IOracle.DisputeStatus _status = ORACLE.disputeStatus(_disputeId); + + if (_status == IOracle.DisputeStatus.Escalated) { + if (_dispute.requestId == bytes32(0)) revert BondEscalationModule_DisputeDoesNotExist(); + + if (_disputeId == _escalation.disputeId) { + if (block.timestamp <= _params.bondEscalationDeadline) revert BondEscalationModule_BondEscalationNotOver(); + + if ( + _escalation.status != BondEscalationStatus.Active + || _escalation.amountOfPledgesForDispute != _escalation.amountOfPledgesAgainstDispute + ) { + revert BondEscalationModule_NotEscalatable(); + } + + _escalation.status = BondEscalationStatus.Escalated; + emit BondEscalationStatusUpdated(_dispute.requestId, _disputeId, BondEscalationStatus.Escalated); + return; + } + } + + bool _won = _status == IOracle.DisputeStatus.Won; + + _params.accountingExtension.pay({ + _requestId: _dispute.requestId, + _payer: _won ? _dispute.proposer : _dispute.disputer, + _receiver: _won ? _dispute.disputer : _dispute.proposer, + _token: _params.bondToken, + _amount: _params.bondSize + }); + + if (_won) { + _params.accountingExtension.release({ + _requestId: _dispute.requestId, + _bonder: _dispute.disputer, + _token: _params.bondToken, + _amount: _params.bondSize + }); + } + + if (_disputeId == _escalation.disputeId) { + // The dispute has been escalated to the Resolution module + if (_escalation.status == BondEscalationStatus.Escalated) { + if (_escalation.amountOfPledgesAgainstDispute == 0) { + return; + } + + BondEscalationStatus _newStatus = _won ? BondEscalationStatus.DisputerWon : BondEscalationStatus.DisputerLost; + _escalation.status = _newStatus; + + emit BondEscalationStatusUpdated(_dispute.requestId, _disputeId, _newStatus); + + _params.accountingExtension.onSettleBondEscalation({ + _requestId: _dispute.requestId, + _disputeId: _disputeId, + _forVotesWon: _won, + _token: _params.bondToken, + _amountPerPledger: _params.bondSize << 1, + _winningPledgersLength: _won ? _escalation.amountOfPledgesForDispute : _escalation.amountOfPledgesAgainstDispute + }); + } else { + // The status has changed to Won or Lost + uint256 _pledgesForDispute = _escalation.amountOfPledgesForDispute; + uint256 _pledgesAgainstDispute = _escalation.amountOfPledgesAgainstDispute; + bool _disputersWon = _pledgesForDispute > _pledgesAgainstDispute; + + uint256 _amountToPay = _disputersWon + ? _params.bondSize + FixedPointMathLib.mulDivDown(_pledgesAgainstDispute, _params.bondSize, _pledgesForDispute) + : _params.bondSize + FixedPointMathLib.mulDivDown(_pledgesForDispute, _params.bondSize, _pledgesAgainstDispute); + + _params.accountingExtension.onSettleBondEscalation({ + _requestId: _dispute.requestId, + _disputeId: _escalation.disputeId, + _forVotesWon: _disputersWon, + _token: _params.bondToken, + _amountPerPledger: _amountToPay, + _winningPledgersLength: _disputersWon ? _pledgesForDispute : _pledgesAgainstDispute + }); + } + } + + emit DisputeStatusChanged({_disputeId: _disputeId, _dispute: _dispute, _status: _status}); + } + + //////////////////////////////////////////////////////////////////// + // Bond Escalation Exclusive Functions + //////////////////////////////////////////////////////////////////// + + /// @inheritdoc IBondEscalationModule + function pledgeForDispute(IOracle.Request calldata _request, IOracle.Dispute calldata _dispute) external { + bytes32 _disputeId = _getId(_dispute); + (bytes32 _requestId, RequestParameters memory _params) = _pledgeChecks(_request, _dispute, _disputeId, true); + + _escalations[_requestId].amountOfPledgesForDispute += 1; + pledgesForDispute[_requestId][msg.sender] += 1; + _params.accountingExtension.pledge({ + _pledger: msg.sender, + _requestId: _requestId, + _disputeId: _disputeId, + _token: _params.bondToken, + _amount: _params.bondSize + }); + + emit PledgedForDispute(_disputeId, msg.sender, _params.bondSize); + } + + /// @inheritdoc IBondEscalationModule + function pledgeAgainstDispute(IOracle.Request calldata _request, IOracle.Dispute calldata _dispute) external { + bytes32 _disputeId = _getId(_dispute); + (bytes32 _requestId, RequestParameters memory _params) = _pledgeChecks(_request, _dispute, _disputeId, false); + + _escalations[_requestId].amountOfPledgesAgainstDispute += 1; + pledgesAgainstDispute[_requestId][msg.sender] += 1; + _params.accountingExtension.pledge({ + _pledger: msg.sender, + _requestId: _requestId, + _disputeId: _disputeId, + _token: _params.bondToken, + _amount: _params.bondSize + }); + + emit PledgedAgainstDispute(_disputeId, msg.sender, _params.bondSize); + } + + /// @inheritdoc IBondEscalationModule + function settleBondEscalation( + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute + ) external { + bytes32 _requestId = _getId(_request); + bytes32 _responseId = _getId(_response); + // TODO: custom error + if (_requestId != _dispute.requestId) revert(); + if (_responseId != _dispute.responseId) revert(); + + RequestParameters memory _params = decodeRequestData(_request.resolutionModuleData); + BondEscalation storage _escalation = _escalations[_requestId]; + + if (block.timestamp <= _params.bondEscalationDeadline + _params.tyingBuffer) { + revert BondEscalationModule_BondEscalationNotOver(); + } + + if (_escalation.status != BondEscalationStatus.Active) { + revert BondEscalationModule_BondEscalationCantBeSettled(); + } + + uint256 _pledgesForDispute = _escalation.amountOfPledgesForDispute; + uint256 _pledgesAgainstDispute = _escalation.amountOfPledgesAgainstDispute; + + if (_pledgesForDispute == _pledgesAgainstDispute) { + revert BondEscalationModule_ShouldBeEscalated(); + } + + bool _disputersWon = _pledgesForDispute > _pledgesAgainstDispute; + _escalation.status = _disputersWon ? BondEscalationStatus.DisputerWon : BondEscalationStatus.DisputerLost; + + emit BondEscalationStatusUpdated(_requestId, _escalation.disputeId, _escalation.status); + + ORACLE.updateDisputeStatus( + _request, _response, _dispute, _disputersWon ? IOracle.DisputeStatus.Won : IOracle.DisputeStatus.Lost + ); + } + + /** + * @notice Checks the necessary conditions for pledging + * @param _disputeId The encoded data for the request + * @return _requestId The ID of the request being disputed on + * @return _params The decoded parameters for the request + */ + function _pledgeChecks( + IOracle.Request calldata _request, + IOracle.Dispute calldata _dispute, + bytes32 _disputeId, + bool _forDispute + ) internal view returns (bytes32 _requestId, RequestParameters memory _params) { + _requestId = _getId(_request); + // TODO: custom error + if (_requestId != _dispute.requestId) revert(); + + BondEscalation memory _escalation = _escalations[_requestId]; + + if (_disputeId != _escalation.disputeId) { + revert BondEscalationModule_InvalidDispute(); + } + + _params = decodeRequestData(_request.disputeModuleData); + + if (block.timestamp > _params.bondEscalationDeadline + _params.tyingBuffer) { + revert BondEscalationModule_BondEscalationOver(); + } + + uint256 _numPledgersForDispute = _escalation.amountOfPledgesForDispute; + uint256 _numPledgersAgainstDispute = _escalation.amountOfPledgesAgainstDispute; + + if (_forDispute) { + if (_numPledgersForDispute == _params.maxNumberOfEscalations) { + revert BondEscalationModule_MaxNumberOfEscalationsReached(); + } + if (_numPledgersForDispute > _numPledgersAgainstDispute) revert BondEscalationModule_CanOnlySurpassByOnePledge(); + } else { + if (_numPledgersAgainstDispute == _params.maxNumberOfEscalations) { + revert BondEscalationModule_MaxNumberOfEscalationsReached(); + } + if (_numPledgersAgainstDispute > _numPledgersForDispute) revert BondEscalationModule_CanOnlySurpassByOnePledge(); + } + + if (block.timestamp > _params.bondEscalationDeadline && _numPledgersForDispute == _numPledgersAgainstDispute) { + revert BondEscalationModule_CannotBreakTieDuringTyingBuffer(); + } + } + + //////////////////////////////////////////////////////////////////// + // View Functions + //////////////////////////////////////////////////////////////////// + + /// @inheritdoc IBondEscalationModule + function decodeRequestData(bytes calldata _data) public pure returns (RequestParameters memory _params) { + _params = abi.decode(_data, (RequestParameters)); + } + + /// @inheritdoc IBondEscalationModule + function getEscalation(bytes32 _requestId) public view returns (BondEscalation memory _escalation) { + _escalation = _escalations[_requestId]; + } + + function validateParameters(bytes calldata _data) external pure returns (bool _valid) { + abi.decode(_data, (RequestParameters)); + _valid = true; + } +} diff --git a/solidity/contracts/modules/dispute/BondedDisputeModule.sol b/solidity/contracts/modules/dispute/BondedDisputeModule.sol index 1da2a6bd..b920d13e 100644 --- a/solidity/contracts/modules/dispute/BondedDisputeModule.sol +++ b/solidity/contracts/modules/dispute/BondedDisputeModule.sol @@ -103,4 +103,9 @@ contract BondedDisputeModule is Module, IBondedDisputeModule { emit DisputeStatusChanged({_disputeId: _disputeId, _dispute: _dispute, _status: _status}); } + + function validateParameters(bytes calldata _data) external pure returns (bool _valid) { + abi.decode(_data, (RequestParameters)); + _valid = true; + } } diff --git a/solidity/contracts/modules/dispute/CircuitResolverModule.sol b/solidity/contracts/modules/dispute/CircuitResolverModule.sol index 8518a2b4..806084a9 100644 --- a/solidity/contracts/modules/dispute/CircuitResolverModule.sol +++ b/solidity/contracts/modules/dispute/CircuitResolverModule.sol @@ -90,4 +90,9 @@ contract CircuitResolverModule is Module, ICircuitResolverModule { ORACLE.updateDisputeStatus(_request, _response, _dispute, _status); } + + function validateParameters(bytes calldata _data) external pure returns (bool _valid) { + abi.decode(_data, (RequestParameters)); + _valid = true; + } } diff --git a/solidity/contracts/modules/dispute/RootVerificationModule.sol b/solidity/contracts/modules/dispute/RootVerificationModule.sol index e954fc1a..7108a9a9 100644 --- a/solidity/contracts/modules/dispute/RootVerificationModule.sol +++ b/solidity/contracts/modules/dispute/RootVerificationModule.sol @@ -92,4 +92,9 @@ contract RootVerificationModule is Module, IRootVerificationModule { ORACLE.updateDisputeStatus(_request, _response, _dispute, _status); } + + function validateParameters(bytes calldata _data) external pure returns (bool _valid) { + abi.decode(_data, (RequestParameters)); + _valid = true; + } } diff --git a/solidity/contracts/modules/finality/CallbackModule.sol b/solidity/contracts/modules/finality/CallbackModule.sol index f3eea3d9..03f9bc9f 100644 --- a/solidity/contracts/modules/finality/CallbackModule.sol +++ b/solidity/contracts/modules/finality/CallbackModule.sol @@ -31,4 +31,9 @@ contract CallbackModule is Module, ICallbackModule { emit Callback(_response.requestId, _params.target, _params.data); emit RequestFinalized(_response.requestId, _response, _finalizer); } + + function validateParameters(bytes calldata _data) external pure returns (bool _valid) { + abi.decode(_data, (RequestParameters)); + _valid = true; + } } diff --git a/solidity/contracts/modules/finality/MultipleCallbacksModule.sol b/solidity/contracts/modules/finality/MultipleCallbacksModule.sol index b2406538..6c6bdbe6 100644 --- a/solidity/contracts/modules/finality/MultipleCallbacksModule.sol +++ b/solidity/contracts/modules/finality/MultipleCallbacksModule.sol @@ -39,4 +39,9 @@ contract MultipleCallbacksModule is Module, IMultipleCallbacksModule { emit RequestFinalized(_response.requestId, _response, _finalizer); } + + function validateParameters(bytes calldata _data) external pure returns (bool _valid) { + abi.decode(_data, (RequestParameters)); + _valid = true; + } } diff --git a/solidity/contracts/modules/request/ContractCallRequestModule.sol b/solidity/contracts/modules/request/ContractCallRequestModule.sol index 311487ec..14f700bb 100644 --- a/solidity/contracts/modules/request/ContractCallRequestModule.sol +++ b/solidity/contracts/modules/request/ContractCallRequestModule.sol @@ -59,4 +59,9 @@ contract ContractCallRequestModule is Module, IContractCallRequestModule { emit RequestFinalized(_response.requestId, _response, _finalizer); } + + function validateParameters(bytes calldata _data) external pure returns (bool _valid) { + abi.decode(_data, (RequestParameters)); + _valid = true; + } } diff --git a/solidity/contracts/modules/request/HttpRequestModule.sol b/solidity/contracts/modules/request/HttpRequestModule.sol index 78531a18..b02f480b 100644 --- a/solidity/contracts/modules/request/HttpRequestModule.sol +++ b/solidity/contracts/modules/request/HttpRequestModule.sol @@ -59,4 +59,9 @@ contract HttpRequestModule is Module, IHttpRequestModule { emit RequestFinalized(_response.requestId, _response, _finalizer); } + + function validateParameters(bytes calldata _data) external pure returns (bool _valid) { + abi.decode(_data, (RequestParameters)); + _valid = true; + } } diff --git a/solidity/contracts/modules/request/SparseMerkleTreeRequestModule.sol b/solidity/contracts/modules/request/SparseMerkleTreeRequestModule.sol index b5ba9938..c68ecbf4 100644 --- a/solidity/contracts/modules/request/SparseMerkleTreeRequestModule.sol +++ b/solidity/contracts/modules/request/SparseMerkleTreeRequestModule.sol @@ -59,4 +59,9 @@ contract SparseMerkleTreeRequestModule is Module, ISparseMerkleTreeRequestModule emit RequestFinalized(_response.requestId, _response, _finalizer); } + + function validateParameters(bytes calldata _data) external pure returns (bool _valid) { + abi.decode(_data, (RequestParameters)); + _valid = true; + } } diff --git a/solidity/contracts/modules/resolution/ArbitratorModule.sol b/solidity/contracts/modules/resolution/ArbitratorModule.sol index 0f4df46a..fad1eaf5 100644 --- a/solidity/contracts/modules/resolution/ArbitratorModule.sol +++ b/solidity/contracts/modules/resolution/ArbitratorModule.sol @@ -66,4 +66,9 @@ contract ArbitratorModule is Module, IArbitratorModule { emit DisputeResolved(_dispute.requestId, _disputeId, _status); } + + function validateParameters(bytes calldata _data) external pure returns (bool _valid) { + abi.decode(_data, (RequestParameters)); + _valid = true; + } } diff --git a/solidity/contracts/modules/resolution/BondEscalationResolutionModule.sol b/solidity/contracts/modules/resolution/BondEscalationResolutionModule.sol index b0e85fb4..ba8baffd 100644 --- a/solidity/contracts/modules/resolution/BondEscalationResolutionModule.sol +++ b/solidity/contracts/modules/resolution/BondEscalationResolutionModule.sol @@ -1,292 +1,334 @@ -// // SPDX-License-Identifier: MIT -// pragma solidity ^0.8.19; - -// // solhint-disable-next-line no-unused-import -// import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -// import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -// import {FixedPointMathLib} from 'solmate/utils/FixedPointMathLib.sol'; - -// // solhint-disable-next-line no-unused-import -// import {IResolutionModule} from -// '@defi-wonderland/prophet-core-contracts/solidity/interfaces/modules/resolution/IResolutionModule.sol'; -// import {Module, IModule} from '@defi-wonderland/prophet-core-contracts/solidity/contracts/Module.sol'; -// import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; - -// import {IBondEscalationResolutionModule} from -// '../../../interfaces/modules/resolution/IBondEscalationResolutionModule.sol'; - -// contract BondEscalationResolutionModule is Module, IBondEscalationResolutionModule { -// using SafeERC20 for IERC20; - -// /// @inheritdoc IBondEscalationResolutionModule -// uint256 public constant BASE = 1e18; - -// /// @inheritdoc IBondEscalationResolutionModule -// mapping(bytes32 _disputeId => Escalation _escalation) public escalations; - -// /// @inheritdoc IBondEscalationResolutionModule -// mapping(bytes32 _disputeId => InequalityData _inequalityData) public inequalityData; - -// /// @inheritdoc IBondEscalationResolutionModule -// mapping(bytes32 _disputeId => mapping(address _pledger => uint256 pledges)) public pledgesForDispute; - -// /// @inheritdoc IBondEscalationResolutionModule -// mapping(bytes32 _disputeId => mapping(address _pledger => uint256 pledges)) public pledgesAgainstDispute; - -// constructor(IOracle _oracle) Module(_oracle) {} - -// /// @inheritdoc IModule -// function moduleName() external pure returns (string memory _moduleName) { -// return 'BondEscalationResolutionModule'; -// } - -// /// @inheritdoc IBondEscalationResolutionModule -// function decodeRequestData(bytes32 _requestId) public view returns (RequestParameters memory _params) { -// _params = abi.decode(requestData[_requestId], (RequestParameters)); -// } - -// /// @inheritdoc IResolutionModule -// function startResolution(bytes32 _disputeId) external onlyOracle { -// bytes32 _requestId = ORACLE.getDispute(_disputeId).requestId; -// escalations[_disputeId].startTime = uint128(block.timestamp); -// emit ResolutionStarted(_requestId, _disputeId); -// } - -// /// @inheritdoc IBondEscalationResolutionModule -// function pledgeForDispute(bytes32 _requestId, bytes32 _disputeId, uint256 _pledgeAmount) external { -// _pledge(_requestId, _disputeId, _pledgeAmount, true); -// } - -// /// @inheritdoc IBondEscalationResolutionModule -// function pledgeAgainstDispute(bytes32 _requestId, bytes32 _disputeId, uint256 _pledgeAmount) external { -// _pledge(_requestId, _disputeId, _pledgeAmount, false); -// } - -// /// @inheritdoc IResolutionModule -// function resolveDispute(bytes32 _disputeId) external onlyOracle { -// Escalation storage _escalation = escalations[_disputeId]; - -// if (_escalation.resolution != Resolution.Unresolved) revert BondEscalationResolutionModule_AlreadyResolved(); -// if (_escalation.startTime == 0) revert BondEscalationResolutionModule_NotEscalated(); - -// bytes32 _requestId = ORACLE.getDispute(_disputeId).requestId; - -// RequestParameters memory _params = decodeRequestData(_requestId); -// InequalityData storage _inequalityData = inequalityData[_disputeId]; - -// uint256 _inequalityTimerDeadline = _inequalityData.time + _params.timeToBreakInequality; -// uint256 _pledgingDeadline = _escalation.startTime + _params.timeUntilDeadline; - -// // Revert if we have not yet reached the deadline and the timer has not passed -// if (block.timestamp < _pledgingDeadline && block.timestamp < _inequalityTimerDeadline) { -// revert BondEscalationResolutionModule_PledgingPhaseNotOver(); -// } - -// uint256 _pledgesFor = _escalation.pledgesFor; -// uint256 _pledgesAgainst = _escalation.pledgesAgainst; -// uint256 _totalPledges = _pledgesFor + _pledgesAgainst; - -// IOracle.DisputeStatus _disputeStatus; - -// if (_totalPledges < _params.pledgeThreshold || _pledgesFor == _pledgesAgainst) { -// _escalation.resolution = Resolution.NoResolution; -// _disputeStatus = IOracle.DisputeStatus.NoResolution; -// } else if (_pledgesFor > _pledgesAgainst) { -// _escalation.resolution = Resolution.DisputerWon; -// _disputeStatus = IOracle.DisputeStatus.Won; -// } else if (_pledgesAgainst > _pledgesFor) { -// _escalation.resolution = Resolution.DisputerLost; -// _disputeStatus = IOracle.DisputeStatus.Lost; -// } - -// ORACLE.updateDisputeStatus(_disputeId, _disputeStatus); -// emit DisputeResolved(_requestId, _disputeId, _disputeStatus); -// } - -// /// @inheritdoc IBondEscalationResolutionModule -// function claimPledge(bytes32 _requestId, bytes32 _disputeId) external { -// Escalation storage _escalation = escalations[_disputeId]; - -// if (_escalation.resolution == Resolution.Unresolved) revert BondEscalationResolutionModule_NotResolved(); - -// uint256 _pledgerBalanceBefore; -// uint256 _pledgerProportion; -// uint256 _amountToRelease; -// uint256 _reward; - -// if (_escalation.resolution == Resolution.DisputerWon) { -// _pledgerBalanceBefore = pledgesForDispute[_disputeId][msg.sender]; -// pledgesForDispute[_disputeId][msg.sender] -= _pledgerBalanceBefore; -// _pledgerProportion = FixedPointMathLib.mulDivDown(_pledgerBalanceBefore, BASE, _escalation.pledgesFor); -// _reward = FixedPointMathLib.mulDivDown(_escalation.pledgesAgainst, _pledgerProportion, BASE); -// _amountToRelease = _reward + _pledgerBalanceBefore; -// _claimPledge(_requestId, _disputeId, _amountToRelease, _escalation.resolution); -// } else if (_escalation.resolution == Resolution.DisputerLost) { -// _pledgerBalanceBefore = pledgesAgainstDispute[_disputeId][msg.sender]; -// pledgesAgainstDispute[_disputeId][msg.sender] -= _pledgerBalanceBefore; -// _pledgerProportion = FixedPointMathLib.mulDivDown(_pledgerBalanceBefore, BASE, _escalation.pledgesAgainst); -// _reward = FixedPointMathLib.mulDivDown(_escalation.pledgesFor, _pledgerProportion, BASE); -// _amountToRelease = _reward + _pledgerBalanceBefore; -// _claimPledge(_requestId, _disputeId, _amountToRelease, _escalation.resolution); -// } else if (_escalation.resolution == Resolution.NoResolution) { -// uint256 _pledgerBalanceFor = pledgesForDispute[_disputeId][msg.sender]; -// uint256 _pledgerBalanceAgainst = pledgesAgainstDispute[_disputeId][msg.sender]; - -// if (_pledgerBalanceFor > 0) { -// pledgesForDispute[_disputeId][msg.sender] -= _pledgerBalanceFor; -// _claimPledge(_requestId, _disputeId, _pledgerBalanceFor, _escalation.resolution); -// } - -// if (_pledgerBalanceAgainst > 0) { -// pledgesAgainstDispute[_disputeId][msg.sender] -= _pledgerBalanceAgainst; -// _claimPledge(_requestId, _disputeId, _pledgerBalanceAgainst, _escalation.resolution); -// } -// } -// } - -// /** -// * @notice Pledges for or against a dispute -// * -// * @param _requestId The ID of the request -// * @param _disputeId The ID of the dispute -// * @param _pledgeAmount The amount to pledge -// * @param _pledgingFor Whether the pledger is pledging for or against the dispute -// */ -// function _pledge(bytes32 _requestId, bytes32 _disputeId, uint256 _pledgeAmount, bool _pledgingFor) internal { -// Escalation storage _escalation = escalations[_disputeId]; - -// if (_escalation.startTime == 0) revert BondEscalationResolutionModule_NotEscalated(); - -// InequalityData storage _inequalityData = inequalityData[_disputeId]; -// RequestParameters memory _params = decodeRequestData(_requestId); - -// uint256 _pledgingDeadline = _escalation.startTime + _params.timeUntilDeadline; - -// if (block.timestamp >= _pledgingDeadline) revert BondEscalationResolutionModule_PledgingPhaseOver(); - -// // Revert if the inequality timer has passed -// if (_inequalityData.time != 0 && block.timestamp >= _inequalityData.time + _params.timeToBreakInequality) { -// revert BondEscalationResolutionModule_MustBeResolved(); -// } - -// _params.accountingExtension.pledge({ -// _pledger: msg.sender, -// _requestId: _requestId, -// _disputeId: _disputeId, -// _token: _params.bondToken, -// _amount: _pledgeAmount -// }); - -// if (_pledgingFor) { -// if (_inequalityData.inequalityStatus == InequalityStatus.AgainstTurnToEqualize) { -// revert BondEscalationResolutionModule_AgainstTurnToEqualize(); -// } - -// _escalation.pledgesFor += _pledgeAmount; -// pledgesForDispute[_disputeId][msg.sender] += _pledgeAmount; -// emit PledgedForDispute(msg.sender, _requestId, _disputeId, _pledgeAmount); -// } else { -// if (_inequalityData.inequalityStatus == InequalityStatus.ForTurnToEqualize) { -// revert BondEscalationResolutionModule_ForTurnToEqualize(); -// } - -// _escalation.pledgesAgainst += _pledgeAmount; -// pledgesAgainstDispute[_disputeId][msg.sender] += _pledgeAmount; -// emit PledgedAgainstDispute(msg.sender, _requestId, _disputeId, _pledgeAmount); -// } - -// if (_escalation.pledgesFor + _escalation.pledgesAgainst >= _params.pledgeThreshold) { -// _updateInequalityStatus({ -// _inequalityData: _inequalityData, -// _pledgesFor: _escalation.pledgesFor, -// _pledgesAgainst: _escalation.pledgesAgainst, -// _percentageDiff: _params.percentageDiff, -// _pledgingFor: _pledgingFor -// }); -// } -// } - -// /** -// * @notice Updates the inequality status of the dispute, switching it from one side to the other if the percentage difference is reached -// * -// * @param _inequalityData The inequality data for the dispute -// * @param _pledgesFor The total amount of pledges for the dispute -// * @param _pledgesAgainst The total amount of pledges against the dispute -// * @param _percentageDiff The percentage difference between the two sides -// * @param _pledgingFor Whether the pledger is pledging for or against the dispute -// */ -// function _updateInequalityStatus( -// InequalityData storage _inequalityData, -// uint256 _pledgesFor, -// uint256 _pledgesAgainst, -// uint256 _percentageDiff, -// bool _pledgingFor -// ) internal { -// uint256 _totalPledges = _pledgesFor + _pledgesAgainst; -// uint256 _pledgesForPercentage = FixedPointMathLib.mulDivDown(_pledgesFor, BASE, _totalPledges); -// uint256 _pledgesAgainstPercentage = FixedPointMathLib.mulDivDown(_pledgesAgainst, BASE, _totalPledges); - -// int256 _forPercentageDifference = int256(_pledgesForPercentage) - int256(_pledgesAgainstPercentage); -// int256 _againstPercentageDifference = int256(_pledgesAgainstPercentage) - int256(_pledgesForPercentage); - -// int256 _scaledPercentageDiffAsInt = int256(_percentageDiff * BASE / 100); - -// if (_pledgingFor) { -// if (_againstPercentageDifference >= _scaledPercentageDiffAsInt) return; - -// if (_forPercentageDifference >= _scaledPercentageDiffAsInt) { -// _inequalityData.inequalityStatus = InequalityStatus.AgainstTurnToEqualize; -// _inequalityData.time = block.timestamp; -// } else if (_inequalityData.inequalityStatus == InequalityStatus.ForTurnToEqualize) { -// // At this point, both _forPercentageDiff and _againstPercentageDiff are < _percentageDiff -// _inequalityData.inequalityStatus = InequalityStatus.Equalized; -// _inequalityData.time = 0; -// } -// } else { -// if (_forPercentageDifference >= _scaledPercentageDiffAsInt) return; - -// if (_againstPercentageDifference >= _scaledPercentageDiffAsInt) { -// _inequalityData.inequalityStatus = InequalityStatus.ForTurnToEqualize; -// _inequalityData.time = block.timestamp; -// } else if (_inequalityData.inequalityStatus == InequalityStatus.AgainstTurnToEqualize) { -// // At this point, both _forPercentageDiff and _againstPercentageDiff are < _percentageDiff -// _inequalityData.inequalityStatus = InequalityStatus.Equalized; -// _inequalityData.time = 0; -// } -// } -// } - -// /** -// * @notice Releases the pledged funds to the pledger -// * -// * @param _requestId The ID of the request -// * @param _disputeId The ID of the dispute -// * @param _amountToRelease The amount to release -// * @param _resolution The resolution of the dispute -// */ -// function _claimPledge( -// bytes32 _requestId, -// bytes32 _disputeId, -// uint256 _amountToRelease, -// Resolution _resolution -// ) internal { -// RequestParameters memory _params = decodeRequestData(_requestId); - -// _params.accountingExtension.releasePledge({ -// _requestId: _requestId, -// _disputeId: _disputeId, -// _pledger: msg.sender, -// _token: _params.bondToken, -// _amount: _amountToRelease -// }); - -// emit PledgeClaimed({ -// _requestId: _requestId, -// _disputeId: _disputeId, -// _pledger: msg.sender, -// _token: _params.bondToken, -// _pledgeReleased: _amountToRelease, -// _resolution: _resolution -// }); -// } -// } +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +// solhint-disable-next-line no-unused-import +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; +import {FixedPointMathLib} from 'solmate/utils/FixedPointMathLib.sol'; + +// solhint-disable-next-line no-unused-import +import {IResolutionModule} from + '@defi-wonderland/prophet-core-contracts/solidity/interfaces/modules/resolution/IResolutionModule.sol'; +import {Module, IModule} from '@defi-wonderland/prophet-core-contracts/solidity/contracts/Module.sol'; +import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; + +import {IBondEscalationResolutionModule} from + '../../../interfaces/modules/resolution/IBondEscalationResolutionModule.sol'; + +contract BondEscalationResolutionModule is Module, IBondEscalationResolutionModule { + using SafeERC20 for IERC20; + + /// @inheritdoc IBondEscalationResolutionModule + uint256 public constant BASE = 1e18; + + /// @inheritdoc IBondEscalationResolutionModule + mapping(bytes32 _disputeId => Escalation _escalation) public escalations; + + /// @inheritdoc IBondEscalationResolutionModule + mapping(bytes32 _disputeId => InequalityData _inequalityData) public inequalityData; + + /// @inheritdoc IBondEscalationResolutionModule + mapping(bytes32 _disputeId => mapping(address _pledger => uint256 pledges)) public pledgesForDispute; + + /// @inheritdoc IBondEscalationResolutionModule + mapping(bytes32 _disputeId => mapping(address _pledger => uint256 pledges)) public pledgesAgainstDispute; + + constructor(IOracle _oracle) Module(_oracle) {} + + /// @inheritdoc IModule + function moduleName() external pure returns (string memory _moduleName) { + return 'BondEscalationResolutionModule'; + } + + /// @inheritdoc IBondEscalationResolutionModule + function decodeRequestData(bytes calldata _data) public pure returns (RequestParameters memory _params) { + _params = abi.decode(_data, (RequestParameters)); + } + + /// @inheritdoc IResolutionModule + function startResolution( + bytes32 _disputeId, + IOracle.Request calldata, + IOracle.Response calldata _response, + IOracle.Dispute calldata + ) external onlyOracle { + escalations[_disputeId].startTime = uint128(block.timestamp); + emit ResolutionStarted(_response.requestId, _disputeId); + } + + /// @inheritdoc IBondEscalationResolutionModule + function pledgeForDispute( + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute, + bytes32 _disputeId, + uint256 _pledgeAmount + ) external { + _pledge(_request, _response, _dispute, _disputeId, _pledgeAmount, true); + } + + /// @inheritdoc IBondEscalationResolutionModule + function pledgeAgainstDispute( + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute, + bytes32 _disputeId, + uint256 _pledgeAmount + ) external { + _pledge(_request, _response, _dispute, _disputeId, _pledgeAmount, false); + } + + /// @inheritdoc IResolutionModule + function resolveDispute( + bytes32 _disputeId, + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute + ) external onlyOracle { + Escalation storage _escalation = escalations[_disputeId]; + + if (_escalation.resolution != Resolution.Unresolved) revert BondEscalationResolutionModule_AlreadyResolved(); + if (_escalation.startTime == 0) revert BondEscalationResolutionModule_NotEscalated(); + + RequestParameters memory _params = decodeRequestData(_request.resolutionModuleData); + InequalityData storage _inequalityData = inequalityData[_disputeId]; + + uint256 _inequalityTimerDeadline = _inequalityData.time + _params.timeToBreakInequality; + uint256 _pledgingDeadline = _escalation.startTime + _params.timeUntilDeadline; + + // Revert if we have not yet reached the deadline and the timer has not passed + if (block.timestamp < _pledgingDeadline && block.timestamp < _inequalityTimerDeadline) { + revert BondEscalationResolutionModule_PledgingPhaseNotOver(); + } + + uint256 _pledgesFor = _escalation.pledgesFor; + uint256 _pledgesAgainst = _escalation.pledgesAgainst; + uint256 _totalPledges = _pledgesFor + _pledgesAgainst; + + IOracle.DisputeStatus _disputeStatus; + + if (_totalPledges < _params.pledgeThreshold || _pledgesFor == _pledgesAgainst) { + _escalation.resolution = Resolution.NoResolution; + _disputeStatus = IOracle.DisputeStatus.NoResolution; + } else if (_pledgesFor > _pledgesAgainst) { + _escalation.resolution = Resolution.DisputerWon; + _disputeStatus = IOracle.DisputeStatus.Won; + } else if (_pledgesAgainst > _pledgesFor) { + _escalation.resolution = Resolution.DisputerLost; + _disputeStatus = IOracle.DisputeStatus.Lost; + } + + ORACLE.updateDisputeStatus(_request, _response, _dispute, _disputeStatus); + emit DisputeResolved(_response.requestId, _disputeId, _disputeStatus); + } + + /// @inheritdoc IBondEscalationResolutionModule + function claimPledge(IOracle.Request calldata _request, bytes32 _requestId, bytes32 _disputeId) external { + Escalation storage _escalation = escalations[_disputeId]; + + if (_escalation.resolution == Resolution.Unresolved) revert BondEscalationResolutionModule_NotResolved(); + + uint256 _pledgerBalanceBefore; + uint256 _pledgerProportion; + uint256 _amountToRelease; + uint256 _reward; + + if (_escalation.resolution == Resolution.DisputerWon) { + _pledgerBalanceBefore = pledgesForDispute[_disputeId][msg.sender]; + pledgesForDispute[_disputeId][msg.sender] -= _pledgerBalanceBefore; + _pledgerProportion = FixedPointMathLib.mulDivDown(_pledgerBalanceBefore, BASE, _escalation.pledgesFor); + _reward = FixedPointMathLib.mulDivDown(_escalation.pledgesAgainst, _pledgerProportion, BASE); + _amountToRelease = _reward + _pledgerBalanceBefore; + _claimPledge(_request.resolutionModuleData, _requestId, _disputeId, _amountToRelease, _escalation.resolution); + } else if (_escalation.resolution == Resolution.DisputerLost) { + _pledgerBalanceBefore = pledgesAgainstDispute[_disputeId][msg.sender]; + pledgesAgainstDispute[_disputeId][msg.sender] -= _pledgerBalanceBefore; + _pledgerProportion = FixedPointMathLib.mulDivDown(_pledgerBalanceBefore, BASE, _escalation.pledgesAgainst); + _reward = FixedPointMathLib.mulDivDown(_escalation.pledgesFor, _pledgerProportion, BASE); + _amountToRelease = _reward + _pledgerBalanceBefore; + _claimPledge(_request.resolutionModuleData, _requestId, _disputeId, _amountToRelease, _escalation.resolution); + } else if (_escalation.resolution == Resolution.NoResolution) { + uint256 _pledgerBalanceFor = pledgesForDispute[_disputeId][msg.sender]; + uint256 _pledgerBalanceAgainst = pledgesAgainstDispute[_disputeId][msg.sender]; + + if (_pledgerBalanceFor > 0) { + pledgesForDispute[_disputeId][msg.sender] -= _pledgerBalanceFor; + _claimPledge(_request.resolutionModuleData, _requestId, _disputeId, _pledgerBalanceFor, _escalation.resolution); + } + + if (_pledgerBalanceAgainst > 0) { + pledgesAgainstDispute[_disputeId][msg.sender] -= _pledgerBalanceAgainst; + _claimPledge( + _request.resolutionModuleData, _requestId, _disputeId, _pledgerBalanceAgainst, _escalation.resolution + ); + } + } + } + + /** + * @notice Pledges for or against a dispute + * + * @param _request The ID of the request + * @param _response The ID of the dispute + * @param _dispute The ID of the dispute + * @param _pledgeAmount The amount to pledge + * @param _pledgingFor Whether the pledger is pledging for or against the dispute + */ + function _pledge( + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute, + bytes32 _disputeId, + uint256 _pledgeAmount, + bool _pledgingFor + ) internal { + bytes32 _requestId = _getId(_request); + bytes32 _responseId = _getId(_response); + + // TODO: custom errors + if (_requestId != _dispute.requestId) revert(); + if (_responseId != _dispute.responseId) revert(); + + Escalation storage _escalation = escalations[_disputeId]; + + if (_escalation.startTime == 0) revert BondEscalationResolutionModule_NotEscalated(); + + InequalityData storage _inequalityData = inequalityData[_disputeId]; + RequestParameters memory _params = decodeRequestData(_request.resolutionModuleData); + + uint256 _pledgingDeadline = _escalation.startTime + _params.timeUntilDeadline; + + if (block.timestamp >= _pledgingDeadline) revert BondEscalationResolutionModule_PledgingPhaseOver(); + + // Revert if the inequality timer has passed + if (_inequalityData.time != 0 && block.timestamp >= _inequalityData.time + _params.timeToBreakInequality) { + revert BondEscalationResolutionModule_MustBeResolved(); + } + + _params.accountingExtension.pledge({ + _pledger: msg.sender, + _requestId: _requestId, + _disputeId: _disputeId, + _token: _params.bondToken, + _amount: _pledgeAmount + }); + + if (_pledgingFor) { + if (_inequalityData.inequalityStatus == InequalityStatus.AgainstTurnToEqualize) { + revert BondEscalationResolutionModule_AgainstTurnToEqualize(); + } + + _escalation.pledgesFor += _pledgeAmount; + pledgesForDispute[_disputeId][msg.sender] += _pledgeAmount; + emit PledgedForDispute(msg.sender, _requestId, _disputeId, _pledgeAmount); + } else { + if (_inequalityData.inequalityStatus == InequalityStatus.ForTurnToEqualize) { + revert BondEscalationResolutionModule_ForTurnToEqualize(); + } + + _escalation.pledgesAgainst += _pledgeAmount; + pledgesAgainstDispute[_disputeId][msg.sender] += _pledgeAmount; + emit PledgedAgainstDispute(msg.sender, _requestId, _disputeId, _pledgeAmount); + } + + if (_escalation.pledgesFor + _escalation.pledgesAgainst >= _params.pledgeThreshold) { + _updateInequalityStatus({ + _inequalityData: _inequalityData, + _pledgesFor: _escalation.pledgesFor, + _pledgesAgainst: _escalation.pledgesAgainst, + _percentageDiff: _params.percentageDiff, + _pledgingFor: _pledgingFor + }); + } + } + + /** + * @notice Updates the inequality status of the dispute, switching it from one side to the other if the percentage difference is reached + * + * @param _inequalityData The inequality data for the dispute + * @param _pledgesFor The total amount of pledges for the dispute + * @param _pledgesAgainst The total amount of pledges against the dispute + * @param _percentageDiff The percentage difference between the two sides + * @param _pledgingFor Whether the pledger is pledging for or against the dispute + */ + function _updateInequalityStatus( + InequalityData storage _inequalityData, + uint256 _pledgesFor, + uint256 _pledgesAgainst, + uint256 _percentageDiff, + bool _pledgingFor + ) internal { + uint256 _totalPledges = _pledgesFor + _pledgesAgainst; + uint256 _pledgesForPercentage = FixedPointMathLib.mulDivDown(_pledgesFor, BASE, _totalPledges); + uint256 _pledgesAgainstPercentage = FixedPointMathLib.mulDivDown(_pledgesAgainst, BASE, _totalPledges); + + int256 _forPercentageDifference = int256(_pledgesForPercentage) - int256(_pledgesAgainstPercentage); + int256 _againstPercentageDifference = int256(_pledgesAgainstPercentage) - int256(_pledgesForPercentage); + + int256 _scaledPercentageDiffAsInt = int256(_percentageDiff * BASE / 100); + + if (_pledgingFor) { + if (_againstPercentageDifference >= _scaledPercentageDiffAsInt) return; + + if (_forPercentageDifference >= _scaledPercentageDiffAsInt) { + _inequalityData.inequalityStatus = InequalityStatus.AgainstTurnToEqualize; + _inequalityData.time = block.timestamp; + } else if (_inequalityData.inequalityStatus == InequalityStatus.ForTurnToEqualize) { + // At this point, both _forPercentageDiff and _againstPercentageDiff are < _percentageDiff + _inequalityData.inequalityStatus = InequalityStatus.Equalized; + _inequalityData.time = 0; + } + } else { + if (_forPercentageDifference >= _scaledPercentageDiffAsInt) return; + + if (_againstPercentageDifference >= _scaledPercentageDiffAsInt) { + _inequalityData.inequalityStatus = InequalityStatus.ForTurnToEqualize; + _inequalityData.time = block.timestamp; + } else if (_inequalityData.inequalityStatus == InequalityStatus.AgainstTurnToEqualize) { + // At this point, both _forPercentageDiff and _againstPercentageDiff are < _percentageDiff + _inequalityData.inequalityStatus = InequalityStatus.Equalized; + _inequalityData.time = 0; + } + } + } + + /** + * @notice Releases the pledged funds to the pledger + * + * @param _requestId The ID of the request + * @param _disputeId The ID of the dispute + * @param _amountToRelease The amount to release + * @param _resolution The resolution of the dispute + */ + function _claimPledge( + bytes calldata _requestData, + bytes32 _requestId, + bytes32 _disputeId, + uint256 _amountToRelease, + Resolution _resolution + ) internal { + RequestParameters memory _params = decodeRequestData(_requestData); + + _params.accountingExtension.releasePledge({ + _requestId: _requestId, + _disputeId: _disputeId, + _pledger: msg.sender, + _token: _params.bondToken, + _amount: _amountToRelease + }); + + emit PledgeClaimed({ + _requestId: _requestId, + _disputeId: _disputeId, + _pledger: msg.sender, + _token: _params.bondToken, + _pledgeReleased: _amountToRelease, + _resolution: _resolution + }); + } + + function validateParameters(bytes calldata _data) external pure returns (bool _valid) { + abi.decode(_data, (RequestParameters)); + _valid = true; + } +} diff --git a/solidity/contracts/modules/resolution/ERC20ResolutionModule.sol b/solidity/contracts/modules/resolution/ERC20ResolutionModule.sol index ae1cf75e..eb713bec 100644 --- a/solidity/contracts/modules/resolution/ERC20ResolutionModule.sol +++ b/solidity/contracts/modules/resolution/ERC20ResolutionModule.sol @@ -126,4 +126,9 @@ contract ERC20ResolutionModule is Module, IERC20ResolutionModule { function getVoters(bytes32 _disputeId) external view returns (address[] memory __voters) { __voters = _voters[_disputeId].values(); } + + function validateParameters(bytes calldata _data) external pure returns (bool _valid) { + abi.decode(_data, (RequestParameters)); + _valid = true; + } } diff --git a/solidity/contracts/modules/resolution/PrivateERC20ResolutionModule.sol b/solidity/contracts/modules/resolution/PrivateERC20ResolutionModule.sol index 079326fd..00bb4a26 100644 --- a/solidity/contracts/modules/resolution/PrivateERC20ResolutionModule.sol +++ b/solidity/contracts/modules/resolution/PrivateERC20ResolutionModule.sol @@ -1,143 +1,172 @@ -// // SPDX-License-Identifier: MIT -// pragma solidity ^0.8.19; - -// // solhint-disable-next-line no-unused-import -// import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -// import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -// import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; - -// // solhint-disable-next-line no-unused-import -// import {Module, IModule} from '@defi-wonderland/prophet-core-contracts/solidity/contracts/Module.sol'; -// import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; - -// import {IPrivateERC20ResolutionModule} from '../../../interfaces/modules/resolution/IPrivateERC20ResolutionModule.sol'; - -// contract PrivateERC20ResolutionModule is Module, IPrivateERC20ResolutionModule { -// using SafeERC20 for IERC20; -// using EnumerableSet for EnumerableSet.AddressSet; - -// /// @inheritdoc IPrivateERC20ResolutionModule -// mapping(bytes32 _disputeId => Escalation _escalation) public escalations; -// /** -// * @notice The data of the voters for a given dispute -// */ -// mapping(bytes32 _disputeId => mapping(address _voter => VoterData)) internal _votersData; -// /** -// * @notice The voters addresses for a given dispute -// */ -// mapping(bytes32 _disputeId => EnumerableSet.AddressSet _votersSet) internal _voters; - -// constructor(IOracle _oracle) Module(_oracle) {} - -// /// @inheritdoc IModule -// function moduleName() external pure returns (string memory _moduleName) { -// return 'PrivateERC20ResolutionModule'; -// } - -// /// @inheritdoc IPrivateERC20ResolutionModule -// function decodeRequestData(bytes32 _requestId) public view returns (RequestParameters memory _params) { -// _params = abi.decode(requestData[_requestId], (RequestParameters)); -// } - -// /// @inheritdoc IPrivateERC20ResolutionModule -// function startResolution(bytes32 _disputeId) external onlyOracle { -// escalations[_disputeId].startTime = block.timestamp; -// emit CommittingPhaseStarted(block.timestamp, _disputeId); -// } - -// /// @inheritdoc IPrivateERC20ResolutionModule -// function commitVote(bytes32 _requestId, bytes32 _disputeId, bytes32 _commitment) public { -// IOracle.Dispute memory _dispute = ORACLE.getDispute(_disputeId); -// if (_dispute.createdAt == 0) revert PrivateERC20ResolutionModule_NonExistentDispute(); -// if (_dispute.status != IOracle.DisputeStatus.None) revert PrivateERC20ResolutionModule_AlreadyResolved(); - -// uint256 _startTime = escalations[_disputeId].startTime; -// if (_startTime == 0) revert PrivateERC20ResolutionModule_DisputeNotEscalated(); - -// RequestParameters memory _params = decodeRequestData(_requestId); -// uint256 _committingDeadline = _startTime + _params.committingTimeWindow; -// if (block.timestamp >= _committingDeadline) revert PrivateERC20ResolutionModule_CommittingPhaseOver(); - -// if (_commitment == bytes32('')) revert PrivateERC20ResolutionModule_EmptyCommitment(); -// _votersData[_disputeId][msg.sender] = VoterData({numOfVotes: 0, commitment: _commitment}); - -// emit VoteCommitted(msg.sender, _disputeId, _commitment); -// } - -// /// @inheritdoc IPrivateERC20ResolutionModule -// function revealVote(bytes32 _requestId, bytes32 _disputeId, uint256 _numberOfVotes, bytes32 _salt) public { -// Escalation memory _escalation = escalations[_disputeId]; -// if (_escalation.startTime == 0) revert PrivateERC20ResolutionModule_DisputeNotEscalated(); - -// RequestParameters memory _params = decodeRequestData(_requestId); -// (uint256 _revealStartTime, uint256 _revealEndTime) = ( -// _escalation.startTime + _params.committingTimeWindow, -// _escalation.startTime + _params.committingTimeWindow + _params.revealingTimeWindow -// ); -// if (block.timestamp <= _revealStartTime) revert PrivateERC20ResolutionModule_OnGoingCommittingPhase(); -// if (block.timestamp > _revealEndTime) revert PrivateERC20ResolutionModule_RevealingPhaseOver(); - -// VoterData storage _voterData = _votersData[_disputeId][msg.sender]; - -// if (_voterData.commitment != keccak256(abi.encode(msg.sender, _disputeId, _numberOfVotes, _salt))) { -// revert PrivateERC20ResolutionModule_WrongRevealData(); -// } - -// _voterData.numOfVotes = _numberOfVotes; -// _voterData.commitment = bytes32(''); -// _voters[_disputeId].add(msg.sender); -// escalations[_disputeId].totalVotes += _numberOfVotes; - -// _params.votingToken.safeTransferFrom(msg.sender, address(this), _numberOfVotes); - -// emit VoteRevealed(msg.sender, _disputeId, _numberOfVotes); -// } - -// /// @inheritdoc IPrivateERC20ResolutionModule -// function resolveDispute(bytes32 _disputeId) external onlyOracle { -// IOracle.Dispute memory _dispute = ORACLE.getDispute(_disputeId); -// if (_dispute.createdAt == 0) revert PrivateERC20ResolutionModule_NonExistentDispute(); -// if (_dispute.status != IOracle.DisputeStatus.None) revert PrivateERC20ResolutionModule_AlreadyResolved(); - -// Escalation memory _escalation = escalations[_disputeId]; -// if (_escalation.startTime == 0) revert PrivateERC20ResolutionModule_DisputeNotEscalated(); - -// RequestParameters memory _params = decodeRequestData(_dispute.requestId); - -// if (block.timestamp < _escalation.startTime + _params.committingTimeWindow) { -// revert PrivateERC20ResolutionModule_OnGoingCommittingPhase(); -// } -// if (block.timestamp < _escalation.startTime + _params.committingTimeWindow + _params.revealingTimeWindow) { -// revert PrivateERC20ResolutionModule_OnGoingRevealingPhase(); -// } - -// uint256 _quorumReached = _escalation.totalVotes >= _params.minVotesForQuorum ? 1 : 0; - -// address[] memory __voters = _voters[_disputeId].values(); - -// if (_quorumReached == 1) { -// ORACLE.updateDisputeStatus(_disputeId, IOracle.DisputeStatus.Won); -// emit DisputeResolved(_dispute.requestId, _disputeId, IOracle.DisputeStatus.Won); -// } else { -// ORACLE.updateDisputeStatus(_disputeId, IOracle.DisputeStatus.Lost); -// emit DisputeResolved(_dispute.requestId, _disputeId, IOracle.DisputeStatus.Lost); -// } - -// uint256 _length = __voters.length; -// for (uint256 _i; _i < _length;) { -// _params.votingToken.safeTransfer(__voters[_i], _votersData[_disputeId][__voters[_i]].numOfVotes); -// unchecked { -// ++_i; -// } -// } -// } - -// /// @inheritdoc IPrivateERC20ResolutionModule -// function computeCommitment( -// bytes32 _disputeId, -// uint256 _numberOfVotes, -// bytes32 _salt -// ) external view returns (bytes32 _commitment) { -// _commitment = keccak256(abi.encode(msg.sender, _disputeId, _numberOfVotes, _salt)); -// } -// } +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +// solhint-disable-next-line no-unused-import +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; +import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; + +// solhint-disable-next-line no-unused-import +import {Module, IModule} from '@defi-wonderland/prophet-core-contracts/solidity/contracts/Module.sol'; +import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; + +import {IPrivateERC20ResolutionModule} from '../../../interfaces/modules/resolution/IPrivateERC20ResolutionModule.sol'; + +contract PrivateERC20ResolutionModule is Module, IPrivateERC20ResolutionModule { + using SafeERC20 for IERC20; + using EnumerableSet for EnumerableSet.AddressSet; + + /// @inheritdoc IPrivateERC20ResolutionModule + mapping(bytes32 _disputeId => Escalation _escalation) public escalations; + /** + * @notice The data of the voters for a given dispute + */ + mapping(bytes32 _disputeId => mapping(address _voter => VoterData)) internal _votersData; + /** + * @notice The voters addresses for a given dispute + */ + mapping(bytes32 _disputeId => EnumerableSet.AddressSet _votersSet) internal _voters; + + constructor(IOracle _oracle) Module(_oracle) {} + + /// @inheritdoc IModule + function moduleName() external pure returns (string memory _moduleName) { + return 'PrivateERC20ResolutionModule'; + } + + /// @inheritdoc IPrivateERC20ResolutionModule + function decodeRequestData(bytes calldata _data) public pure returns (RequestParameters memory _params) { + _params = abi.decode(_data, (RequestParameters)); + } + + /// @inheritdoc IPrivateERC20ResolutionModule + function startResolution( + bytes32 _disputeId, + IOracle.Request calldata, + IOracle.Response calldata, + IOracle.Dispute calldata + ) external onlyOracle { + escalations[_disputeId].startTime = block.timestamp; + emit CommittingPhaseStarted(block.timestamp, _disputeId); + } + + /// @inheritdoc IPrivateERC20ResolutionModule + function commitVote(IOracle.Request calldata _request, IOracle.Dispute calldata _dispute, bytes32 _commitment) public { + bytes32 _disputeId = _getId(_dispute); + if (ORACLE.disputeStatus(_disputeId) != IOracle.DisputeStatus.None) { + revert PrivateERC20ResolutionModule_AlreadyResolved(); + } + + uint256 _startTime = escalations[_disputeId].startTime; + if (_startTime == 0) revert PrivateERC20ResolutionModule_DisputeNotEscalated(); + + RequestParameters memory _params = decodeRequestData(_request.resolutionModuleData); + uint256 _committingDeadline = _startTime + _params.committingTimeWindow; + if (block.timestamp >= _committingDeadline) revert PrivateERC20ResolutionModule_CommittingPhaseOver(); + + if (_commitment == bytes32('')) revert PrivateERC20ResolutionModule_EmptyCommitment(); + _votersData[_disputeId][msg.sender] = VoterData({numOfVotes: 0, commitment: _commitment}); + + emit VoteCommitted(msg.sender, _disputeId, _commitment); + } + + /// @inheritdoc IPrivateERC20ResolutionModule + function revealVote( + IOracle.Request calldata _request, + IOracle.Dispute calldata _dispute, + uint256 _numberOfVotes, + bytes32 _salt + ) public { + bytes32 _disputeId = _getId(_dispute); + bytes32 _requestId = _getId(_request); + + // TODO custom error + if (_requestId != _dispute.requestId) revert(); + + Escalation memory _escalation = escalations[_disputeId]; + if (_escalation.startTime == 0) revert PrivateERC20ResolutionModule_DisputeNotEscalated(); + + RequestParameters memory _params = decodeRequestData(_request.resolutionModuleData); + (uint256 _revealStartTime, uint256 _revealEndTime) = ( + _escalation.startTime + _params.committingTimeWindow, + _escalation.startTime + _params.committingTimeWindow + _params.revealingTimeWindow + ); + if (block.timestamp <= _revealStartTime) revert PrivateERC20ResolutionModule_OnGoingCommittingPhase(); + if (block.timestamp > _revealEndTime) revert PrivateERC20ResolutionModule_RevealingPhaseOver(); + + VoterData storage _voterData = _votersData[_disputeId][msg.sender]; + + if (_voterData.commitment != keccak256(abi.encode(msg.sender, _disputeId, _numberOfVotes, _salt))) { + revert PrivateERC20ResolutionModule_WrongRevealData(); + } + + _voterData.numOfVotes = _numberOfVotes; + _voterData.commitment = bytes32(''); + _voters[_disputeId].add(msg.sender); + escalations[_disputeId].totalVotes += _numberOfVotes; + + _params.votingToken.safeTransferFrom(msg.sender, address(this), _numberOfVotes); + + emit VoteRevealed(msg.sender, _disputeId, _numberOfVotes); + } + + /// @inheritdoc IPrivateERC20ResolutionModule + function resolveDispute( + bytes32 _disputeId, + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute + ) external onlyOracle { + // TODO: replace created at + // if (_dispute.createdAt == 0) revert PrivateERC20ResolutionModule_NonExistentDispute(); + if (ORACLE.disputeStatus(_disputeId) != IOracle.DisputeStatus.None) { + revert PrivateERC20ResolutionModule_AlreadyResolved(); + } + + Escalation memory _escalation = escalations[_disputeId]; + if (_escalation.startTime == 0) revert PrivateERC20ResolutionModule_DisputeNotEscalated(); + + RequestParameters memory _params = decodeRequestData(_request.resolutionModuleData); + + if (block.timestamp < _escalation.startTime + _params.committingTimeWindow) { + revert PrivateERC20ResolutionModule_OnGoingCommittingPhase(); + } + if (block.timestamp < _escalation.startTime + _params.committingTimeWindow + _params.revealingTimeWindow) { + revert PrivateERC20ResolutionModule_OnGoingRevealingPhase(); + } + + uint256 _quorumReached = _escalation.totalVotes >= _params.minVotesForQuorum ? 1 : 0; + + address[] memory __voters = _voters[_disputeId].values(); + + if (_quorumReached == 1) { + ORACLE.updateDisputeStatus(_request, _response, _dispute, IOracle.DisputeStatus.Won); + emit DisputeResolved(_dispute.requestId, _disputeId, IOracle.DisputeStatus.Won); + } else { + ORACLE.updateDisputeStatus(_request, _response, _dispute, IOracle.DisputeStatus.Lost); + emit DisputeResolved(_dispute.requestId, _disputeId, IOracle.DisputeStatus.Lost); + } + + uint256 _length = __voters.length; + for (uint256 _i; _i < _length;) { + _params.votingToken.safeTransfer(__voters[_i], _votersData[_disputeId][__voters[_i]].numOfVotes); + unchecked { + ++_i; + } + } + } + + /// @inheritdoc IPrivateERC20ResolutionModule + function computeCommitment( + bytes32 _disputeId, + uint256 _numberOfVotes, + bytes32 _salt + ) external view returns (bytes32 _commitment) { + _commitment = keccak256(abi.encode(msg.sender, _disputeId, _numberOfVotes, _salt)); + } + + function validateParameters(bytes calldata _data) external pure returns (bool _valid) { + abi.decode(_data, (RequestParameters)); + _valid = true; + } +} diff --git a/solidity/contracts/modules/response/BondedResponseModule.sol b/solidity/contracts/modules/response/BondedResponseModule.sol index c52bf5df..4f9efa89 100644 --- a/solidity/contracts/modules/response/BondedResponseModule.sol +++ b/solidity/contracts/modules/response/BondedResponseModule.sol @@ -88,4 +88,9 @@ contract BondedResponseModule is Module, IBondedResponseModule { emit RequestFinalized(_response.requestId, _response, _finalizer); } + + function validateParameters(bytes calldata _data) external pure returns (bool _valid) { + abi.decode(_data, (RequestParameters)); + _valid = true; + } } diff --git a/solidity/interfaces/extensions/IBondEscalationAccounting.sol b/solidity/interfaces/extensions/IBondEscalationAccounting.sol index 6dbec948..ce7728c9 100644 --- a/solidity/interfaces/extensions/IBondEscalationAccounting.sol +++ b/solidity/interfaces/extensions/IBondEscalationAccounting.sol @@ -1,240 +1,240 @@ -// // SPDX-License-Identifier: AGPL-3.0-only -// pragma solidity ^0.8.19; - -// import {IAccountingExtension} from './IAccountingExtension.sol'; -// import {IBondEscalationModule} from '../modules/dispute/IBondEscalationModule.sol'; -// import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; - -// /** -// * @title BondEscalationAccounting -// * @notice Extension allowing users to deposit and pledge funds to be used for bond escalation -// */ -// interface IBondEscalationAccounting is IAccountingExtension { -// /*/////////////////////////////////////////////////////////////// -// EVENTS -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice A user pledged tokens for one of the sides of a dispute -// * -// * @param _pledger The user who pledged the tokens -// * @param _requestId The ID of the bond-escalated request -// * @param _disputeId The ID of the bond-escalated dispute -// * @param _token The address of the token being pledged -// * @param _amount The amount of `_token` pledged by the user -// */ -// event Pledged( -// address indexed _pledger, bytes32 indexed _requestId, bytes32 indexed _disputeId, IERC20 _token, uint256 _amount -// ); - -// /** -// * @notice The pledgers of the winning side of a dispute have been paid -// * -// * @param _requestId The ID of the bond-escalated request -// * @param _disputeId The ID of the bond-escalated dispute -// * @param _winningPledgers The users who got paid for pledging for the winning side -// * @param _token The address of the token being paid out -// * @param _amountPerPledger The amount of `_token` paid to each of the winning pledgers -// */ -// event WinningPledgersPaid( -// bytes32 indexed _requestId, -// bytes32 indexed _disputeId, -// address[] indexed _winningPledgers, -// IERC20 _token, -// uint256 _amountPerPledger -// ); - -// /** -// * @notice A bond escalation has been settled -// * -// * @param _requestId The ID of the bond-escalated request -// * @param _disputeId The ID of the bond-escalated dispute -// * @param _forVotesWon True if the winning side were the for votes -// * @param _token The address of the token being paid out -// * @param _amountPerPledger The amount of `_token` to be paid for each winning pledgers -// * @param _winningPledgersLength The number of winning pledgers -// */ -// event BondEscalationSettled( -// bytes32 _requestId, -// bytes32 _disputeId, -// bool _forVotesWon, -// IERC20 _token, -// uint256 _amountPerPledger, -// uint256 _winningPledgersLength -// ); - -// /** -// * @notice A pledge has been released back to the user -// * -// * @param _requestId The ID of the bond-escalated request -// * @param _disputeId The ID of the bond-escalated dispute -// * @param _pledger The user who is getting their tokens released -// * @param _token The address of the token being released -// * @param _amount The amount of `_token` released -// */ -// event PledgeReleased( -// bytes32 indexed _requestId, bytes32 indexed _disputeId, address indexed _pledger, IERC20 _token, uint256 _amount -// ); - -// /** -// * @notice A user claimed their reward for pledging for the winning side of a dispute -// * -// * @param _requestId The ID of the bond-escalated request -// * @param _disputeId The ID of the bond-escalated dispute -// * @param _pledger The user who claimed their reward -// * @param _token The address of the token being paid out -// * @param _amount The amount of `_token` paid to the pledger -// */ -// event EscalationRewardClaimed( -// bytes32 indexed _requestId, bytes32 indexed _disputeId, address indexed _pledger, IERC20 _token, uint256 _amount -// ); - -// /*/////////////////////////////////////////////////////////////// -// STRUCTS -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice Contains the data of the result of an escalation. Is used by users to claim their pledges -// * @param requestId The ID of the bond-escalated request -// * @param forVotesWon Whether the for votes won the dispute -// * @param token The address of the token being paid out -// * @param amountPerPledger The amount of token paid to each of the winning pledgers -// * @param bondEscalationModule The address of the bond escalation module that was used -// */ -// struct EscalationResult { -// bytes32 requestId; -// bool forVotesWon; -// IERC20 token; -// uint256 amountPerPledger; -// IBondEscalationModule bondEscalationModule; -// } - -// /*/////////////////////////////////////////////////////////////// -// ERRORS -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice Thrown when the user tries to claim their pledge for an escalation that was already claimed -// */ -// error BondEscalationAccounting_AlreadyClaimed(); - -// /** -// * @notice Thrown when the user tries to claim their pledge for an escalation that wasn't finished yet -// */ -// error BondEscalationAccounting_NoEscalationResult(); - -// /** -// * @notice Thrown when the user doesn't have enough funds to pledge -// */ -// error BondEscalationAccounting_InsufficientFunds(); - -// /** -// * @notice Thrown when trying to settle an already settled escalation -// */ -// error BondEscalationAccounting_AlreadySettled(); - -// /*/////////////////////////////////////////////////////////////// -// VARIABLES -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice The amount pledged by the given pledger in the given dispute of the given request -// * -// * @param _disputeId The ID of the bond-escalated dispute -// * @param _token Address of the token being pledged -// * @return _amountPledged The amount of pledged tokens -// */ -// function pledges(bytes32 _disputeId, IERC20 _token) external returns (uint256 _amountPledged); - -// /** -// * @notice The result of the given dispute -// * -// * @param _disputeId The ID of the bond-escalated dispute -// * @return _requestId The ID of the bond-escalated request -// * @return _forVotesWon True if the for votes won the dispute -// * @return _token Address of the token being paid as a reward for winning the bond escalation -// * @return _amountPerPledger Amount of `_token` to be rewarded to each of the winning pledgers -// * @return _bondEscalationModule The address of the bond escalation module that was used -// */ -// function escalationResults(bytes32 _disputeId) -// external -// returns ( -// bytes32 _requestId, -// bool _forVotesWon, -// IERC20 _token, -// uint256 _amountPerPledger, -// IBondEscalationModule _bondEscalationModule -// ); - -// /** -// * @notice True if the given pledger has claimed their reward for the given dispute -// * -// * @param _requestId The ID of the bond-escalated request -// * @param _pledger Address of the pledger -// * @return _claimed True if the pledger has claimed their reward -// */ -// function pledgerClaimed(bytes32 _requestId, address _pledger) external returns (bool _claimed); - -// /*/////////////////////////////////////////////////////////////// -// LOGIC -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice Pledges the given amount of token to the provided dispute id of the provided request id -// * -// * @dev This function must be called by an allowed module -// * -// * @param _pledger Address of the pledger -// * @param _requestId The ID of the bond-escalated request -// * @param _disputeId The ID of the bond-escalated dispute -// * @param _token Address of the token being paid as a reward for winning the bond escalation -// * @param _amount Amount of token to pledge -// */ -// function pledge(address _pledger, bytes32 _requestId, bytes32 _disputeId, IERC20 _token, uint256 _amount) external; - -// /** -// * @notice Updates the accounting of the given dispute to reflect the result of the bond escalation -// * @dev This function must be called by an allowed module -// * -// * @param _requestId The ID of the bond-escalated request -// * @param _disputeId The ID of the bond-escalated dispute -// * @param _forVotesWon True if the for votes won the dispute -// * @param _token Address of the token being paid as a reward for winning the bond escalation -// * @param _amountPerPledger Amount of `_token` to be rewarded to each of the winning pledgers -// * @param _winningPledgersLength Amount of pledges that won the dispute -// */ -// function onSettleBondEscalation( -// bytes32 _requestId, -// bytes32 _disputeId, -// bool _forVotesWon, -// IERC20 _token, -// uint256 _amountPerPledger, -// uint256 _winningPledgersLength -// ) external; - -// /** -// * @notice Releases a given amount of funds to the pledger -// * -// * @dev This function must be called by an allowed module -// * -// * @param _requestId The ID of the bond-escalated request -// * @param _disputeId The ID of the bond-escalated dispute -// * @param _pledger Address of the pledger -// * @param _token Address of the token to be released -// * @param _amount Amount of `_token` to be released to the pledger -// */ -// function releasePledge( -// bytes32 _requestId, -// bytes32 _disputeId, -// address _pledger, -// IERC20 _token, -// uint256 _amount -// ) external; - -// /** -// * @notice Claims the reward for the pledger the given dispute -// * @param _disputeId The ID of the bond-escalated dispute -// * @param _pledger Address of the pledger to claim the rewards -// */ -// function claimEscalationReward(bytes32 _disputeId, address _pledger) external; -// } +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.19; + +import {IAccountingExtension} from './IAccountingExtension.sol'; +import {IBondEscalationModule} from '../modules/dispute/IBondEscalationModule.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; + +/** + * @title BondEscalationAccounting + * @notice Extension allowing users to deposit and pledge funds to be used for bond escalation + */ +interface IBondEscalationAccounting is IAccountingExtension { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + /** + * @notice A user pledged tokens for one of the sides of a dispute + * + * @param _pledger The user who pledged the tokens + * @param _requestId The ID of the bond-escalated request + * @param _disputeId The ID of the bond-escalated dispute + * @param _token The address of the token being pledged + * @param _amount The amount of `_token` pledged by the user + */ + event Pledged( + address indexed _pledger, bytes32 indexed _requestId, bytes32 indexed _disputeId, IERC20 _token, uint256 _amount + ); + + /** + * @notice The pledgers of the winning side of a dispute have been paid + * + * @param _requestId The ID of the bond-escalated request + * @param _disputeId The ID of the bond-escalated dispute + * @param _winningPledgers The users who got paid for pledging for the winning side + * @param _token The address of the token being paid out + * @param _amountPerPledger The amount of `_token` paid to each of the winning pledgers + */ + event WinningPledgersPaid( + bytes32 indexed _requestId, + bytes32 indexed _disputeId, + address[] indexed _winningPledgers, + IERC20 _token, + uint256 _amountPerPledger + ); + + /** + * @notice A bond escalation has been settled + * + * @param _requestId The ID of the bond-escalated request + * @param _disputeId The ID of the bond-escalated dispute + * @param _forVotesWon True if the winning side were the for votes + * @param _token The address of the token being paid out + * @param _amountPerPledger The amount of `_token` to be paid for each winning pledgers + * @param _winningPledgersLength The number of winning pledgers + */ + event BondEscalationSettled( + bytes32 _requestId, + bytes32 _disputeId, + bool _forVotesWon, + IERC20 _token, + uint256 _amountPerPledger, + uint256 _winningPledgersLength + ); + + /** + * @notice A pledge has been released back to the user + * + * @param _requestId The ID of the bond-escalated request + * @param _disputeId The ID of the bond-escalated dispute + * @param _pledger The user who is getting their tokens released + * @param _token The address of the token being released + * @param _amount The amount of `_token` released + */ + event PledgeReleased( + bytes32 indexed _requestId, bytes32 indexed _disputeId, address indexed _pledger, IERC20 _token, uint256 _amount + ); + + /** + * @notice A user claimed their reward for pledging for the winning side of a dispute + * + * @param _requestId The ID of the bond-escalated request + * @param _disputeId The ID of the bond-escalated dispute + * @param _pledger The user who claimed their reward + * @param _token The address of the token being paid out + * @param _amount The amount of `_token` paid to the pledger + */ + event EscalationRewardClaimed( + bytes32 indexed _requestId, bytes32 indexed _disputeId, address indexed _pledger, IERC20 _token, uint256 _amount + ); + + /*/////////////////////////////////////////////////////////////// + STRUCTS + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Contains the data of the result of an escalation. Is used by users to claim their pledges + * @param requestId The ID of the bond-escalated request + * @param forVotesWon Whether the for votes won the dispute + * @param token The address of the token being paid out + * @param amountPerPledger The amount of token paid to each of the winning pledgers + * @param bondEscalationModule The address of the bond escalation module that was used + */ + struct EscalationResult { + bytes32 requestId; + bool forVotesWon; + IERC20 token; + uint256 amountPerPledger; + IBondEscalationModule bondEscalationModule; + } + + /*/////////////////////////////////////////////////////////////// + ERRORS + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Thrown when the user tries to claim their pledge for an escalation that was already claimed + */ + error BondEscalationAccounting_AlreadyClaimed(); + + /** + * @notice Thrown when the user tries to claim their pledge for an escalation that wasn't finished yet + */ + error BondEscalationAccounting_NoEscalationResult(); + + /** + * @notice Thrown when the user doesn't have enough funds to pledge + */ + error BondEscalationAccounting_InsufficientFunds(); + + /** + * @notice Thrown when trying to settle an already settled escalation + */ + error BondEscalationAccounting_AlreadySettled(); + + /*/////////////////////////////////////////////////////////////// + VARIABLES + //////////////////////////////////////////////////////////////*/ + + /** + * @notice The amount pledged by the given pledger in the given dispute of the given request + * + * @param _disputeId The ID of the bond-escalated dispute + * @param _token Address of the token being pledged + * @return _amountPledged The amount of pledged tokens + */ + function pledges(bytes32 _disputeId, IERC20 _token) external returns (uint256 _amountPledged); + + /** + * @notice The result of the given dispute + * + * @param _disputeId The ID of the bond-escalated dispute + * @return _requestId The ID of the bond-escalated request + * @return _forVotesWon True if the for votes won the dispute + * @return _token Address of the token being paid as a reward for winning the bond escalation + * @return _amountPerPledger Amount of `_token` to be rewarded to each of the winning pledgers + * @return _bondEscalationModule The address of the bond escalation module that was used + */ + function escalationResults(bytes32 _disputeId) + external + returns ( + bytes32 _requestId, + bool _forVotesWon, + IERC20 _token, + uint256 _amountPerPledger, + IBondEscalationModule _bondEscalationModule + ); + + /** + * @notice True if the given pledger has claimed their reward for the given dispute + * + * @param _requestId The ID of the bond-escalated request + * @param _pledger Address of the pledger + * @return _claimed True if the pledger has claimed their reward + */ + function pledgerClaimed(bytes32 _requestId, address _pledger) external returns (bool _claimed); + + /*/////////////////////////////////////////////////////////////// + LOGIC + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Pledges the given amount of token to the provided dispute id of the provided request id + * + * @dev This function must be called by an allowed module + * + * @param _pledger Address of the pledger + * @param _requestId The ID of the bond-escalated request + * @param _disputeId The ID of the bond-escalated dispute + * @param _token Address of the token being paid as a reward for winning the bond escalation + * @param _amount Amount of token to pledge + */ + function pledge(address _pledger, bytes32 _requestId, bytes32 _disputeId, IERC20 _token, uint256 _amount) external; + + /** + * @notice Updates the accounting of the given dispute to reflect the result of the bond escalation + * @dev This function must be called by an allowed module + * + * @param _requestId The ID of the bond-escalated request + * @param _disputeId The ID of the bond-escalated dispute + * @param _forVotesWon True if the for votes won the dispute + * @param _token Address of the token being paid as a reward for winning the bond escalation + * @param _amountPerPledger Amount of `_token` to be rewarded to each of the winning pledgers + * @param _winningPledgersLength Amount of pledges that won the dispute + */ + function onSettleBondEscalation( + bytes32 _requestId, + bytes32 _disputeId, + bool _forVotesWon, + IERC20 _token, + uint256 _amountPerPledger, + uint256 _winningPledgersLength + ) external; + + /** + * @notice Releases a given amount of funds to the pledger + * + * @dev This function must be called by an allowed module + * + * @param _requestId The ID of the bond-escalated request + * @param _disputeId The ID of the bond-escalated dispute + * @param _pledger Address of the pledger + * @param _token Address of the token to be released + * @param _amount Amount of `_token` to be released to the pledger + */ + function releasePledge( + bytes32 _requestId, + bytes32 _disputeId, + address _pledger, + IERC20 _token, + uint256 _amount + ) external; + + /** + * @notice Claims the reward for the pledger the given dispute + * @param _disputeId The ID of the bond-escalated dispute + * @param _pledger Address of the pledger to claim the rewards + */ + function claimEscalationReward(bytes32 _disputeId, address _pledger) external; +} diff --git a/solidity/interfaces/modules/dispute/IBondEscalationModule.sol b/solidity/interfaces/modules/dispute/IBondEscalationModule.sol index 4b511fc8..c0242f82 100644 --- a/solidity/interfaces/modules/dispute/IBondEscalationModule.sol +++ b/solidity/interfaces/modules/dispute/IBondEscalationModule.sol @@ -1,275 +1,277 @@ -// // SPDX-License-Identifier: AGPL-3.0-only -// pragma solidity ^0.8.19; +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.19; -// import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -// import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; -// import {IDisputeModule} from -// '@defi-wonderland/prophet-core-contracts/solidity/interfaces/modules/dispute/IDisputeModule.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; +import {IDisputeModule} from + '@defi-wonderland/prophet-core-contracts/solidity/interfaces/modules/dispute/IDisputeModule.sol'; -// import {IBondEscalationAccounting} from '../../extensions/IBondEscalationAccounting.sol'; +import {IBondEscalationAccounting} from '../../extensions/IBondEscalationAccounting.sol'; -// /** -// * @title BondEscalationModule -// * @notice Module allowing users to have the first dispute of a request go through the bond escalation mechanism. -// */ -// interface IBondEscalationModule is IDisputeModule { -// /*/////////////////////////////////////////////////////////////// -// EVENTS -// //////////////////////////////////////////////////////////////*/ +/** + * @title BondEscalationModule + * @notice Module allowing users to have the first dispute of a request go through the bond escalation mechanism. + */ +interface IBondEscalationModule is IDisputeModule { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ -// /** -// * @notice A pledge has been made in favor of a dispute. -// * -// * @param _disputeId The id of the dispute the pledger is pledging in favor of. -// * @param _pledger The address of the pledger. -// * @param _amount The amount pledged. -// */ -// event PledgedForDispute(bytes32 indexed _disputeId, address indexed _pledger, uint256 indexed _amount); + /** + * @notice A pledge has been made in favor of a dispute. + * + * @param _disputeId The id of the dispute the pledger is pledging in favor of. + * @param _pledger The address of the pledger. + * @param _amount The amount pledged. + */ + event PledgedForDispute(bytes32 indexed _disputeId, address indexed _pledger, uint256 indexed _amount); -// /** -// * @notice A pledge has been made against a dispute. -// * -// * @param _disputeId The id of the dispute the pledger is pledging against. -// * @param _pledger The address of the pledger. -// * @param _amount The amount pledged. -// */ -// event PledgedAgainstDispute(bytes32 indexed _disputeId, address indexed _pledger, uint256 indexed _amount); + /** + * @notice A pledge has been made against a dispute. + * + * @param _disputeId The id of the dispute the pledger is pledging against. + * @param _pledger The address of the pledger. + * @param _amount The amount pledged. + */ + event PledgedAgainstDispute(bytes32 indexed _disputeId, address indexed _pledger, uint256 indexed _amount); -// /** -// * @notice The status of the bond escalation mechanism has been updated. -// * -// * @param _requestId The id of the request associated with the bond escalation mechanism. -// * @param _disputeId The id of the dispute going through the bond escalation mechanism. -// * @param _status The new status. -// */ -// event BondEscalationStatusUpdated( -// bytes32 indexed _requestId, bytes32 indexed _disputeId, BondEscalationStatus _status -// ); + /** + * @notice The status of the bond escalation mechanism has been updated. + * + * @param _requestId The id of the request associated with the bond escalation mechanism. + * @param _disputeId The id of the dispute going through the bond escalation mechanism. + * @param _status The new status. + */ + event BondEscalationStatusUpdated( + bytes32 indexed _requestId, bytes32 indexed _disputeId, BondEscalationStatus _status + ); -// /*/////////////////////////////////////////////////////////////// -// ERRORS -// //////////////////////////////////////////////////////////////*/ + /*/////////////////////////////////////////////////////////////// + ERRORS + //////////////////////////////////////////////////////////////*/ -// /** -// * @notice Thrown when trying to escalate a dispute going through the bond escalation module before its deadline. -// */ -// error BondEscalationModule_BondEscalationNotOver(); -// /** -// * @notice Thrown when trying to pledge for a dispute that is not going through the bond escalation mechanism. -// */ -// error BondEscalationModule_InvalidDispute(); -// /** -// * @notice Thrown when the number of escalation pledges of a given dispute has reached its maximum. -// */ -// error BondEscalationModule_MaxNumberOfEscalationsReached(); -// /** -// * @notice Thrown when trying to settle a dispute that went through the bond escalation when it's not active. -// */ -// error BondEscalationModule_BondEscalationCantBeSettled(); -// /** -// * @notice Thrown when trying to settle a bond escalation process that is not tied. -// */ -// error BondEscalationModule_ShouldBeEscalated(); -// /** -// * @notice Thrown when trying to break a tie after the tying buffer has started. -// */ -// error BondEscalationModule_CannotBreakTieDuringTyingBuffer(); -// /** -// * @notice Thrown when the max number of escalations or the bond size is set to 0. -// */ -// error BondEscalationModule_ZeroValue(); -// /** -// * @notice Thrown when trying to pledge after the bond escalation deadline. -// */ -// error BondEscalationModule_BondEscalationOver(); -// /** -// * @notice Thrown when trying to escalate a dispute going through the bond escalation process that is not tied -// * or that is not active. -// */ -// error BondEscalationModule_NotEscalatable(); -// /** -// * @notice Thrown when trying to pledge for a dispute that does not exist -// */ -// error BondEscalationModule_DisputeDoesNotExist(); -// /** -// * @notice Thrown when trying to surpass the number of pledges of the other side by more than 1 in the bond escalation mechanism. -// */ -// error BondEscalationModule_CanOnlySurpassByOnePledge(); -// /** -// * @notice Thrown when trying to dispute a response after the dispute period expired. -// */ -// error BondEscalationModule_DisputeWindowOver(); -// /** -// * @notice Thrown when trying to set up a request with invalid bond size or maximum amount of escalations. -// */ -// error BondEscalationModule_InvalidEscalationParameters(); + /** + * @notice Thrown when trying to escalate a dispute going through the bond escalation module before its deadline. + */ + error BondEscalationModule_BondEscalationNotOver(); + /** + * @notice Thrown when trying to pledge for a dispute that is not going through the bond escalation mechanism. + */ + error BondEscalationModule_InvalidDispute(); + /** + * @notice Thrown when the number of escalation pledges of a given dispute has reached its maximum. + */ + error BondEscalationModule_MaxNumberOfEscalationsReached(); + /** + * @notice Thrown when trying to settle a dispute that went through the bond escalation when it's not active. + */ + error BondEscalationModule_BondEscalationCantBeSettled(); + /** + * @notice Thrown when trying to settle a bond escalation process that is not tied. + */ + error BondEscalationModule_ShouldBeEscalated(); + /** + * @notice Thrown when trying to break a tie after the tying buffer has started. + */ + error BondEscalationModule_CannotBreakTieDuringTyingBuffer(); + /** + * @notice Thrown when the max number of escalations or the bond size is set to 0. + */ + error BondEscalationModule_ZeroValue(); + /** + * @notice Thrown when trying to pledge after the bond escalation deadline. + */ + error BondEscalationModule_BondEscalationOver(); + /** + * @notice Thrown when trying to escalate a dispute going through the bond escalation process that is not tied + * or that is not active. + */ + error BondEscalationModule_NotEscalatable(); + /** + * @notice Thrown when trying to pledge for a dispute that does not exist + */ + error BondEscalationModule_DisputeDoesNotExist(); + /** + * @notice Thrown when trying to surpass the number of pledges of the other side by more than 1 in the bond escalation mechanism. + */ + error BondEscalationModule_CanOnlySurpassByOnePledge(); + /** + * @notice Thrown when trying to dispute a response after the dispute period expired. + */ + error BondEscalationModule_DisputeWindowOver(); + /** + * @notice Thrown when trying to set up a request with invalid bond size or maximum amount of escalations. + */ + error BondEscalationModule_InvalidEscalationParameters(); -// /*/////////////////////////////////////////////////////////////// -// ENUMS -// //////////////////////////////////////////////////////////////*/ + /*/////////////////////////////////////////////////////////////// + ENUMS + //////////////////////////////////////////////////////////////*/ -// /** -// * @notice Enum holding all the possible statuses of a dispute going through the bond escalation mechanism. -// */ -// enum BondEscalationStatus { -// None, // Dispute is not going through the bond escalation mechanism. -// Active, // Dispute is going through the bond escalation mechanism. -// Escalated, // Dispute is going through the bond escalation mechanism and has been escalated. -// DisputerLost, // An escalated dispute has been settled and the disputer lost. -// DisputerWon // An escalated dispute has been settled and the disputer won. -// } + /** + * @notice Enum holding all the possible statuses of a dispute going through the bond escalation mechanism. + */ + enum BondEscalationStatus { + None, // Dispute is not going through the bond escalation mechanism. + Active, // Dispute is going through the bond escalation mechanism. + Escalated, // Dispute is going through the bond escalation mechanism and has been escalated. + DisputerLost, // An escalated dispute has been settled and the disputer lost. + DisputerWon // An escalated dispute has been settled and the disputer won. + } -// /*/////////////////////////////////////////////////////////////// -// STRUCTS -// //////////////////////////////////////////////////////////////*/ + /*/////////////////////////////////////////////////////////////// + STRUCTS + //////////////////////////////////////////////////////////////*/ -// /** -// * @notice Parameters of the request as stored in the module -// * -// * @param _accountingExtension Address of the accounting extension associated with the given request -// * @param _bondToken Address of the token associated with the given request -// * @param _bondSize Amount to bond to dispute or propose an answer for the given request -// * @param _numberOfEscalations Maximum allowed escalations or pledges for each side during the bond escalation process -// * @param _bondEscalationDeadline Timestamp at which bond escalation process finishes when pledges are not tied -// * @param _tyingBuffer Number of seconds to extend the bond escalation process to allow the losing -// * party to tie if at the end of the initial deadline the pledges weren't tied. -// * @param _disputeWindow Number of seconds disputers have to challenge the proposed response since its creation. -// */ -// struct RequestParameters { -// IBondEscalationAccounting accountingExtension; -// IERC20 bondToken; -// uint256 bondSize; -// uint256 maxNumberOfEscalations; -// uint256 bondEscalationDeadline; -// uint256 tyingBuffer; -// uint256 disputeWindow; -// } + /** + * @notice Parameters of the request as stored in the module + * + * @param _accountingExtension Address of the accounting extension associated with the given request + * @param _bondToken Address of the token associated with the given request + * @param _bondSize Amount to bond to dispute or propose an answer for the given request + * @param _numberOfEscalations Maximum allowed escalations or pledges for each side during the bond escalation process + * @param _bondEscalationDeadline Timestamp at which bond escalation process finishes when pledges are not tied + * @param _tyingBuffer Number of seconds to extend the bond escalation process to allow the losing + * party to tie if at the end of the initial deadline the pledges weren't tied. + * @param _disputeWindow Number of seconds disputers have to challenge the proposed response since its creation. + */ + struct RequestParameters { + IBondEscalationAccounting accountingExtension; + IERC20 bondToken; + uint256 bondSize; + uint256 maxNumberOfEscalations; + uint256 bondEscalationDeadline; + uint256 tyingBuffer; + uint256 disputeWindow; + } -// /** -// * @notice Data of a dispute going through the bond escalation. -// * -// * @param disputeId The id of the dispute being bond-escalated. -// * @param status The status of the bond escalation. -// * @param amountOfPledgesForDispute The amount of pledges made in favor of the dispute. -// * @param amountOfPledgesAgainstDispute The amount of pledges made against the dispute. -// */ -// struct BondEscalation { -// bytes32 disputeId; -// BondEscalationStatus status; -// uint256 amountOfPledgesForDispute; -// uint256 amountOfPledgesAgainstDispute; -// } + /** + * @notice Data of a dispute going through the bond escalation. + * + * @param disputeId The id of the dispute being bond-escalated. + * @param status The status of the bond escalation. + * @param amountOfPledgesForDispute The amount of pledges made in favor of the dispute. + * @param amountOfPledgesAgainstDispute The amount of pledges made against the dispute. + */ + struct BondEscalation { + bytes32 disputeId; + BondEscalationStatus status; + uint256 amountOfPledgesForDispute; + uint256 amountOfPledgesAgainstDispute; + } -// /*/////////////////////////////////////////////////////////////// -// VARIABLES -// //////////////////////////////////////////////////////////////*/ + /*/////////////////////////////////////////////////////////////// + VARIABLES + //////////////////////////////////////////////////////////////*/ -// /** -// * @notice Returns the escalation data for a request. -// * @param _requestId The id of the request to get its escalation data. -// * @return _escalation The struct containing the escalation data. -// */ -// function getEscalation(bytes32 _requestId) external view returns (BondEscalation memory _escalation); + /** + * @notice Returns the escalation data for a request. + * @param _requestId The id of the request to get its escalation data. + * @return _escalation The struct containing the escalation data. + */ + function getEscalation(bytes32 _requestId) external view returns (BondEscalation memory _escalation); -// /** -// * @notice Decodes the request data associated with a request id. -// * @param _requestId The id of the request to decode. -// * @return _params The struct containing the parameters for the request -// */ -// function decodeRequestData(bytes32 _requestId) external view returns (RequestParameters memory _params); + /** + * @notice Returns the decoded data for a request + * @param _data The encoded request parameters + * @return _params The struct containing the parameters for the request + */ + function decodeRequestData(bytes calldata _data) external view returns (RequestParameters memory _params); -// /** -// * @notice Returns the amount of pledges that a particular pledger has made for a given dispute. -// * @param _requestId The id of the request to get the pledges for. -// * @param _pledger The address of the pledger to get the pledges for. -// * @return _numPledges The number of pledges made by the pledger for the dispute. -// */ -// function pledgesForDispute(bytes32 _requestId, address _pledger) external view returns (uint256 _numPledges); + /** + * @notice Returns the amount of pledges that a particular pledger has made for a given dispute. + * @param _requestId The id of the request to get the pledges for. + * @param _pledger The address of the pledger to get the pledges for. + * @return _numPledges The number of pledges made by the pledger for the dispute. + */ + function pledgesForDispute(bytes32 _requestId, address _pledger) external view returns (uint256 _numPledges); -// /** -// * @notice Returns the amount of pledges that a particular pledger has made against a given dispute. -// * @param _requestId The id of the request to get the pledges for. -// * @param _pledger The address of the pledger to get the pledges for. -// * @return _numPledges The number of pledges made by the pledger against the dispute. -// */ -// function pledgesAgainstDispute(bytes32 _requestId, address _pledger) external view returns (uint256 _numPledges); + /** + * @notice Returns the amount of pledges that a particular pledger has made against a given dispute. + * @param _requestId The id of the request to get the pledges for. + * @param _pledger The address of the pledger to get the pledges for. + * @return _numPledges The number of pledges made by the pledger against the dispute. + */ + function pledgesAgainstDispute(bytes32 _requestId, address _pledger) external view returns (uint256 _numPledges); -// /*/////////////////////////////////////////////////////////////// -// LOGIC -// //////////////////////////////////////////////////////////////*/ + /*/////////////////////////////////////////////////////////////// + LOGIC + //////////////////////////////////////////////////////////////*/ -// /** -// * @notice Disputes a response -// * -// * @dev If this is the first dispute of the request and the bond escalation window is not over, -// * it will start the bond escalation process. This function must be called through the Oracle. -// * -// * @param _requestId The ID of the request containing the response to dispute. -// * @param _responseId The ID of the request to dispute. -// * @param _disputer The address of the disputer. -// * @param _proposer The address of the proposer of the response. -// * -// * @return _dispute The data of the created dispute. -// */ -// function disputeResponse( -// bytes32 _requestId, -// bytes32 _responseId, -// address _disputer, -// address _proposer -// ) external override returns (IOracle.Dispute memory _dispute); + /** + * @notice Disputes a response + * + * @dev If this is the first dispute of the request and the bond escalation window is not over, + * it will start the bond escalation process. This function must be called through the Oracle. + * + * @param _request The request a dispute has been submitted for + * @param _response The response that is being disputed + * @param _dispute The dispute that is being submitted + */ + function disputeResponse( + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute + ) external; -// /** -// * @notice Updates the status of a given disputeId and pays the proposer and disputer accordingly. If this -// * dispute has gone through the bond escalation mechanism, then it will pay the winning pledgers as well. -// * -// * @param _disputeId The ID of the dispute to update the status for. -// * @param _dispute The full dispute object. -// * -// */ -// function onDisputeStatusChange(bytes32 _disputeId, IOracle.Dispute memory _dispute) external override; + /** + * @notice Updates the status of a given disputeId and pays the proposer and disputer accordingly. If this + * dispute has gone through the bond escalation mechanism, then it will pay the winning pledgers as well. + * + * @param _disputeId The id of the dispute + * @param _request The request that the response was proposed to + * @param _response The response that was disputed + * @param _dispute The dispute being updated + */ + function onDisputeStatusChange( + bytes32 _disputeId, + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute + ) external; -// /** -// * @notice Verifies whether the dispute going through the bond escalation mechanism has reached a tie and -// * updates its escalation status accordingly. -// * -// * @param _disputeId The ID of the dispute to escalate. -// */ -// function disputeEscalated(bytes32 _disputeId) external; + /** + * @notice Bonds funds in favor of a given dispute during the bond escalation process. + * + * @dev This function must be called directly through this contract. + * @dev If the bond escalation is not tied at the end of its deadline, a tying buffer is added + * to avoid scenarios where one of the parties breaks the tie very last second. + * During the tying buffer, the losing party can only tie, and once the escalation is tied + * no further funds can be pledged. + * + * @param _request The request being disputed on. + * @param _dispute The dispute to pledge for. + */ + function pledgeForDispute(IOracle.Request calldata _request, IOracle.Dispute calldata _dispute) external; -// /** -// * @notice Bonds funds in favor of a given dispute during the bond escalation process. -// * -// * @dev This function must be called directly through this contract. -// * @dev If the bond escalation is not tied at the end of its deadline, a tying buffer is added -// * to avoid scenarios where one of the parties breaks the tie very last second. -// * During the tying buffer, the losing party can only tie, and once the escalation is tied -// * no further funds can be pledged. -// * -// * @param _disputeId The ID of the dispute to pledge for. -// */ -// function pledgeForDispute(bytes32 _disputeId) external; + /** + * @notice Pledges funds against a given disputeId during its bond escalation process. + * + * @dev Must be called directly through this contract. Will revert if the disputeId is not going through + * the bond escalation process. + * @dev If the bond escalation is not tied at the end of its deadline, a tying buffer is added + * to avoid scenarios where one of the parties breaks the tie very last second. + * During the tying buffer, the losing party can only tie, and once the escalation is tied + * no further funds can be pledged. + * + * @param _request The request being disputed on. + * @param _dispute The dispute to pledge against. + */ + function pledgeAgainstDispute(IOracle.Request calldata _request, IOracle.Dispute calldata _dispute) external; -// /** -// * @notice Pledges funds against a given disputeId during its bond escalation process. -// * -// * @dev Must be called directly through this contract. Will revert if the disputeId is not going through -// * the bond escalation process. -// * @dev If the bond escalation is not tied at the end of its deadline, a tying buffer is added -// * to avoid scenarios where one of the parties breaks the tie very last second. -// * During the tying buffer, the losing party can only tie, and once the escalation is tied -// * no further funds can be pledged. -// * -// * @param _disputeId ID of the dispute id to pledge against. -// */ -// function pledgeAgainstDispute(bytes32 _disputeId) external; - -// /** -// * @notice Settles the bond escalation process of a given requestId. -// * -// * @dev Must be called directly through this contract. -// * @dev Can only be called if after the deadline + tyingBuffer window is over, the pledges weren't tied -// * -// * @param _requestId requestId of the request to settle the bond escalation process for. -// */ -// function settleBondEscalation(bytes32 _requestId) external; -// } + /** + * @notice Settles the bond escalation process of a given requestId. + * + * @dev Must be called directly through this contract. + * @dev Can only be called if after the deadline + tyingBuffer window is over, the pledges weren't tied + * + * @param _request The request to settle the bond escalation process for. + * @param _response The response to settle the bond escalation process for. + * @param _dispute The dispute to settle the bond escalation process for. + */ + function settleBondEscalation( + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute + ) external; +} diff --git a/solidity/interfaces/modules/resolution/IBondEscalationResolutionModule.sol b/solidity/interfaces/modules/resolution/IBondEscalationResolutionModule.sol index 764f713a..24b5cd8d 100644 --- a/solidity/interfaces/modules/resolution/IBondEscalationResolutionModule.sol +++ b/solidity/interfaces/modules/resolution/IBondEscalationResolutionModule.sol @@ -1,300 +1,318 @@ -// // SPDX-License-Identifier: MIT -// pragma solidity ^0.8.19; - -// import {IResolutionModule} from -// '@defi-wonderland/prophet-core-contracts/solidity/interfaces/modules/resolution/IResolutionModule.sol'; -// import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -// import {IBondEscalationAccounting} from '../../extensions/IBondEscalationAccounting.sol'; - -// /** -// * @title BondEscalationResolutionModule -// * @notice Handles the bond escalation resolution process for disputes, in which sides take turns pledging for or against a dispute by bonding tokens. -// * @dev This is a resolution module, similar in its mechanics to the BondEscalationModule. -// */ -// interface IBondEscalationResolutionModule is IResolutionModule { -// /*/////////////////////////////////////////////////////////////// -// EVENTS -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice Emitted when a dispute is escalated. -// * -// * @param _disputeId The ID of the dispute that was escalated. -// * @param _requestId The ID of the request associated with the dispute. -// */ -// event DisputeEscalated(bytes32 indexed _disputeId, bytes32 indexed _requestId); - -// /** -// * @notice Emitted when a user pledges in favor of a dispute. -// * -// * @param _pledger The address of the user that pledged. -// * @param _requestId The ID of the request associated with the dispute. -// * @param _disputeId The ID of the dispute the user pledged in favor of. -// * @param _pledgedAmount The amount of tokens the user pledged. -// */ -// event PledgedForDispute( -// address indexed _pledger, bytes32 indexed _requestId, bytes32 indexed _disputeId, uint256 _pledgedAmount -// ); - -// /** -// * @notice Emitted when a user pledges against a dispute. -// * -// * @param _pledger The address of the user that pledged. -// * @param _requestId The ID of the request associated with the dispute. -// * @param _disputeId The ID of the dispute the user pledged against. -// * @param _pledgedAmount The amount of tokens the user pledged. -// */ -// event PledgedAgainstDispute( -// address indexed _pledger, bytes32 indexed _requestId, bytes32 indexed _disputeId, uint256 _pledgedAmount -// ); - -// /** -// * @notice Emitted when a user claims his pledges after a successful dispute. -// * -// * @param _requestId The ID of the request associated with the dispute. -// * @param _disputeId The ID of the dispute the user supported. -// * @param _pledger The address of the user that claimed his pledges. -// * @param _token The token the user claimed his pledges in. -// * @param _pledgeReleased The amount of tokens the user claimed. -// * @param _resolution The outcome of the resolution -// */ -// event PledgeClaimed( -// bytes32 indexed _requestId, -// bytes32 indexed _disputeId, -// address indexed _pledger, -// IERC20 _token, -// uint256 _pledgeReleased, -// Resolution _resolution -// ); - -// /*/////////////////////////////////////////////////////////////// -// ERRORS -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice Thrown when the user tries to resolve a dispute that has already been resolved. -// */ -// error BondEscalationResolutionModule_AlreadyResolved(); - -// /** -// * @notice Thrown when trying to claim a pledge for a dispute that has not been resolved yet. -// */ -// error BondEscalationResolutionModule_NotResolved(); - -// /** -// * @notice Thrown when the user tries to pledge for or resolve a non-existent dispute. -// */ -// error BondEscalationResolutionModule_NotEscalated(); - -// /** -// * @notice Thrown when trying to pledge after the pledging phase is over. -// */ -// error BondEscalationResolutionModule_PledgingPhaseOver(); - -// /** -// * @notice Thrown when trying to resolve a dispute before the pledging phase is over. -// */ -// error BondEscalationResolutionModule_PledgingPhaseNotOver(); - -// /** -// * @notice Thrown when trying to pledge after the inequality timer has passed. -// */ -// error BondEscalationResolutionModule_MustBeResolved(); - -// /** -// * @notice Thrown when trying to pledge for a dispute during the opposing side's pledging turn. -// */ -// error BondEscalationResolutionModule_AgainstTurnToEqualize(); - -// /** -// * @notice Thrown when trying to pledge against a dispute during the supporting side's pledging turn. -// */ -// error BondEscalationResolutionModule_ForTurnToEqualize(); - -// /*/////////////////////////////////////////////////////////////// -// ENUMS -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice The possible inequality statuses of a dispute -// * -// * @param Equalized The percentage difference between the for and against pledges is smaller than the set percentageDiff. This state allows any of the two -// * parties to pledge. When the percentageDiff is surpassed, the status changes to AgainstTurnToEqualize or ForTurnToEqualize depending on -// * which side surpassed the percentageDiff. When this happens, only the respective side can pledge. -// * @param ForTurnToEqualize If the for pledges surpassed the percentageDiff, a timer is started and the against party has a set amount of time to -// * reduce the percentageDiff so that the status is Equalized again, or to surpass the percentageDiff so that the status changes to ForTurnToEqualize. -// * Until this happens, only the people pledging against a dispute can pledge. -// * If the timer runs out without the status changing, then the dispute is considered finalized and the for party wins. -// * @param AgainstTurnToEqualize The same as AgainstTurnToEqualize but for the parties that wish to pledge in favor a given dispute. -// */ -// enum InequalityStatus { -// Equalized, -// ForTurnToEqualize, -// AgainstTurnToEqualize -// } - -// /** -// * @notice The possible resolutions of a dispute -// * -// * @param Unresolved The dispute has not been resolved yet. -// * @param DisputerWon The disputer won the dispute. -// * @param DisputerLost The disputer lost the dispute. -// * @param NoResolution The dispute was not resolved. -// */ -// enum Resolution { -// Unresolved, -// DisputerWon, -// DisputerLost, -// NoResolution -// } - -// /*/////////////////////////////////////////////////////////////// -// STRUCTS -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice Parameters of the request as stored in the module -// * -// * @param _accountingExtension The accounting extension to use for this request. -// * @param _token The token to use for this request. -// * @param _percentageDiff The percentage difference between the for and against pledges that triggers the change in voting turns. This value should be between 1 and 100. -// * @param _pledgeThreshold The amount of pledges that must be reached to achieve quorum and start triggering voting turns. -// * @param _timeUntilDeadline The amount of time in seconds past the start time of the escalation until the resolution process is over. -// * @param _timeToBreakInequality The amount of time the pledgers have to break the pledge inequality once the percentage difference has been surpassed. -// */ -// struct RequestParameters { -// IBondEscalationAccounting accountingExtension; -// IERC20 bondToken; -// uint256 percentageDiff; -// uint256 pledgeThreshold; -// uint256 timeUntilDeadline; -// uint256 timeToBreakInequality; -// } - -// /** -// * @notice The inequality status and its last update time of a given dispute. -// * -// * @param _inequalityStatus The current status of the inequality. -// * @param _time The time at which the inequality was last updated. -// */ -// struct InequalityData { -// InequalityStatus inequalityStatus; -// uint256 time; -// } - -// /** -// * @notice The bond escalation progress and the balance of pledges for and against a given dispute. -// * -// * @param _resolution The current resolution of the dispute. -// * @param _startTime The time at which the dispute was escalated. -// * @param _pledgesFor The amount of pledges in favor of the dispute. -// * @param _pledgesAgainst The amount of pledges against the dispute. -// */ -// struct Escalation { -// Resolution resolution; -// uint128 startTime; -// uint256 pledgesFor; -// uint256 pledgesAgainst; -// } - -// /*/////////////////////////////////////////////////////////////// -// VARIABLES -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice Base to avoid over/underflow -// * -// * @return _base The base to avoid over/underflow -// */ -// function BASE() external view returns (uint256 _base); - -// /** -// * @notice Returns the bond escalation progress and the balance of pledges for and against a given dispute. -// * -// * @param _disputeId The ID of the dispute. -// * -// * @return _resolution The current resolution of the dispute. -// * @return _startTime The time at which the dispute was escalated. -// * @return _pledgesFor The amount of pledges in favor of the dispute. -// * @return _pledgesAgainst The amount of pledges against the dispute. -// */ -// function escalations(bytes32 _disputeId) -// external -// view -// returns (Resolution _resolution, uint128 _startTime, uint256 _pledgesFor, uint256 _pledgesAgainst); - -// /** -// * @notice Returns the inequality status and its last update time of a given dispute. -// * -// * @param _disputeId The ID of the dispute. -// * -// * @return _inequalityStatus The current status of the inequality. -// * @return _time The time at which the inequality was last updated. -// */ -// function inequalityData(bytes32 _disputeId) external view returns (InequalityStatus _inequalityStatus, uint256 _time); - -// /** -// * @notice Returns the amount pledged by a user for a given dispute. -// * -// * @param _disputeId The ID of the dispute. -// * @param _pledger The address of the user. -// * -// * @return _pledgesForDispute The amount pledged by a user for a given dispute. -// */ -// function pledgesForDispute(bytes32 _disputeId, address _pledger) external view returns (uint256 _pledgesForDispute); - -// /** -// * @notice Returns the amount pledged by a user against a given dispute. -// * -// * @param _disputeId The ID of the dispute. -// * @param _pledger The address of the user. -// * -// * @return _pledgesAgainstDispute The amount pledged by a user against a given dispute. -// */ -// function pledgesAgainstDispute( -// bytes32 _disputeId, -// address _pledger -// ) external view returns (uint256 _pledgesAgainstDispute); - -// /** -// * @notice Returns the decoded data for a request -// * @param _requestId The ID of the request -// * @return _params The struct containing the parameters for the request -// */ -// function decodeRequestData(bytes32 _requestId) external view returns (RequestParameters memory _params); - -// /*/////////////////////////////////////////////////////////////// -// LOGIC -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice Allows users to pledge in favor of a given dispute. This means the user believes the proposed answer is -// * incorrect and therefore wants the disputer to win his dispute. -// * -// * @param _requestId The ID of the request associated with the dispute. -// * @param _disputeId The ID of the dispute to pledge in favor of. -// * @param _pledgeAmount The amount of pledges to pledge. -// */ -// function pledgeForDispute(bytes32 _requestId, bytes32 _disputeId, uint256 _pledgeAmount) external; - -// /** -// * @notice Allows users to pledge against a given dispute. This means the user believes the proposed answer is -// * correct and therefore wants the disputer to lose his dispute. -// * -// * @param _requestId The ID of the request associated with the dispute. -// * @param _disputeId The ID of the dispute to pledge against of. -// * @param _pledgeAmount The amount of pledges to pledge. -// */ -// function pledgeAgainstDispute(bytes32 _requestId, bytes32 _disputeId, uint256 _pledgeAmount) external; - -// /** -// * @notice Allows user to claim his corresponding pledges after a dispute is resolved. -// * -// * @dev Winning pledgers will claim their pledges along with their reward. In case of no resolution, users can -// * claim their pledges back. Losing pledgers will go to the rewards of the winning pledgers. -// * -// * @param _requestId The ID of the request associated with dispute. -// * @param _disputeId The ID of the dispute the user wants to claim pledges from. -// */ -// function claimPledge(bytes32 _requestId, bytes32 _disputeId) external; -// } +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; +import {IResolutionModule} from + '@defi-wonderland/prophet-core-contracts/solidity/interfaces/modules/resolution/IResolutionModule.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {IBondEscalationAccounting} from '../../extensions/IBondEscalationAccounting.sol'; + +/** + * @title BondEscalationResolutionModule + * @notice Handles the bond escalation resolution process for disputes, in which sides take turns pledging for or against a dispute by bonding tokens. + * @dev This is a resolution module, similar in its mechanics to the BondEscalationModule. + */ +interface IBondEscalationResolutionModule is IResolutionModule { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Emitted when a dispute is escalated. + * + * @param _disputeId The ID of the dispute that was escalated. + * @param _requestId The ID of the request associated with the dispute. + */ + event DisputeEscalated(bytes32 indexed _disputeId, bytes32 indexed _requestId); + + /** + * @notice Emitted when a user pledges in favor of a dispute. + * + * @param _pledger The address of the user that pledged. + * @param _requestId The ID of the request associated with the dispute. + * @param _disputeId The ID of the dispute the user pledged in favor of. + * @param _pledgedAmount The amount of tokens the user pledged. + */ + event PledgedForDispute( + address indexed _pledger, bytes32 indexed _requestId, bytes32 indexed _disputeId, uint256 _pledgedAmount + ); + + /** + * @notice Emitted when a user pledges against a dispute. + * + * @param _pledger The address of the user that pledged. + * @param _requestId The ID of the request associated with the dispute. + * @param _disputeId The ID of the dispute the user pledged against. + * @param _pledgedAmount The amount of tokens the user pledged. + */ + event PledgedAgainstDispute( + address indexed _pledger, bytes32 indexed _requestId, bytes32 indexed _disputeId, uint256 _pledgedAmount + ); + + /** + * @notice Emitted when a user claims his pledges after a successful dispute. + * + * @param _requestId The ID of the request associated with the dispute. + * @param _disputeId The ID of the dispute the user supported. + * @param _pledger The address of the user that claimed his pledges. + * @param _token The token the user claimed his pledges in. + * @param _pledgeReleased The amount of tokens the user claimed. + * @param _resolution The outcome of the resolution + */ + event PledgeClaimed( + bytes32 indexed _requestId, + bytes32 indexed _disputeId, + address indexed _pledger, + IERC20 _token, + uint256 _pledgeReleased, + Resolution _resolution + ); + + /*/////////////////////////////////////////////////////////////// + ERRORS + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Thrown when the user tries to resolve a dispute that has already been resolved. + */ + error BondEscalationResolutionModule_AlreadyResolved(); + + /** + * @notice Thrown when trying to claim a pledge for a dispute that has not been resolved yet. + */ + error BondEscalationResolutionModule_NotResolved(); + + /** + * @notice Thrown when the user tries to pledge for or resolve a non-existent dispute. + */ + error BondEscalationResolutionModule_NotEscalated(); + + /** + * @notice Thrown when trying to pledge after the pledging phase is over. + */ + error BondEscalationResolutionModule_PledgingPhaseOver(); + + /** + * @notice Thrown when trying to resolve a dispute before the pledging phase is over. + */ + error BondEscalationResolutionModule_PledgingPhaseNotOver(); + + /** + * @notice Thrown when trying to pledge after the inequality timer has passed. + */ + error BondEscalationResolutionModule_MustBeResolved(); + + /** + * @notice Thrown when trying to pledge for a dispute during the opposing side's pledging turn. + */ + error BondEscalationResolutionModule_AgainstTurnToEqualize(); + + /** + * @notice Thrown when trying to pledge against a dispute during the supporting side's pledging turn. + */ + error BondEscalationResolutionModule_ForTurnToEqualize(); + + /*/////////////////////////////////////////////////////////////// + ENUMS + //////////////////////////////////////////////////////////////*/ + + /** + * @notice The possible inequality statuses of a dispute + * + * @param Equalized The percentage difference between the for and against pledges is smaller than the set percentageDiff. This state allows any of the two + * parties to pledge. When the percentageDiff is surpassed, the status changes to AgainstTurnToEqualize or ForTurnToEqualize depending on + * which side surpassed the percentageDiff. When this happens, only the respective side can pledge. + * @param ForTurnToEqualize If the for pledges surpassed the percentageDiff, a timer is started and the against party has a set amount of time to + * reduce the percentageDiff so that the status is Equalized again, or to surpass the percentageDiff so that the status changes to ForTurnToEqualize. + * Until this happens, only the people pledging against a dispute can pledge. + * If the timer runs out without the status changing, then the dispute is considered finalized and the for party wins. + * @param AgainstTurnToEqualize The same as AgainstTurnToEqualize but for the parties that wish to pledge in favor a given dispute. + */ + enum InequalityStatus { + Equalized, + ForTurnToEqualize, + AgainstTurnToEqualize + } + + /** + * @notice The possible resolutions of a dispute + * + * @param Unresolved The dispute has not been resolved yet. + * @param DisputerWon The disputer won the dispute. + * @param DisputerLost The disputer lost the dispute. + * @param NoResolution The dispute was not resolved. + */ + enum Resolution { + Unresolved, + DisputerWon, + DisputerLost, + NoResolution + } + + /*/////////////////////////////////////////////////////////////// + STRUCTS + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Parameters of the request as stored in the module + * + * @param _accountingExtension The accounting extension to use for this request. + * @param _token The token to use for this request. + * @param _percentageDiff The percentage difference between the for and against pledges that triggers the change in voting turns. This value should be between 1 and 100. + * @param _pledgeThreshold The amount of pledges that must be reached to achieve quorum and start triggering voting turns. + * @param _timeUntilDeadline The amount of time in seconds past the start time of the escalation until the resolution process is over. + * @param _timeToBreakInequality The amount of time the pledgers have to break the pledge inequality once the percentage difference has been surpassed. + */ + struct RequestParameters { + IBondEscalationAccounting accountingExtension; + IERC20 bondToken; + uint256 percentageDiff; + uint256 pledgeThreshold; + uint256 timeUntilDeadline; + uint256 timeToBreakInequality; + } + + /** + * @notice The inequality status and its last update time of a given dispute. + * + * @param _inequalityStatus The current status of the inequality. + * @param _time The time at which the inequality was last updated. + */ + struct InequalityData { + InequalityStatus inequalityStatus; + uint256 time; + } + + /** + * @notice The bond escalation progress and the balance of pledges for and against a given dispute. + * + * @param _resolution The current resolution of the dispute. + * @param _startTime The time at which the dispute was escalated. + * @param _pledgesFor The amount of pledges in favor of the dispute. + * @param _pledgesAgainst The amount of pledges against the dispute. + */ + struct Escalation { + Resolution resolution; + uint128 startTime; + uint256 pledgesFor; + uint256 pledgesAgainst; + } + + /*/////////////////////////////////////////////////////////////// + VARIABLES + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Base to avoid over/underflow + * + * @return _base The base to avoid over/underflow + */ + function BASE() external view returns (uint256 _base); + + /** + * @notice Returns the bond escalation progress and the balance of pledges for and against a given dispute. + * + * @param _disputeId The ID of the dispute. + * + * @return _resolution The current resolution of the dispute. + * @return _startTime The time at which the dispute was escalated. + * @return _pledgesFor The amount of pledges in favor of the dispute. + * @return _pledgesAgainst The amount of pledges against the dispute. + */ + function escalations(bytes32 _disputeId) + external + view + returns (Resolution _resolution, uint128 _startTime, uint256 _pledgesFor, uint256 _pledgesAgainst); + + /** + * @notice Returns the inequality status and its last update time of a given dispute. + * + * @param _disputeId The ID of the dispute. + * + * @return _inequalityStatus The current status of the inequality. + * @return _time The time at which the inequality was last updated. + */ + function inequalityData(bytes32 _disputeId) external view returns (InequalityStatus _inequalityStatus, uint256 _time); + + /** + * @notice Returns the amount pledged by a user for a given dispute. + * + * @param _disputeId The ID of the dispute. + * @param _pledger The address of the user. + * + * @return _pledgesForDispute The amount pledged by a user for a given dispute. + */ + function pledgesForDispute(bytes32 _disputeId, address _pledger) external view returns (uint256 _pledgesForDispute); + + /** + * @notice Returns the amount pledged by a user against a given dispute. + * + * @param _disputeId The ID of the dispute. + * @param _pledger The address of the user. + * + * @return _pledgesAgainstDispute The amount pledged by a user against a given dispute. + */ + function pledgesAgainstDispute( + bytes32 _disputeId, + address _pledger + ) external view returns (uint256 _pledgesAgainstDispute); + + /** + * @notice Returns the decoded data for a request + * @param _data The encoded request parameters + * @return _params The struct containing the parameters for the request + */ + function decodeRequestData(bytes calldata _data) external view returns (RequestParameters memory _params); + + /*/////////////////////////////////////////////////////////////// + LOGIC + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Allows users to pledge in favor of a given dispute. This means the user believes the proposed answer is + * incorrect and therefore wants the disputer to win his dispute. + * + * @param _request The request associated with the dispute. + * @param _response The response being disputed. + * @param _dispute The dispute to pledge in favor of. + * @param _disputeId The ID of the dispute to pledge in favor of. + * @param _pledgeAmount The amount of pledges to pledge. + */ + function pledgeForDispute( + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute, + bytes32 _disputeId, + uint256 _pledgeAmount + ) external; + + /** + * @notice Allows users to pledge against a given dispute. This means the user believes the proposed answer is + * correct and therefore wants the disputer to lose his dispute. + * + * @param _request The request associated with the dispute. + * @param _response The response being disputed. + * @param _dispute The dispute to pledge against of. + * @param _disputeId The ID of the dispute to pledge in favor of. + * @param _pledgeAmount The amount of pledges to pledge. + */ + function pledgeAgainstDispute( + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute, + bytes32 _disputeId, + uint256 _pledgeAmount + ) external; + + /** + * @notice Allows user to claim his corresponding pledges after a dispute is resolved. + * + * @dev Winning pledgers will claim their pledges along with their reward. In case of no resolution, users can + * claim their pledges back. Losing pledgers will go to the rewards of the winning pledgers. + * + * @param _request The request associated with the dispute. + * @param _requestId The ID of the request associated with dispute. + * @param _disputeId The ID of the dispute the user wants to claim pledges from. + */ + function claimPledge(IOracle.Request calldata _request, bytes32 _requestId, bytes32 _disputeId) external; +} diff --git a/solidity/interfaces/modules/resolution/IPrivateERC20ResolutionModule.sol b/solidity/interfaces/modules/resolution/IPrivateERC20ResolutionModule.sol index 66b1249b..3a5c9672 100644 --- a/solidity/interfaces/modules/resolution/IPrivateERC20ResolutionModule.sol +++ b/solidity/interfaces/modules/resolution/IPrivateERC20ResolutionModule.sol @@ -1,200 +1,223 @@ -// // SPDX-License-Identifier: MIT -// pragma solidity ^0.8.19; - -// import {IResolutionModule} from -// '@defi-wonderland/prophet-core-contracts/solidity/interfaces/modules/resolution/IResolutionModule.sol'; -// import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -// import {IAccountingExtension} from '../../extensions/IAccountingExtension.sol'; - -// /* -// * @title PrivateERC20ResolutionModule -// * @notice Module allowing users to vote on a dispute using ERC20 -// * tokens through a commit/reveal pattern. -// */ -// interface IPrivateERC20ResolutionModule is IResolutionModule { -// /*/////////////////////////////////////////////////////////////// -// EVENTS -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice A commitment has been provided by a voter -// * @param _voter The user who provided a commitment of a vote -// * @param _disputeId The id of the dispute being voted on -// * @param _commitment The commitment provided by the voter -// */ -// event VoteCommitted(address _voter, bytes32 _disputeId, bytes32 _commitment); - -// /** -// * @notice A vote has been revealed by a voter providing -// * the salt used to compute the commitment -// * @param _voter The user who revealed his vote -// * @param _disputeId The id of the dispute being voted on -// * @param _numberOfVotes The number of votes cast -// */ -// event VoteRevealed(address _voter, bytes32 _disputeId, uint256 _numberOfVotes); - -// /** -// * @notice The phase of committing votes has started -// * @param _startTime The timestamp at which the phase started -// * @param _disputeId The id of the dispute being voted on -// */ -// event CommittingPhaseStarted(uint256 _startTime, bytes32 _disputeId); - -// /*/////////////////////////////////////////////////////////////// -// ERRORS -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice Thrown when the dispute has not been escalated -// */ -// error PrivateERC20ResolutionModule_DisputeNotEscalated(); - -// /** -// * @notice Thrown when trying to commit a vote after the committing deadline -// */ -// error PrivateERC20ResolutionModule_CommittingPhaseOver(); - -// /** -// * @notice Thrown when trying to reveal a vote after the revealing deadline -// */ -// error PrivateERC20ResolutionModule_RevealingPhaseOver(); - -// /** -// * @notice Thrown when trying to resolve a dispute during the committing phase -// */ -// error PrivateERC20ResolutionModule_OnGoingCommittingPhase(); - -// /** -// * @notice Thrown when trying to resolve a dispute during the revealing phase -// */ -// error PrivateERC20ResolutionModule_OnGoingRevealingPhase(); - -// /** -// * @notice Thrown when trying to resolve a dispute that does not exist -// */ -// error PrivateERC20ResolutionModule_NonExistentDispute(); - -// /** -// * @notice Thrown when trying to commit an empty commitment -// */ -// error PrivateERC20ResolutionModule_EmptyCommitment(); - -// /** -// * @notice Thrown when trying to reveal a vote with data that does not match the stored commitment -// */ -// error PrivateERC20ResolutionModule_WrongRevealData(); - -// /** -// * @notice Thrown when trying to resolve a dispute that is already resolved -// */ -// error PrivateERC20ResolutionModule_AlreadyResolved(); - -// /*/////////////////////////////////////////////////////////////// -// STRUCTS -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice Parameters of the request as stored in the module -// * @param accountingExtension The accounting extension used to bond and release tokens -// * @param token The token used to vote -// * @param minVotesForQuorum The minimum amount of votes to win the dispute -// * @param committingTimeWindow The amount of time to commit votes from the escalation of the dispute -// * @param revealingTimeWindow The amount of time to reveal votes from the committing phase -// */ -// struct RequestParameters { -// IAccountingExtension accountingExtension; -// IERC20 votingToken; -// uint256 minVotesForQuorum; -// uint256 committingTimeWindow; -// uint256 revealingTimeWindow; -// } - -// /** -// * @notice Escalation data for a dispute -// * @param startTime The timestamp at which the dispute was escalated -// * @param totalVotes The total amount of votes cast for the dispute -// */ - -// struct Escalation { -// uint256 startTime; -// uint256 totalVotes; -// } - -// /** -// * @notice Voting data for each voter -// * @param numOfVotes The amount of votes cast for the dispute -// * @param commitment The commitment provided by the voter -// */ -// struct VoterData { -// uint256 numOfVotes; -// bytes32 commitment; -// } - -// /*/////////////////////////////////////////////////////////////// -// VARIABLES -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice Returns the escalation data for a dispute -// * @param _disputeId The id of the dispute -// * @return _startTime The timestamp at which the dispute was escalated -// * @return _totalVotes The total amount of votes cast for the dispute -// */ -// function escalations(bytes32 _disputeId) external view returns (uint256 _startTime, uint256 _totalVotes); - -// /*/////////////////////////////////////////////////////////////// -// LOGIC -// //////////////////////////////////////////////////////////////*/ - -// /** -// * @notice Starts the committing phase for a dispute -// * @dev Only callable by the Oracle -// * @param _disputeId The id of the dispute to start resolution of -// */ -// function startResolution(bytes32 _disputeId) external; - -// /** -// * @notice Stores a commitment for a vote cast by a voter -// * @dev Committing multiple times and overwriting a previous commitment is allowed -// * @param _requestId The id of the request being disputed -// * @param _disputeId The id of the dispute being voted on -// * @param _commitment The commitment computed from the provided data and the user's address -// */ -// function commitVote(bytes32 _requestId, bytes32 _disputeId, bytes32 _commitment) external; - -// /** -// * @notice Reveals a vote cast by a voter -// * @dev The user must have previously approved the module to transfer the tokens -// * @param _requestId The id of the request being disputed -// * @param _disputeId The id of the dispute being voted on -// * @param _numberOfVotes The amount of votes being revealed -// * @param _salt The salt used to compute the commitment -// */ -// function revealVote(bytes32 _requestId, bytes32 _disputeId, uint256 _numberOfVotes, bytes32 _salt) external; - -// /** -// * @notice Resolves a dispute by tallying the votes and executing the winning outcome -// * @dev Only callable by the Oracle -// * @param _disputeId The id of the dispute being resolved -// */ -// function resolveDispute(bytes32 _disputeId) external; - -// /** -// * @notice Returns the decoded data for a request -// * @param _requestId The ID of the request -// * @return _params The struct containing the parameters for the request -// */ -// function decodeRequestData(bytes32 _requestId) external view returns (RequestParameters memory _params); - -// /** -// * @notice Computes a valid commitment for the revealing phase -// * @param _disputeId The id of the dispute being voted on -// * @param _numberOfVotes The amount of votes being cast -// * @return _commitment The commitment computed from the provided data and the user's address -// */ -// function computeCommitment( -// bytes32 _disputeId, -// uint256 _numberOfVotes, -// bytes32 _salt -// ) external view returns (bytes32 _commitment); -// } +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; +import {IResolutionModule} from + '@defi-wonderland/prophet-core-contracts/solidity/interfaces/modules/resolution/IResolutionModule.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {IAccountingExtension} from '../../extensions/IAccountingExtension.sol'; + +/* + * @title PrivateERC20ResolutionModule + * @notice Module allowing users to vote on a dispute using ERC20 + * tokens through a commit/reveal pattern. + */ +interface IPrivateERC20ResolutionModule is IResolutionModule { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + /** + * @notice A commitment has been provided by a voter + * @param _voter The user who provided a commitment of a vote + * @param _disputeId The id of the dispute being voted on + * @param _commitment The commitment provided by the voter + */ + event VoteCommitted(address _voter, bytes32 _disputeId, bytes32 _commitment); + + /** + * @notice A vote has been revealed by a voter providing + * the salt used to compute the commitment + * @param _voter The user who revealed his vote + * @param _disputeId The id of the dispute being voted on + * @param _numberOfVotes The number of votes cast + */ + event VoteRevealed(address _voter, bytes32 _disputeId, uint256 _numberOfVotes); + + /** + * @notice The phase of committing votes has started + * @param _startTime The timestamp at which the phase started + * @param _disputeId The id of the dispute being voted on + */ + event CommittingPhaseStarted(uint256 _startTime, bytes32 _disputeId); + + /*/////////////////////////////////////////////////////////////// + ERRORS + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Thrown when the dispute has not been escalated + */ + error PrivateERC20ResolutionModule_DisputeNotEscalated(); + + /** + * @notice Thrown when trying to commit a vote after the committing deadline + */ + error PrivateERC20ResolutionModule_CommittingPhaseOver(); + + /** + * @notice Thrown when trying to reveal a vote after the revealing deadline + */ + error PrivateERC20ResolutionModule_RevealingPhaseOver(); + + /** + * @notice Thrown when trying to resolve a dispute during the committing phase + */ + error PrivateERC20ResolutionModule_OnGoingCommittingPhase(); + + /** + * @notice Thrown when trying to resolve a dispute during the revealing phase + */ + error PrivateERC20ResolutionModule_OnGoingRevealingPhase(); + + /** + * @notice Thrown when trying to resolve a dispute that does not exist + */ + error PrivateERC20ResolutionModule_NonExistentDispute(); + + /** + * @notice Thrown when trying to commit an empty commitment + */ + error PrivateERC20ResolutionModule_EmptyCommitment(); + + /** + * @notice Thrown when trying to reveal a vote with data that does not match the stored commitment + */ + error PrivateERC20ResolutionModule_WrongRevealData(); + + /** + * @notice Thrown when trying to resolve a dispute that is already resolved + */ + error PrivateERC20ResolutionModule_AlreadyResolved(); + + /*/////////////////////////////////////////////////////////////// + STRUCTS + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Parameters of the request as stored in the module + * @param accountingExtension The accounting extension used to bond and release tokens + * @param token The token used to vote + * @param minVotesForQuorum The minimum amount of votes to win the dispute + * @param committingTimeWindow The amount of time to commit votes from the escalation of the dispute + * @param revealingTimeWindow The amount of time to reveal votes from the committing phase + */ + struct RequestParameters { + IAccountingExtension accountingExtension; + IERC20 votingToken; + uint256 minVotesForQuorum; + uint256 committingTimeWindow; + uint256 revealingTimeWindow; + } + + /** + * @notice Escalation data for a dispute + * @param startTime The timestamp at which the dispute was escalated + * @param totalVotes The total amount of votes cast for the dispute + */ + + struct Escalation { + uint256 startTime; + uint256 totalVotes; + } + + /** + * @notice Voting data for each voter + * @param numOfVotes The amount of votes cast for the dispute + * @param commitment The commitment provided by the voter + */ + struct VoterData { + uint256 numOfVotes; + bytes32 commitment; + } + + /*/////////////////////////////////////////////////////////////// + VARIABLES + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Returns the escalation data for a dispute + * @param _disputeId The id of the dispute + * @return _startTime The timestamp at which the dispute was escalated + * @return _totalVotes The total amount of votes cast for the dispute + */ + function escalations(bytes32 _disputeId) external view returns (uint256 _startTime, uint256 _totalVotes); + + /*/////////////////////////////////////////////////////////////// + LOGIC + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Starts the committing phase for a dispute + * @dev Only callable by the Oracle + * @param _disputeId The id of the dispute to start resolution of + */ + function startResolution( + bytes32 _disputeId, + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute + ) external; + + /** + * @notice Stores a commitment for a vote cast by a voter + * @dev Committing multiple times and overwriting a previous commitment is allowed + * @param _request The request being disputed + * @param _dispute The dispute being voted on + * @param _commitment The commitment computed from the provided data and the user's address + */ + function commitVote( + IOracle.Request calldata _request, + IOracle.Dispute calldata _dispute, + bytes32 _commitment + ) external; + + /** + * @notice Reveals a vote cast by a voter + * @dev The user must have previously approved the module to transfer the tokens + * @param _request The id of the request being disputed + * @param _dispute The id of the dispute being voted on + * @param _numberOfVotes The amount of votes being revealed + * @param _salt The salt used to compute the commitment + */ + function revealVote( + IOracle.Request calldata _request, + IOracle.Dispute calldata _dispute, + uint256 _numberOfVotes, + bytes32 _salt + ) external; + + /** + * @notice Settles the dispute, transferring the funds back to the voters + * + * @param _disputeId The id of the dispute + * @param _request The request for which the dispute was created + * @param _response The disputed response + * @param _dispute The dispute that is being resolved + */ + function resolveDispute( + bytes32 _disputeId, + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute + ) external; + + /** + * @notice Returns the decoded data for a request + * @param _data The encoded request parameters + * @return _params The struct containing the parameters for the request + */ + function decodeRequestData(bytes calldata _data) external view returns (RequestParameters memory _params); + + /** + * @notice Computes a valid commitment for the revealing phase + * @param _disputeId The id of the dispute being voted on + * @param _numberOfVotes The amount of votes being cast + * @return _commitment The commitment computed from the provided data and the user's address + */ + function computeCommitment( + bytes32 _disputeId, + uint256 _numberOfVotes, + bytes32 _salt + ) external view returns (bytes32 _commitment); +} diff --git a/solidity/interfaces/modules/resolution/ISequentialResolutionModule.sol b/solidity/interfaces/modules/resolution/ISequentialResolutionModule.sol index 8a7fc2db..95565ffd 100644 --- a/solidity/interfaces/modules/resolution/ISequentialResolutionModule.sol +++ b/solidity/interfaces/modules/resolution/ISequentialResolutionModule.sol @@ -72,11 +72,11 @@ // function requestIdForDispute(bytes32 _disputeId) external view returns (bytes32 _requestId); // /** -// * @notice Returns the decoded data for a request -// * @param _requestId The ID of the request -// * @return _params The struct containing the parameters for the request +// * @notice Returns the decoded data for a request +// * @param _data The encoded request parameters +// * @return _params The struct containing the parameters for the request // */ -// function decodeRequestData(bytes32 _requestId) external view returns (RequestParameters memory _params); +// function decodeRequestData(bytes calldata _data) external view returns (RequestParameters memory _params); // /*/////////////////////////////////////////////////////////////// // FUNCTIONS diff --git a/yarn.lock b/yarn.lock index e3e8e0d1..d2572dae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1181,10 +1181,6 @@ dotgitignore@^2.1.0: find-up "^3.0.0" minimatch "^3.0.4" -"ds-test@git+https://github.com/dapphub/ds-test.git#e282159d5170298eb2455a6c05280ab5a73a4ef0": - version "1.0.0" - resolved "git+https://github.com/dapphub/ds-test.git#e282159d5170298eb2455a6c05280ab5a73a4ef0" - "ds-test@https://github.com/dapphub/ds-test": version "1.0.0" uid e282159d5170298eb2455a6c05280ab5a73a4ef0 @@ -1192,7 +1188,6 @@ dotgitignore@^2.1.0: "ds-test@https://github.com/dapphub/ds-test.git#e282159d5170298eb2455a6c05280ab5a73a4ef0": version "1.0.0" - uid e282159d5170298eb2455a6c05280ab5a73a4ef0 resolved "https://github.com/dapphub/ds-test.git#e282159d5170298eb2455a6c05280ab5a73a4ef0" eastasianwidth@^0.2.0: @@ -1570,14 +1565,14 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" -"forge-std@git+https://github.com/foundry-rs/forge-std.git#e8a047e3f40f13fa37af6fe14e6e06283d9a060e": - version "1.5.6" - resolved "git+https://github.com/foundry-rs/forge-std.git#e8a047e3f40f13fa37af6fe14e6e06283d9a060e" - "forge-std@https://github.com/foundry-rs/forge-std": version "1.7.1" resolved "https://github.com/foundry-rs/forge-std#37a37ab73364d6644bfe11edf88a07880f99bd56" +"forge-std@https://github.com/foundry-rs/forge-std.git#e8a047e3f40f13fa37af6fe14e6e06283d9a060e": + version "1.5.6" + resolved "https://github.com/foundry-rs/forge-std.git#e8a047e3f40f13fa37af6fe14e6e06283d9a060e" + "forge-std@https://github.com/foundry-rs/forge-std.git#f73c73d2018eb6a111f35e4dae7b4f27401e9421": version "1.7.1" resolved "https://github.com/foundry-rs/forge-std.git#f73c73d2018eb6a111f35e4dae7b4f27401e9421" @@ -3279,13 +3274,8 @@ solidity-docgen@0.6.0-beta.35: handlebars "^4.7.7" solidity-ast "^0.4.38" -"solmate@git+https://github.com/transmissions11/solmate.git#bfc9c25865a274a7827fea5abf6e4fb64fc64e6c": - version "6.1.0" - resolved "git+https://github.com/transmissions11/solmate.git#bfc9c25865a274a7827fea5abf6e4fb64fc64e6c" - "solmate@https://github.com/transmissions11/solmate.git#bfc9c25865a274a7827fea5abf6e4fb64fc64e6c": version "6.1.0" - uid bfc9c25865a274a7827fea5abf6e4fb64fc64e6c resolved "https://github.com/transmissions11/solmate.git#bfc9c25865a274a7827fea5abf6e4fb64fc64e6c" sort-object-keys@^1.1.3: