diff --git a/solidity/contracts/modules/dispute/BondEscalationModule.sol b/solidity/contracts/modules/dispute/BondEscalationModule.sol index ce44ec97..4a5dd673 100644 --- a/solidity/contracts/modules/dispute/BondEscalationModule.sol +++ b/solidity/contracts/modules/dispute/BondEscalationModule.sol @@ -1,314 +1,293 @@ -// // 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); + + if (block.timestamp > ORACLE.createdAt(_dispute.responseId) + _params.disputeWindow) { + revert BondEscalationModule_DisputeWindowOver(); + } + + BondEscalation storage _escalation = _escalations[_dispute.requestId]; + bytes32 _disputeId = _getId(_dispute); + + // 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(); + + _escalation.status = BondEscalationStatus.Active; + _escalation.disputeId = _disputeId; + emit BondEscalationStatusUpdated(_dispute.requestId, _disputeId, BondEscalationStatus.Active); + } + + _params.accountingExtension.bond({ + _bonder: _dispute.disputer, + _requestId: _dispute.requestId, + _token: _params.bondToken, + _amount: _params.bondSize + }); + + emit ResponseDisputed({ + _requestId: _dispute.requestId, + _responseId: _dispute.responseId, + _disputeId: _disputeId, + _dispute: _dispute, + _blockNumber: 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]; + + if (ORACLE.disputeStatus(_disputeId) == IOracle.DisputeStatus.Escalated) { + 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 = ORACLE.disputeStatus(_disputeId) == 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 + }); + } + } + + IOracle.DisputeStatus _status = ORACLE.disputeStatus(_disputeId); + 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); + RequestParameters memory _params = _pledgeChecks(_disputeId, _request, _dispute, true); + + _escalations[_dispute.requestId].amountOfPledgesForDispute += 1; + pledgesForDispute[_dispute.requestId][msg.sender] += 1; + _params.accountingExtension.pledge({ + _pledger: msg.sender, + _requestId: _dispute.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); + RequestParameters memory _params = _pledgeChecks(_disputeId, _request, _dispute, false); + + _escalations[_dispute.requestId].amountOfPledgesAgainstDispute += 1; + pledgesAgainstDispute[_dispute.requestId][msg.sender] += 1; + _params.accountingExtension.pledge({ + _pledger: msg.sender, + _requestId: _dispute.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); + RequestParameters memory _params = decodeRequestData(_request.disputeModuleData); + 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 + * @return _params The decoded parameters for the request + */ + function _pledgeChecks( + bytes32 _disputeId, + IOracle.Request calldata _request, + IOracle.Dispute calldata _dispute, + bool _forDispute + ) internal view returns (RequestParameters memory _params) { + BondEscalation memory _escalation = _escalations[_dispute.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]; + } +} 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..20463e01 100644 --- a/solidity/interfaces/modules/dispute/IBondEscalationModule.sol +++ b/solidity/interfaces/modules/dispute/IBondEscalationModule.sol @@ -1,275 +1,264 @@ -// // 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 _response The response being disputed. + */ + 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 to update the status for. + * @param _dispute The full dispute object. + * + */ + 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. + */ + 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. + */ + 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 + */ + function settleBondEscalation( + IOracle.Request calldata _request, + IOracle.Response calldata _response, + IOracle.Dispute calldata _dispute + ) external; +} diff --git a/solidity/test/unit/modules/dispute/BondEscalationModule.t.sol b/solidity/test/unit/modules/dispute/BondEscalationModule.t.sol index bcf3c02f..09f830e0 100644 --- a/solidity/test/unit/modules/dispute/BondEscalationModule.t.sol +++ b/solidity/test/unit/modules/dispute/BondEscalationModule.t.sol @@ -1,1437 +1,1429 @@ -// // SPDX-License-Identifier: AGPL-3.0-only -// pragma solidity ^0.8.19; - -// import 'forge-std/Test.sol'; - -// import {Helpers} from '../../../utils/Helpers.sol'; - -// import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -// import {Strings} from '@openzeppelin/contracts/utils/Strings.sol'; -// import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; -// import {IModule} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IModule.sol'; - -// import { -// BondEscalationModule, IBondEscalationModule -// } from '../../../../contracts/modules/dispute/BondEscalationModule.sol'; - -// import {IAccountingExtension} from '../../../../interfaces/extensions/IAccountingExtension.sol'; -// import {IBondEscalationAccounting} from '../../../../interfaces/extensions/IBondEscalationAccounting.sol'; - -// /** -// * @dev Harness to set an entry in the requestData mapping, without triggering setup request hooks -// */ -// contract ForTest_BondEscalationModule is BondEscalationModule { -// constructor(IOracle _oracle) BondEscalationModule(_oracle) {} - -// function forTest_setRequestData(bytes32 _requestId, bytes memory _data) public { -// requestData[_requestId] = _data; -// } - -// function forTest_setBondEscalation( -// bytes32 _requestId, -// address[] memory _pledgersForDispute, -// address[] memory _pledgersAgainstDispute -// ) public { -// for (uint256 _i; _i < _pledgersForDispute.length; _i++) { -// pledgesForDispute[_requestId][_pledgersForDispute[_i]] += 1; -// } - -// for (uint256 _i; _i < _pledgersAgainstDispute.length; _i++) { -// pledgesAgainstDispute[_requestId][_pledgersAgainstDispute[_i]] += 1; -// } - -// _escalations[_requestId].amountOfPledgesForDispute += _pledgersForDispute.length; -// _escalations[_requestId].amountOfPledgesAgainstDispute += _pledgersAgainstDispute.length; -// } - -// function forTest_setBondEscalationStatus( -// bytes32 _requestId, -// BondEscalationModule.BondEscalationStatus _bondEscalationStatus -// ) public { -// _escalations[_requestId].status = _bondEscalationStatus; -// } - -// function forTest_setEscalatedDispute(bytes32 _requestId, bytes32 _disputeId) public { -// _escalations[_requestId].disputeId = _disputeId; -// } -// } - -// /** -// * @title Bonded Response Module Unit tests -// */ - -// contract BaseTest is Test, Helpers { -// // The target contract -// ForTest_BondEscalationModule public bondEscalationModule; -// // A mock oracle -// IOracle public oracle; -// // A mock accounting extension -// IBondEscalationAccounting public accounting; -// // A mock token -// IERC20 public token; -// // Mock EOA proposer -// address public proposer = makeAddr('proposer'); -// // Mock EOA disputer -// address public disputer = makeAddr('disputer'); -// // Mock bondSize -// uint256 public bondSize; -// // Mock max number of escalations -// uint256 public maxEscalations; -// // Mock bond escalation deadline -// uint256 public bondEscalationDeadline; -// // Mock tyingBuffer -// uint256 public tyingBuffer; -// // Mock dispute window -// uint256 public disputeWindow; -// // Mock dispute -// IOracle.Dispute internal _mockDispute; -// // Mock response -// IOracle.Response internal _mockResponse; - -// // Events -// event PledgedForDispute(bytes32 indexed _disputeId, address indexed _pledger, uint256 indexed _amount); -// event PledgedAgainstDispute(bytes32 indexed _disputeId, address indexed _pledger, uint256 indexed _amount); -// event BondEscalationStatusUpdated( -// bytes32 indexed _requestId, bytes32 indexed _disputeId, IBondEscalationModule.BondEscalationStatus _status -// ); -// event ResponseDisputed(bytes32 indexed _requestId, bytes32 _responseId, address _disputer, address _proposer); -// event DisputeStatusChanged( -// bytes32 indexed _requestId, bytes32 _responseId, address _disputer, address _proposer, IOracle.DisputeStatus _status -// ); - -// /** -// * @notice Deploy the target and mock oracle+accounting extension -// */ -// function setUp() public { -// oracle = IOracle(makeAddr('Oracle')); -// vm.etch(address(oracle), hex'069420'); - -// accounting = IBondEscalationAccounting(makeAddr('BondEscalationAccounting')); -// vm.etch(address(accounting), hex'069420'); - -// token = IERC20(makeAddr('ERC20')); -// vm.etch(address(token), hex'069420'); - -// // Set to an arbitrary large value to avoid unintended reverts -// disputeWindow = type(uint128).max; - -// // Avoid starting at 0 for time sensitive tests -// vm.warp(123_456); - -// _mockDispute = IOracle.Dispute({ -// disputer: disputer, -// responseId: bytes32('response'), -// proposer: proposer, -// requestId: bytes32('69'), -// status: IOracle.DisputeStatus.Active, -// createdAt: block.timestamp -// }); - -// _mockResponse = IOracle.Response({ -// createdAt: block.timestamp, -// proposer: proposer, -// requestId: bytes32('69'), -// disputeId: 0, -// response: abi.encode(bytes32('response')) -// }); - -// bondEscalationModule = new ForTest_BondEscalationModule(oracle); -// } - -// function _setRequestData( -// bytes32 _requestId, -// uint256 _bondSize, -// uint256 _maxNumberOfEscalations, -// uint256 _bondEscalationDeadline, -// uint256 _tyingBuffer, -// uint256 _disputeWindow -// ) internal { -// bytes memory _data = abi.encode( -// IBondEscalationModule.RequestParameters({ -// accountingExtension: accounting, -// bondToken: token, -// bondSize: _bondSize, -// maxNumberOfEscalations: _maxNumberOfEscalations, -// bondEscalationDeadline: _bondEscalationDeadline, -// tyingBuffer: _tyingBuffer, -// disputeWindow: _disputeWindow -// }) -// ); -// bondEscalationModule.forTest_setRequestData(_requestId, _data); -// } - -// function _getRandomDispute( -// bytes32 _requestId, -// IOracle.DisputeStatus _status -// ) internal view returns (IOracle.Dispute memory _dispute) { -// _dispute = IOracle.Dispute({ -// disputer: disputer, -// responseId: bytes32('response'), -// proposer: proposer, -// requestId: _requestId, -// status: _status, -// createdAt: block.timestamp -// }); -// } - -// function _setBondEscalation( -// bytes32 _requestId, -// uint256 _numForPledgers, -// uint256 _numAgainstPledgers -// ) internal returns (address[] memory _forPledgers, address[] memory _againstPledgers) { -// _forPledgers = new address[](_numForPledgers); -// _againstPledgers = new address[](_numAgainstPledgers); -// address _forPledger; -// address _againstPledger; - -// for (uint256 _i; _i < _numForPledgers; _i++) { -// _forPledger = makeAddr(string.concat('forPledger', Strings.toString(_i))); -// _forPledgers[_i] = _forPledger; -// } - -// for (uint256 _j; _j < _numAgainstPledgers; _j++) { -// _againstPledger = makeAddr(string.concat('againstPledger', Strings.toString(_j))); -// _againstPledgers[_j] = _againstPledger; -// } - -// bondEscalationModule.forTest_setBondEscalation(_requestId, _forPledgers, _againstPledgers); - -// return (_forPledgers, _againstPledgers); -// } -// } - -// contract BondEscalationModule_Unit_ModuleData is BaseTest { -// /** -// * @notice Test that the moduleName function returns the correct name -// */ -// function test_moduleName() public { -// assertEq(bondEscalationModule.moduleName(), 'BondEscalationModule'); -// } - -// /** -// * @notice Tests that decodeRequestData decodes the data correctly -// */ -// function test_decodeRequestDataReturnTheCorrectData( -// bytes32 _requestId, -// uint256 _bondSize, -// uint256 _maxNumberOfEscalations, -// uint256 _bondEscalationDeadline, -// uint256 _tyingBuffer, -// uint256 _disputeWindow -// ) public { -// _setRequestData( -// _requestId, _bondSize, _maxNumberOfEscalations, _bondEscalationDeadline, _tyingBuffer, _disputeWindow -// ); -// IBondEscalationModule.RequestParameters memory _params = bondEscalationModule.decodeRequestData(_requestId); - -// // Check: does the stored data match the provided one? -// assertEq(address(accounting), address(_params.accountingExtension)); -// assertEq(address(token), address(_params.bondToken)); -// assertEq(_bondSize, _params.bondSize); -// assertEq(_maxNumberOfEscalations, _params.maxNumberOfEscalations); -// assertEq(_bondEscalationDeadline, _params.bondEscalationDeadline); -// assertEq(_tyingBuffer, _params.tyingBuffer); -// assertEq(_disputeWindow, _params.disputeWindow); -// } -// } - -// contract BondEscalationModule_Unit_EscalateDispute is BaseTest { -// /** -// * @notice Tests that escalateDispute reverts if the _disputeId doesn't match any existing disputes. -// */ -// function test_revertOnInvalidDispute(bytes32 _disputeId) public { -// _mockDispute.requestId = bytes32(0); -// // Mock and expect Oracle.getDispute to be called. -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// // Check: does it revert if the dispute does not exist? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_DisputeDoesNotExist.selector); -// vm.prank(address(oracle)); -// bondEscalationModule.disputeEscalated(_disputeId); -// } - -// /** -// * @notice Tests that escalateDispute reverts if the _disputeId doesn't match any existing disputes. -// */ -// function test_revertOnInvalidParameters( -// bytes32 _requestId, -// uint256 _maxNumberOfEscalations, -// uint256 _bondSize, -// uint256 _bondEscalationDeadline, -// uint256 _tyingBuffer, -// uint256 _disputeWindow -// ) public { -// bytes memory _requestData = abi.encode( -// IBondEscalationModule.RequestParameters({ -// accountingExtension: accounting, -// bondToken: token, -// bondSize: _bondSize, -// maxNumberOfEscalations: _maxNumberOfEscalations, -// bondEscalationDeadline: _bondEscalationDeadline, -// tyingBuffer: _tyingBuffer, -// disputeWindow: _disputeWindow -// }) -// ); - -// if (_maxNumberOfEscalations == 0 || _bondSize == 0) { -// // Check: does it revert if _maxNumberOfEscalations or _bondSize is 0? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_InvalidEscalationParameters.selector); -// } - -// vm.prank(address(oracle)); -// bondEscalationModule.setupRequest(_requestId, _requestData); -// } - -// /** -// * @notice Tests that escalateDispute reverts if a dispute is escalated before the bond escalation deadline is over. -// * Conditions to reach this check: -// * - The _requestId tied to the dispute tied to _disputeId must be valid (non-zero) -// * - The block.timestamp has to be <= bond escalation deadline -// */ -// function test_revertEscalationDuringBondEscalation(bytes32 _disputeId, bytes32 _requestId) public { -// vm.assume(_requestId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect Oracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// // Set _bondEscalationDeadline to be the current timestamp to reach the second condition. -// uint256 _bondEscalationDeadline = block.timestamp; - -// // Populate the requestData for the given requestId -// _setRequestData(_requestId, bondSize, maxEscalations, _bondEscalationDeadline, tyingBuffer, disputeWindow); - -// // Setting this dispute as the one going through the bond escalation process, as the user can only -// // dispute once before the bond escalation deadline is over, and that dispute goes through the escalation module. -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// // Check: does it revert if the bond escalation is not over yet? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_BondEscalationNotOver.selector); -// vm.prank(address(oracle)); -// bondEscalationModule.disputeEscalated(_disputeId); -// } - -// /** -// * @notice Tests that escalateDispute reverts if a dispute that went through the bond escalation mechanism but isn't active -// * anymore is escalated. -// * Conditions to reach this check: -// * - The _requestId tied to the dispute tied to _disputeId must be valid (non-zero) -// * - The block.timestamp has to be > bond escalation deadline -// * - The dispute has to have gone through the bond escalation process before -// * - The status of the bond escalation mechanism has to be different from Active -// */ -// function test_revertIfEscalatingNonActiveDispute(bytes32 _disputeId, bytes32 _requestId, uint8 _status) public { -// // Assume _requestId is not zero -// vm.assume(_requestId > 0); -// // Assume the status will be any available other but Active -// vm.assume(_status != uint8(IBondEscalationModule.BondEscalationStatus.Active) && _status < 4); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect Oracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// // Set a tying buffer to show that this can happen even in the tying buffer if the dispute was settled -// uint256 _tyingBuffer = 1000; - -// // Make the current timestamp be greater than the bond escalation deadline -// uint256 _bondEscalationDeadline = block.timestamp - 1; - -// // Populate the requestData for the given requestId -// _setRequestData(_requestId, bondSize, maxEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow); - -// // Set the bond escalation status of the given requestId to something different than Active -// bondEscalationModule.forTest_setBondEscalationStatus( -// _requestId, IBondEscalationModule.BondEscalationStatus(_status) -// ); - -// // Set the dispute to be the one that went through the bond escalation process for the given requestId -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// // Check: does it revert if the dispute is not escalatable? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_NotEscalatable.selector); -// vm.prank(address(oracle)); -// bondEscalationModule.disputeEscalated(_disputeId); -// } - -// /** -// * @notice Tests that escalateDispute reverts if a dispute that went through the bond escalation mechanism and is still active -// * but its pledges are not tied even after the tying buffer is escalated. -// * Conditions to reach this check: -// * - The _requestId tied to the dispute tied to _disputeId must be valid (non-zero) -// * - The block.timestamp has to be > bond escalation deadline + tying buffer -// * - The dispute has to have gone or be going through the bond escalation process -// * - The pledges must not be tied -// */ -// function test_revertIfEscalatingDisputeIsNotTied(bytes32 _disputeId, bytes32 _requestId) public { -// // Assume _requestId is not zero -// vm.assume(_requestId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect Oracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// // Set a tying buffer to make the test more explicit -// uint256 _tyingBuffer = 1000; - -// // Set bond escalation deadline to be the current timestamp. We will warp this. -// uint256 _bondEscalationDeadline = block.timestamp; - -// // Set the number of pledgers to be different -// uint256 _numForPledgers = 1; -// uint256 _numAgainstPledgers = 2; - -// // Warp the current timestamp so we are past the tyingBuffer -// vm.warp(_bondEscalationDeadline + _tyingBuffer + 1); - -// // Populate the requestData for the given requestId -// _setRequestData(_requestId, bondSize, maxEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow); - -// // Set the bond escalation status of the given requestId to Active -// bondEscalationModule.forTest_setBondEscalationStatus(_requestId, IBondEscalationModule.BondEscalationStatus.Active); - -// // Set the dispute to be the one that went through the bond escalation process for the given requestId -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// // Set the number of pledgers for both sides -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// // Check: does it revert if the dispute is not escalatable? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_NotEscalatable.selector); -// vm.prank(address(oracle)); -// bondEscalationModule.disputeEscalated(_disputeId); -// } - -// /** -// * @notice Tests that escalateDispute escalates the dispute going through the bond escalation mechanism correctly when the -// * pledges are tied and the dispute is still active. -// * Conditions for the function to succeed: -// * - The _requestId tied to the dispute tied to _disputeId must be valid (non-zero) -// * - The block.timestamp has to be > bond escalation deadline -// * - The dispute has to have gone or be going through the bond escalation process -// * - The pledges must be tied -// */ -// function test_escalateTiedDispute(bytes32 _disputeId, bytes32 _requestId) public { -// // Assume _requestId is not zero -// vm.assume(_requestId > 0); -// vm.assume(_disputeId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect Oracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// // Set a tying buffer -// uint256 _tyingBuffer = 1000; - -// // Set bond escalation deadline to be the current timestamp. We will warp this. -// uint256 _bondEscalationDeadline = block.timestamp; - -// // Set the number of pledgers to be the same. This means the pledges are tied. -// uint256 _numForPledgers = 2; -// uint256 _numAgainstPledgers = 2; - -// // Warp so we are still in the tying buffer period. This is to show a dispute can be escalated during the buffer if the pledges are tied. -// vm.warp(_bondEscalationDeadline + _tyingBuffer); - -// // Populate the requestData for the given requestId -// _setRequestData(_requestId, bondSize, maxEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow); - -// // Set the bond escalation status of the given requestId to Active -// bondEscalationModule.forTest_setBondEscalationStatus(_requestId, IBondEscalationModule.BondEscalationStatus.Active); - -// // Set the dispute to be the one that went through the bond escalation process for the given requestId -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// // Set the number of pledgers for both sides -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// // Check: is the event emitted? -// vm.expectEmit(true, true, true, true, address(bondEscalationModule)); -// emit BondEscalationStatusUpdated(_requestId, _disputeId, IBondEscalationModule.BondEscalationStatus.Escalated); - -// vm.prank(address(oracle)); -// bondEscalationModule.disputeEscalated(_disputeId); - -// IBondEscalationModule.BondEscalation memory _escalation = bondEscalationModule.getEscalation(_requestId); -// // Check: is the bond escalation status properly updated? -// assertEq(uint256(_escalation.status), uint256(IBondEscalationModule.BondEscalationStatus.Escalated)); -// } - -// /** -// * @notice Tests that escalateDispute escalates a dispute not going through the bond escalation mechanism correctly after -// * the bond mechanism deadline has gone by. -// * Conditions for the function to succeed: -// * - The _requestId tied to the dispute tied to _disputeId must be valid (non-zero) -// * - The block.timestamp has to be > bond escalation deadline -// */ -// function test_escalateNormalDispute(bytes32 _disputeId, bytes32 _requestId) public { -// // Assume _requestId and _disputeId are not zero -// vm.assume(_requestId > 0); -// vm.assume(_disputeId > 0); - -// uint256 _tyingBuffer = 1000; - -// _mockDispute.requestId = _requestId; - -// // Mock and expect Oracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// // Set bond escalation deadline to be the current timestamp. We will warp this. -// uint256 _bondEscalationDeadline = block.timestamp; - -// // Warp so we are past the tying buffer period -// vm.warp(_bondEscalationDeadline + 1); - -// // Populate the requestData for the given requestId -// _setRequestData(_requestId, bondSize, maxEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow); - -// vm.prank(address(oracle)); -// bondEscalationModule.disputeEscalated(_disputeId); -// } -// } - -// contract BondEscalationModule_Unit_DisputeResponse is BaseTest { -// /** -// * @notice Tests that disputeResponse reverts the caller is not the oracle address. -// */ -// function test_revertIfCallerIsNotOracle(bytes32 _requestId, bytes32 _responseId, address _caller) public { -// vm.assume(_caller != address(oracle)); - -// // Check: does it revert if not called by the Oracle? -// vm.expectRevert(IModule.Module_OnlyOracle.selector); -// vm.prank(_caller); -// bondEscalationModule.disputeResponse(_requestId, _responseId, disputer, proposer); -// } - -// /** -// * @notice Tests that disputeResponse reverts if the challenge period for the response is over. -// */ -// function test_revertIfDisputeWindowIsOver(bytes32 _requestId, bytes32 _responseId) public { -// uint256 _disputeWindow = 1; - -// _setRequestData(_requestId, bondSize, maxEscalations, bondEscalationDeadline, tyingBuffer, _disputeWindow); - -// _mockResponse.requestId = _requestId; - -// // Mock and expect Oracle.getResponse to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getResponse, (_responseId)), abi.encode(_mockResponse)); - -// // Warp to a time after the disputeWindow is over. -// vm.warp(block.timestamp + _disputeWindow + 1); - -// // Check: does it revert if the dispute window is over? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_DisputeWindowOver.selector); -// vm.prank(address(oracle)); -// bondEscalationModule.disputeResponse(_requestId, _responseId, disputer, proposer); -// } - -// /** -// * @notice Tests that disputeResponse succeeds if someone dispute after the bond escalation deadline is over -// */ -// function test_succeedIfDisputeAfterBondingEscalationDeadline(bytes32 _requestId, bytes32 _responseId) public { -// // Set deadline to timestamp so we are still in the bond escalation period -// uint256 _bondEscalationDeadline = block.timestamp - 1; - -// // Set the request data for the given requestId -// _setRequestData(_requestId, bondSize, maxEscalations, _bondEscalationDeadline, tyingBuffer, disputeWindow); - -// _mockResponse.requestId = _requestId; - -// // Mock and expect Oracle.getResponse to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getResponse, (_responseId)), abi.encode(_mockResponse)); - -// // Check: does it revert if the bond escalation is over? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_BondEscalationOver.selector); -// vm.prank(address(oracle)); -// bondEscalationModule.disputeResponse(_requestId, _responseId, disputer, proposer); -// } - -// /** -// * @notice Tests that disputeResponse succeeds in starting the bond escalation mechanism when someone disputes -// * the first propose before the bond escalation deadline is over. -// */ -// function test_firstDisputeThroughBondMechanism(bytes32 _requestId, bytes32 _responseId) public { -// // Set deadline to timestamp so we are still in the bond escalation period -// uint256 _bondEscalationDeadline = block.timestamp; - -// // Set the request data for the given requestId -// _setRequestData(_requestId, bondSize, maxEscalations, _bondEscalationDeadline, tyingBuffer, disputeWindow); - -// _mockResponse.requestId = _requestId; - -// // Mock and expect Oracle.getResponse to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getResponse, (_responseId)), abi.encode(_mockResponse)); - -// // Mock and expect the accounting extension to be called -// _mockAndExpect( -// address(accounting), -// abi.encodeWithSignature('bond(address,bytes32,address,uint256)', disputer, _requestId, token, bondSize), -// abi.encode(true) -// ); - -// bytes32 _expectedDisputeId = keccak256(abi.encodePacked(disputer, _requestId, _responseId)); - -// // Check: is the event emitted? -// vm.expectEmit(true, true, true, true, address(bondEscalationModule)); -// emit BondEscalationStatusUpdated(_requestId, _expectedDisputeId, IBondEscalationModule.BondEscalationStatus.Active); - -// vm.prank(address(oracle)); -// bondEscalationModule.disputeResponse(_requestId, _responseId, disputer, proposer); - -// // Check: is the bond escalation status now active? -// assertEq( -// uint256(bondEscalationModule.getEscalation(_requestId).status), -// uint256(IBondEscalationModule.BondEscalationStatus.Active) -// ); - -// // Check: is the dispute assigned to the bond escalation process? -// assertEq(bondEscalationModule.getEscalation(_requestId).disputeId, _expectedDisputeId); -// } - -// function test_emitsEvent(bytes32 _requestId, bytes32 _responseId) public { -// // Set deadline to timestamp so we are still in the bond escalation period -// uint256 _bondEscalationDeadline = block.timestamp; - -// // Set the request data for the given requestId -// _setRequestData(_requestId, bondSize, maxEscalations, _bondEscalationDeadline, tyingBuffer, disputeWindow); - -// _mockResponse.requestId = _requestId; - -// // Mock and expect Oracle.getResponse to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getResponse, (_responseId)), abi.encode(_mockResponse)); - -// // Mock and expect the accounting extension to be called -// _mockAndExpect( -// address(accounting), -// abi.encodeWithSignature('bond(address,bytes32,address,uint256)', disputer, _requestId, token, bondSize), -// abi.encode(true) -// ); - -// // Check: is the event emitted? -// vm.expectEmit(true, true, true, true, address(bondEscalationModule)); -// emit ResponseDisputed(_requestId, _responseId, disputer, proposer); - -// vm.prank(address(oracle)); -// bondEscalationModule.disputeResponse(_requestId, _responseId, disputer, proposer); -// } -// } - -// contract BondEscalationModule_Unit_OnDisputeStatusChange is BaseTest { -// /** -// * @notice Tests that onDisputeStatusChange reverts -// */ -// function test_revertIfCallerIsNotOracle( -// bytes32 _disputeId, -// bytes32 _requestId, -// address _caller, -// uint8 _status -// ) public { -// vm.assume(_caller != address(oracle)); -// vm.assume(_status < 4); - -// IOracle.DisputeStatus _disputeStatus = IOracle.DisputeStatus(_status); -// IOracle.Dispute memory _dispute = _getRandomDispute(_requestId, _disputeStatus); - -// // Check: does it revert if not called by the Oracle? -// vm.expectRevert(IModule.Module_OnlyOracle.selector); -// vm.prank(_caller); -// bondEscalationModule.onDisputeStatusChange(_disputeId, _dispute); -// } - -// /** -// * @notice Tests that onDisputeStatusChange pays the proposer if the disputer lost -// */ -// function test_callPayIfNormalDisputeLost(bytes32 _disputeId, bytes32 _requestId) public { -// vm.assume(_disputeId > 0 && _requestId > 0); - -// IOracle.DisputeStatus _status = IOracle.DisputeStatus.Lost; -// IOracle.Dispute memory _dispute = _getRandomDispute(_requestId, _status); - -// _setRequestData(_requestId, bondSize, maxEscalations, bondEscalationDeadline, tyingBuffer, disputeWindow); - -// // Mock and expect IAccountingExtension.pay to be called -// _mockAndExpect( -// address(accounting), -// abi.encodeCall(IAccountingExtension.pay, (_requestId, _dispute.disputer, _dispute.proposer, token, bondSize)), -// abi.encode(true) -// ); - -// vm.prank(address(oracle)); -// bondEscalationModule.onDisputeStatusChange(_disputeId, _dispute); -// } - -// /** -// * @notice Tests that onDisputeStatusChange pays the disputer if the disputer won -// */ -// function test_callPayIfNormalDisputeWon(bytes32 _disputeId, bytes32 _requestId) public { -// IOracle.DisputeStatus _status = IOracle.DisputeStatus.Won; -// IOracle.Dispute memory _dispute = _getRandomDispute(_requestId, _status); - -// _setRequestData(_requestId, bondSize, maxEscalations, bondEscalationDeadline, tyingBuffer, disputeWindow); - -// // Mock and expect IAccountingExtension.pay to be called -// _mockAndExpect( -// address(accounting), -// abi.encodeCall(IAccountingExtension.pay, (_requestId, _dispute.proposer, _dispute.disputer, token, bondSize)), -// abi.encode(true) -// ); - -// // Mock and expect IAccountingExtension.release to be called -// _mockAndExpect( -// address(accounting), -// abi.encodeCall(IAccountingExtension.release, (_dispute.disputer, _requestId, token, bondSize)), -// abi.encode(true) -// ); - -// vm.prank(address(oracle)); -// bondEscalationModule.onDisputeStatusChange(_disputeId, _dispute); -// } - -// function test_emitsEvent(bytes32 _disputeId, bytes32 _requestId) public { -// IOracle.DisputeStatus _status = IOracle.DisputeStatus.Won; -// IOracle.Dispute memory _dispute = _getRandomDispute(_requestId, _status); - -// _setRequestData(_requestId, bondSize, maxEscalations, bondEscalationDeadline, tyingBuffer, disputeWindow); - -// // Mock and expect IAccountingExtension.pay to be called -// _mockAndExpect( -// address(accounting), -// abi.encodeCall(IAccountingExtension.pay, (_requestId, _dispute.proposer, _dispute.disputer, token, bondSize)), -// abi.encode(true) -// ); - -// // Mock and expect IAccountingExtension.release to be called -// _mockAndExpect( -// address(accounting), -// abi.encodeCall(IAccountingExtension.release, (_dispute.disputer, _requestId, token, bondSize)), -// abi.encode(true) -// ); - -// // Check: is the event emitted? -// vm.expectEmit(true, true, true, true, address(bondEscalationModule)); -// emit DisputeStatusChanged( -// _requestId, _dispute.responseId, _dispute.disputer, _dispute.proposer, IOracle.DisputeStatus.Won -// ); - -// vm.prank(address(oracle)); -// bondEscalationModule.onDisputeStatusChange(_disputeId, _dispute); -// } - -// /** -// * @notice Tests that onDisputeStatusChange returns early if the dispute has gone through the bond -// * escalation mechanism but no one pledged -// */ -// function test_earlyReturnIfBondEscalatedDisputeHashNoPledgers(bytes32 _disputeId, bytes32 _requestId) public { -// IOracle.DisputeStatus _status = IOracle.DisputeStatus.Won; -// IOracle.Dispute memory _dispute = _getRandomDispute(_requestId, _status); - -// _setRequestData(_requestId, bondSize, maxEscalations, bondEscalationDeadline, tyingBuffer, disputeWindow); - -// uint256 _numForPledgers = 0; -// uint256 _numAgainstPledgers = 0; - -// // Set bond escalation data to have no pledgers -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// // Set this dispute to have gone through the bond escalation process -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// // Set the bond escalation status to Escalated, which is the only possible one for this function -// bondEscalationModule.forTest_setBondEscalationStatus( -// _requestId, IBondEscalationModule.BondEscalationStatus.Escalated -// ); - -// // Mock and expect IAccountingExtension.pay to be called -// _mockAndExpect( -// address(accounting), -// abi.encodeCall(IAccountingExtension.pay, (_requestId, _dispute.proposer, _dispute.disputer, token, bondSize)), -// abi.encode(true) -// ); - -// // Mock and expect IAccountingExtension.release to be called -// _mockAndExpect( -// address(accounting), -// abi.encodeCall(IAccountingExtension.release, (_dispute.disputer, _requestId, token, bondSize)), -// abi.encode(true) -// ); - -// vm.prank(address(oracle)); -// bondEscalationModule.onDisputeStatusChange(_disputeId, _dispute); - -// // Check: is the bond escalation status properly updated? -// assertEq( -// uint256(bondEscalationModule.getEscalation(_requestId).status), -// uint256(IBondEscalationModule.BondEscalationStatus.Escalated) -// ); -// } - -// /** -// * @notice Tests that onDisputeStatusChange changes the status of the bond escalation if the -// * dispute went through the bond escalation process, as well as testing that it calls -// * payPledgersWon with the correct arguments. In the Won case, this would be, passing -// * the users that pledged in favor of the dispute, as they have won. -// */ -// function test_shouldChangeBondEscalationStatusAndCallPayPledgersWon(bytes32 _disputeId, bytes32 _requestId) public { -// IOracle.DisputeStatus _status = IOracle.DisputeStatus.Won; -// IOracle.Dispute memory _dispute = _getRandomDispute(_requestId, _status); - -// _setRequestData(_requestId, bondSize, maxEscalations, bondEscalationDeadline, tyingBuffer, disputeWindow); - -// uint256 _numForPledgers = 2; -// uint256 _numAgainstPledgers = 2; - -// // Set bond escalation data to have pledgers and to return the winning for pledgers as in this case they won the escalation -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// // Set this dispute to have gone through the bond escalation process -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// // Set the bond escalation status to Escalated, which is the only possible one for this function -// bondEscalationModule.forTest_setBondEscalationStatus( -// _requestId, IBondEscalationModule.BondEscalationStatus.Escalated -// ); - -// // Mock and expect IAccountingExtension.pay to be called -// _mockAndExpect( -// address(accounting), -// abi.encodeCall(IAccountingExtension.pay, (_requestId, _dispute.proposer, _dispute.disputer, token, bondSize)), -// abi.encode(true) -// ); - -// // Mock and expect IAccountingExtension.release to be called -// _mockAndExpect( -// address(accounting), -// abi.encodeCall(IAccountingExtension.release, (_dispute.disputer, _requestId, token, bondSize)), -// abi.encode(true) -// ); - -// // Mock and expect IBondEscalationAccounting.onSettleBondEscalation to be called -// _mockAndExpect( -// address(accounting), -// abi.encodeCall( -// IBondEscalationAccounting.onSettleBondEscalation, -// (_requestId, _disputeId, true, token, bondSize << 1, _numForPledgers) -// ), -// abi.encode() -// ); - -// // Check: is the event emitted? -// vm.expectEmit(true, true, true, true, address(bondEscalationModule)); -// emit BondEscalationStatusUpdated(_requestId, _disputeId, IBondEscalationModule.BondEscalationStatus.DisputerWon); - -// vm.prank(address(oracle)); -// bondEscalationModule.onDisputeStatusChange(_disputeId, _dispute); - -// // Check: is the bond escalation status properly updated? -// assertEq( -// uint256(bondEscalationModule.getEscalation(_requestId).status), -// uint256(IBondEscalationModule.BondEscalationStatus.DisputerWon) -// ); -// } - -// /** -// * @notice Tests that onDisputeStatusChange changes the status of the bond escalation if the -// * dispute went through the bond escalation process, as well as testing that it calls -// * payPledgersWon with the correct arguments. In the Lost case, this would be, passing -// * the users that pledged against the dispute, as those that pledged in favor have lost . -// */ -// function test_shouldChangeBondEscalationStatusAndCallPayPledgersLost(bytes32 _disputeId, bytes32 _requestId) public { -// // Set to Lost so the proposer and againstDisputePledgers win -// IOracle.DisputeStatus _status = IOracle.DisputeStatus.Lost; -// IOracle.Dispute memory _dispute = _getRandomDispute(_requestId, _status); - -// uint256 _bondSize = 1000; - -// _setRequestData(_requestId, _bondSize, maxEscalations, bondEscalationDeadline, tyingBuffer, disputeWindow); - -// uint256 _numForPledgers = 2; -// uint256 _numAgainstPledgers = 2; - -// // Set bond escalation data to have pledgers and to return the winning for pledgers as in this case they won the escalation -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// // Set this dispute to have gone through the bond escalation process -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// // Set the bond escalation status to Escalated, which is the only possible one for this function -// bondEscalationModule.forTest_setBondEscalationStatus( -// _requestId, IBondEscalationModule.BondEscalationStatus.Escalated -// ); - -// // Mock and expect IAccountingExtension.pay to be called -// _mockAndExpect( -// address(accounting), -// abi.encodeCall(IAccountingExtension.pay, (_requestId, _dispute.disputer, _dispute.proposer, token, _bondSize)), -// abi.encode(true) -// ); - -// // Mock and expect IBondEscalationAccounting.onSettleBondEscalation to be called -// vm.mockCall( -// address(accounting), -// abi.encodeCall( -// IBondEscalationAccounting.onSettleBondEscalation, -// (_requestId, _disputeId, false, token, _bondSize << 1, _numAgainstPledgers) -// ), -// abi.encode(true) -// ); - -// // Check: is th event emitted? -// vm.expectEmit(true, true, true, true, address(bondEscalationModule)); -// emit BondEscalationStatusUpdated(_requestId, _disputeId, IBondEscalationModule.BondEscalationStatus.DisputerLost); - -// vm.prank(address(oracle)); -// bondEscalationModule.onDisputeStatusChange(_disputeId, _dispute); - -// // Check: is the bond escalation status properly updated? -// assertEq( -// uint256(bondEscalationModule.getEscalation(_requestId).status), -// uint256(IBondEscalationModule.BondEscalationStatus.DisputerLost) -// ); -// } -// } - -// contract BondEscalationModule_Unit_PledgeForDispute is BaseTest { -// /** -// * @notice Tests that pledgeForDispute reverts if the dispute does not exist. -// */ -// function test_revertIfDisputeIsZero() public { -// bytes32 _disputeId = 0; - -// // Check: does it revert if the dispute does not exist? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_DisputeDoesNotExist.selector); -// bondEscalationModule.pledgeForDispute(_disputeId); -// } - -// /** -// * @notice Tests that pledgeForDispute reverts if the dispute is not going through the bond escalation mechanism. -// */ -// function test_revertIfTheDisputeIsNotGoingThroughTheBondEscalationProcess( -// bytes32 _disputeId, -// bytes32 _requestId -// ) public { -// vm.assume(_disputeId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect IOracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// // Check: does it revert if the dispute is not escalated yet? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_InvalidDispute.selector); -// bondEscalationModule.pledgeForDispute(_disputeId); -// } - -// /** -// * @notice Tests that pledgeForDispute reverts if someone tries to pledge after the tying buffer. -// */ -// function test_revertIfTimestampBeyondTyingBuffer(bytes32 _disputeId, bytes32 _requestId) public { -// vm.assume(_disputeId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect IOracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// uint256 _bondSize = 1; -// uint256 _maxNumberOfEscalations = 1; -// uint256 _bondEscalationDeadline = block.timestamp; -// uint256 _tyingBuffer = 1000; - -// vm.warp(_bondEscalationDeadline + _tyingBuffer + 1); - -// _setRequestData( -// _requestId, _bondSize, _maxNumberOfEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow -// ); - -// // Check: does it revert if the bond escalation is over? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_BondEscalationOver.selector); -// bondEscalationModule.pledgeForDispute(_disputeId); -// } - -// /** -// * @notice Tests that pledgeForDispute reverts if the maximum number of escalations has been reached. -// */ -// function test_revertIfMaxNumberOfEscalationsReached(bytes32 _disputeId, bytes32 _requestId) public { -// vm.assume(_disputeId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect IOracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// uint256 _bondSize = 1; -// uint256 _maxNumberOfEscalations = 2; -// uint256 _bondEscalationDeadline = block.timestamp - 1; -// uint256 _tyingBuffer = 1000; - -// _setRequestData( -// _requestId, _bondSize, _maxNumberOfEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow -// ); - -// uint256 _numForPledgers = 2; -// uint256 _numAgainstPledgers = _numForPledgers; - -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// // Check: does it revert if the maximum number of escalations is reached? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_MaxNumberOfEscalationsReached.selector); -// bondEscalationModule.pledgeForDispute(_disputeId); -// } - -// /** -// * @notice Tests that pledgeForDispute reverts if someone tries to pledge in favor of the dispute when there are -// * more pledges in favor of the dispute than against -// */ -// function test_revertIfThereIsMorePledgedForForDisputeThanAgainst(bytes32 _disputeId, bytes32 _requestId) public { -// vm.assume(_disputeId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect IOracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// uint256 _bondSize = 1; -// uint256 _maxNumberOfEscalations = 3; -// uint256 _bondEscalationDeadline = block.timestamp + 1; - -// _setRequestData(_requestId, _bondSize, _maxNumberOfEscalations, _bondEscalationDeadline, tyingBuffer, disputeWindow); - -// uint256 _numForPledgers = 2; -// uint256 _numAgainstPledgers = _numForPledgers - 1; - -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// // Check: does it revert if trying to pledge in a dispute that is already surpassed? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_CanOnlySurpassByOnePledge.selector); -// bondEscalationModule.pledgeForDispute(_disputeId); -// } - -// /** -// * @notice Tests that pledgeForDispute reverts if the timestamp is within the tying buffer and someone attempts -// * to pledge when the funds are tied, effectively breaking the tie -// */ -// function test_revertIfAttemptToBreakTieDuringTyingBuffer(bytes32 _disputeId, bytes32 _requestId) public { -// vm.assume(_disputeId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect IOracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// uint256 _bondSize = 1; -// uint256 _maxNumberOfEscalations = 3; -// uint256 _bondEscalationDeadline = block.timestamp - 1; -// uint256 _tyingBuffer = 1000; - -// _setRequestData( -// _requestId, _bondSize, _maxNumberOfEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow -// ); - -// uint256 _numForPledgers = 2; -// uint256 _numAgainstPledgers = _numForPledgers; - -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// // Check: does it revert if trying to tie outside of the tying buffer? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_CannotBreakTieDuringTyingBuffer.selector); -// bondEscalationModule.pledgeForDispute(_disputeId); -// } - -// /** -// * @notice Tests that pledgeForDispute is called successfully -// */ -// function test_successfulCall(bytes32 _disputeId, bytes32 _requestId) public { -// vm.assume(_disputeId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// uint256 _bondSize = 1000; -// uint256 _maxNumberOfEscalations = 3; -// uint256 _bondEscalationDeadline = block.timestamp - 1; -// uint256 _tyingBuffer = 1000; - -// _setRequestData( -// _requestId, _bondSize, _maxNumberOfEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow -// ); - -// uint256 _numForPledgers = 2; -// uint256 _numAgainstPledgers = _numForPledgers + 1; - -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// // Mock and expect IBondEscalationAccounting.pledge to be called -// _mockAndExpect( -// address(accounting), -// abi.encodeCall(IBondEscalationAccounting.pledge, (address(this), _requestId, _disputeId, token, _bondSize)), -// abi.encode(true) -// ); - -// // Check: is event emitted? -// vm.expectEmit(true, true, true, true, address(bondEscalationModule)); -// emit PledgedForDispute(_disputeId, address(this), _bondSize); - -// bondEscalationModule.pledgeForDispute(_disputeId); - -// uint256 _pledgesForDispute = bondEscalationModule.getEscalation(_requestId).amountOfPledgesForDispute; -// // Check: is the number of pledges for the dispute properly updated? -// assertEq(_pledgesForDispute, _numForPledgers + 1); - -// uint256 _userPledges = bondEscalationModule.pledgesForDispute(_requestId, address(this)); -// // Check: is the number of pledges for the user properly updated? -// assertEq(_userPledges, 1); -// } -// } - -// contract BondEscalationModule_Unit_PledgeAgainstDispute is BaseTest { -// /** -// * @notice Tests that pledgeAgainstDispute reverts if the dispute does not exist. -// */ -// function test_revertIfDisputeIsZero() public { -// bytes32 _disputeId = 0; - -// // Check: does it revert if the dispute does not exist? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_DisputeDoesNotExist.selector); -// bondEscalationModule.pledgeAgainstDispute(_disputeId); -// } - -// /** -// * @notice Tests that pledgeAgainstDispute reverts if the dispute is not going through the bond escalation mechanism. -// */ -// function test_revertIfTheDisputeIsNotGoingThroughTheBondEscalationProcess( -// bytes32 _disputeId, -// bytes32 _requestId -// ) public { -// vm.assume(_disputeId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect IOracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// // Check: does it revert if the dispute is not escalated yet? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_InvalidDispute.selector); -// bondEscalationModule.pledgeAgainstDispute(_disputeId); -// } - -// /** -// * @notice Tests that pledgeAgainstDispute reverts if someone tries to pledge after the tying buffer. -// */ -// function test_revertIfTimestampBeyondTyingBuffer(bytes32 _disputeId, bytes32 _requestId) public { -// vm.assume(_disputeId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect IOracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// uint256 _bondSize = 1; -// uint256 _maxNumberOfEscalations = 1; -// uint256 _bondEscalationDeadline = block.timestamp; -// uint256 _tyingBuffer = 1000; - -// vm.warp(_bondEscalationDeadline + _tyingBuffer + 1); - -// _setRequestData( -// _requestId, _bondSize, _maxNumberOfEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow -// ); - -// // Check: does it revert if the bond escalation is over? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_BondEscalationOver.selector); - -// bondEscalationModule.pledgeAgainstDispute(_disputeId); -// } - -// /** -// * @notice Tests that pledgeAgainstDispute reverts if the maximum number of escalations has been reached. -// */ -// function test_revertIfMaxNumberOfEscalationsReached(bytes32 _disputeId, bytes32 _requestId) public { -// vm.assume(_disputeId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect IOracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// uint256 _bondSize = 1; -// uint256 _maxNumberOfEscalations = 2; -// uint256 _bondEscalationDeadline = block.timestamp - 1; -// uint256 _tyingBuffer = 1000; - -// _setRequestData( -// _requestId, _bondSize, _maxNumberOfEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow -// ); - -// uint256 _numForPledgers = 2; -// uint256 _numAgainstPledgers = _numForPledgers; - -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// // Check: does it revert if the maximum number of escalations is reached? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_MaxNumberOfEscalationsReached.selector); - -// bondEscalationModule.pledgeAgainstDispute(_disputeId); -// } - -// /** -// * @notice Tests that pledgeAgainstDispute reverts if someone tries to pledge in favor of the dispute when there are -// * more pledges against of the dispute than in favor of it -// */ -// function test_revertIfThereIsMorePledgedAgainstDisputeThanFor(bytes32 _disputeId, bytes32 _requestId) public { -// vm.assume(_disputeId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect IOracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// uint256 _bondSize = 1; -// uint256 _maxNumberOfEscalations = 3; -// uint256 _bondEscalationDeadline = block.timestamp + 1; - -// _setRequestData(_requestId, _bondSize, _maxNumberOfEscalations, _bondEscalationDeadline, tyingBuffer, disputeWindow); - -// uint256 _numAgainstPledgers = 2; -// uint256 _numForPledgers = _numAgainstPledgers - 1; - -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// // Check: does it revert if trying to pledge in a dispute that is already surpassed? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_CanOnlySurpassByOnePledge.selector); - -// bondEscalationModule.pledgeAgainstDispute(_disputeId); -// } - -// /** -// * @notice Tests that pledgeAgainstDispute reverts if the timestamp is within the tying buffer and someone attempts -// * to pledge when the funds are tied, effectively breaking the tie -// */ -// function test_revertIfAttemptToBreakTieDuringTyingBuffer(bytes32 _disputeId, bytes32 _requestId) public { -// vm.assume(_disputeId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect IOracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// uint256 _bondSize = 1; -// uint256 _maxNumberOfEscalations = 3; -// uint256 _bondEscalationDeadline = block.timestamp - 1; -// uint256 _tyingBuffer = 1000; - -// _setRequestData( -// _requestId, _bondSize, _maxNumberOfEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow -// ); - -// uint256 _numForPledgers = 2; -// uint256 _numAgainstPledgers = _numForPledgers; - -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// // Check: does it revert if trying to tie outside of the tying buffer? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_CannotBreakTieDuringTyingBuffer.selector); -// bondEscalationModule.pledgeAgainstDispute(_disputeId); -// } - -// /** -// * @notice Tests that pledgeAgainstDispute is called successfully -// */ -// function test_successfulCall(bytes32 _disputeId, bytes32 _requestId) public { -// vm.assume(_disputeId > 0); - -// _mockDispute.requestId = _requestId; - -// // Mock and expect IOracle.getDispute to be called -// _mockAndExpect(address(oracle), abi.encodeCall(IOracle.getDispute, (_disputeId)), abi.encode(_mockDispute)); - -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// uint256 _bondSize = 1000; -// uint256 _maxNumberOfEscalations = 3; -// uint256 _bondEscalationDeadline = block.timestamp - 1; -// uint256 _tyingBuffer = 1000; - -// _setRequestData( -// _requestId, _bondSize, _maxNumberOfEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow -// ); - -// uint256 _numAgainstPledgers = 2; -// uint256 _numForPledgers = _numAgainstPledgers + 1; - -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// _mockAndExpect( -// address(accounting), -// abi.encodeCall(IBondEscalationAccounting.pledge, (address(this), _requestId, _disputeId, token, _bondSize)), -// abi.encode(true) -// ); - -// // Check: is the event emitted? -// vm.expectEmit(true, true, true, true, address(bondEscalationModule)); -// emit PledgedAgainstDispute(_disputeId, address(this), _bondSize); - -// bondEscalationModule.pledgeAgainstDispute(_disputeId); - -// uint256 _pledgesForDispute = bondEscalationModule.getEscalation(_requestId).amountOfPledgesAgainstDispute; -// // Check: is the number of pledges for the dispute properly updated? -// assertEq(_pledgesForDispute, _numAgainstPledgers + 1); - -// uint256 _userPledges = bondEscalationModule.pledgesAgainstDispute(_requestId, address(this)); -// // Check: is the number of pledges for the user properly updated? -// assertEq(_userPledges, 1); -// } -// } - -// contract BondEscalationModule_Unit_SettleBondEscalation is BaseTest { -// /** -// * @notice Tests that settleBondEscalation reverts if someone tries to settle the escalation before the tying buffer -// * has elapsed. -// */ -// function test_revertIfTimestampLessThanEndOfTyingBuffer(bytes32 _requestId) public { -// uint256 _bondEscalationDeadline = block.timestamp; -// _setRequestData(_requestId, bondSize, maxEscalations, _bondEscalationDeadline, tyingBuffer, disputeWindow); - -// // Check: does it revert if the bond escalation is not over? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_BondEscalationNotOver.selector); -// bondEscalationModule.settleBondEscalation(_requestId); -// } - -// /** -// * @notice Tests that settleBondEscalation reverts if someone tries to settle a bond-escalated dispute that -// * is not active. -// */ -// function test_revertIfStatusOfBondEscalationIsNotActive(bytes32 _requestId) public { -// uint256 _bondEscalationDeadline = block.timestamp; -// uint256 _tyingBuffer = 1000; - -// vm.warp(_bondEscalationDeadline + _tyingBuffer + 1); - -// _setRequestData(_requestId, bondSize, maxEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow); - -// bondEscalationModule.forTest_setBondEscalationStatus(_requestId, IBondEscalationModule.BondEscalationStatus.None); - -// // Check: does it revert if the bond escalation is not active? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_BondEscalationCantBeSettled.selector); -// bondEscalationModule.settleBondEscalation(_requestId); -// } - -// /** -// * @notice Tests that settleBondEscalation reverts if someone tries to settle a bond-escalated dispute that -// * has the same number of pledgers. -// */ -// function test_revertIfSameNumberOfPledgers(bytes32 _requestId, bytes32 _disputeId) public { -// uint256 _bondEscalationDeadline = block.timestamp; -// uint256 _tyingBuffer = 1000; - -// vm.warp(_bondEscalationDeadline + _tyingBuffer + 1); - -// _setRequestData(_requestId, bondSize, maxEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow); -// bondEscalationModule.forTest_setBondEscalationStatus(_requestId, IBondEscalationModule.BondEscalationStatus.Active); -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// uint256 _numForPledgers = 5; -// uint256 _numAgainstPledgers = _numForPledgers; - -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// // Check: does it revert if the number of pledgers is the same? -// vm.expectRevert(IBondEscalationModule.BondEscalationModule_ShouldBeEscalated.selector); -// bondEscalationModule.settleBondEscalation(_requestId); -// } - -// /** -// * @notice Tests that settleBondEscalation is called successfully. -// */ -// function test_successfulCallDisputerWon(bytes32 _requestId, bytes32 _disputeId) public { -// uint256 _bondSize = 1000; -// uint256 _bondEscalationDeadline = block.timestamp; -// uint256 _tyingBuffer = 1000; - -// vm.warp(_bondEscalationDeadline + _tyingBuffer + 1); - -// _setRequestData(_requestId, _bondSize, maxEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow); -// bondEscalationModule.forTest_setBondEscalationStatus(_requestId, IBondEscalationModule.BondEscalationStatus.Active); -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// uint256 _numForPledgers = 2; -// uint256 _numAgainstPledgers = _numForPledgers - 1; - -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// _mockAndExpect( -// address(oracle), -// abi.encodeCall(IOracle.updateDisputeStatus, (_disputeId, IOracle.DisputeStatus.Won)), -// abi.encode(true) -// ); - -// // Check: is the event emitted? -// vm.expectEmit(true, true, true, true, address(bondEscalationModule)); -// emit BondEscalationStatusUpdated(_requestId, _disputeId, IBondEscalationModule.BondEscalationStatus.DisputerWon); - -// bondEscalationModule.settleBondEscalation(_requestId); -// // Check: is the bond escalation status properly updated? -// assertEq( -// uint256(bondEscalationModule.getEscalation(_requestId).status), -// uint256(IBondEscalationModule.BondEscalationStatus.DisputerWon) -// ); -// } - -// /** -// * @notice Tests that settleBondEscalation is called successfully. -// */ -// function test_successfulCallDisputerLost(bytes32 _requestId, bytes32 _disputeId) public { -// uint256 _bondSize = 1000; -// uint256 _bondEscalationDeadline = block.timestamp; -// uint256 _tyingBuffer = 1000; - -// vm.warp(_bondEscalationDeadline + _tyingBuffer + 1); - -// _setRequestData(_requestId, _bondSize, maxEscalations, _bondEscalationDeadline, _tyingBuffer, disputeWindow); -// bondEscalationModule.forTest_setBondEscalationStatus(_requestId, IBondEscalationModule.BondEscalationStatus.Active); -// bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); - -// uint256 _numAgainstPledgers = 2; -// uint256 _numForPledgers = _numAgainstPledgers - 1; - -// _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); - -// _mockAndExpect( -// address(oracle), -// abi.encodeCall(IOracle.updateDisputeStatus, (_disputeId, IOracle.DisputeStatus.Lost)), -// abi.encode(true) -// ); - -// // Check: is the event emitted? -// vm.expectEmit(true, true, true, true, address(bondEscalationModule)); -// emit BondEscalationStatusUpdated(_requestId, _disputeId, IBondEscalationModule.BondEscalationStatus.DisputerLost); - -// bondEscalationModule.settleBondEscalation(_requestId); -// // Check: is the bond escalation status properly updated? -// assertEq( -// uint256(bondEscalationModule.getEscalation(_requestId).status), -// uint256(IBondEscalationModule.BondEscalationStatus.DisputerLost) -// ); -// } -// } +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.19; + +import 'forge-std/Test.sol'; + +import {Helpers} from '../../../utils/Helpers.sol'; + +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {Strings} from '@openzeppelin/contracts/utils/Strings.sol'; +import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol'; +import {IModule} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IModule.sol'; + +import { + BondEscalationModule, IBondEscalationModule +} from '../../../../contracts/modules/dispute/BondEscalationModule.sol'; + +import {IAccountingExtension} from '../../../../interfaces/extensions/IAccountingExtension.sol'; +import {IBondEscalationAccounting} from '../../../../interfaces/extensions/IBondEscalationAccounting.sol'; + +/** + * @dev Harness to set an entry in the requestData mapping, without triggering setup request hooks + */ +contract ForTest_BondEscalationModule is BondEscalationModule { + constructor(IOracle _oracle) BondEscalationModule(_oracle) {} + + function forTest_setBondEscalation( + bytes32 _requestId, + address[] memory _pledgersForDispute, + address[] memory _pledgersAgainstDispute + ) public { + for (uint256 _i; _i < _pledgersForDispute.length; _i++) { + pledgesForDispute[_requestId][_pledgersForDispute[_i]] += 1; + } + + for (uint256 _i; _i < _pledgersAgainstDispute.length; _i++) { + pledgesAgainstDispute[_requestId][_pledgersAgainstDispute[_i]] += 1; + } + + _escalations[_requestId].amountOfPledgesForDispute += _pledgersForDispute.length; + _escalations[_requestId].amountOfPledgesAgainstDispute += _pledgersAgainstDispute.length; + } + + function forTest_setBondEscalationStatus( + bytes32 _requestId, + BondEscalationModule.BondEscalationStatus _bondEscalationStatus + ) public { + _escalations[_requestId].status = _bondEscalationStatus; + } + + function forTest_setEscalatedDispute(bytes32 _requestId, bytes32 _disputeId) public { + _escalations[_requestId].disputeId = _disputeId; + } +} + +/** + * @title Bonded Response Module Unit tests + */ + +contract BaseTest is Test, Helpers { + // The target contract + ForTest_BondEscalationModule public bondEscalationModule; + // A mock oracle + IOracle public oracle; + // A mock accounting extension + IBondEscalationAccounting public accounting; + // A mock token + IERC20 public token; + // Mock bondSize + uint256 public bondSize; + // Mock max number of escalations + uint256 public maxEscalations; + // Mock bond escalation deadline + uint256 public bondEscalationDeadline; + // Mock tyingBuffer + uint256 public tyingBuffer; + // Mock dispute window + uint256 public disputeWindow; + + // Events + event PledgedForDispute(bytes32 indexed _disputeId, address indexed _pledger, uint256 indexed _amount); + event PledgedAgainstDispute(bytes32 indexed _disputeId, address indexed _pledger, uint256 indexed _amount); + event BondEscalationStatusUpdated( + bytes32 indexed _requestId, bytes32 indexed _disputeId, IBondEscalationModule.BondEscalationStatus _status + ); + event ResponseDisputed( + bytes32 indexed _requestId, + bytes32 indexed _responseId, + bytes32 indexed _disputeId, + IOracle.Dispute _dispute, + uint256 _blockNumber + ); + event DisputeStatusChanged(bytes32 indexed _disputeId, IOracle.Dispute _dispute, IOracle.DisputeStatus _status); + + /** + * @notice Deploy the target and mock oracle+accounting extension + */ + function setUp() public { + oracle = IOracle(makeAddr('Oracle')); + vm.etch(address(oracle), hex'069420'); + + accounting = IBondEscalationAccounting(makeAddr('BondEscalationAccounting')); + vm.etch(address(accounting), hex'069420'); + + token = IERC20(makeAddr('ERC20')); + vm.etch(address(token), hex'069420'); + + // Set to an arbitrary large value to avoid unintended reverts + disputeWindow = type(uint128).max; + + // Avoid starting at 0 for time sensitive tests + vm.warp(123_456); + + mockDispute = IOracle.Dispute({ + disputer: disputer, + responseId: bytes32('response'), + proposer: proposer, + requestId: bytes32('69') + }); + + mockResponse = + IOracle.Response({proposer: proposer, requestId: bytes32('69'), response: abi.encode(bytes32('response'))}); + + bondEscalationModule = new ForTest_BondEscalationModule(oracle); + } + + function _getRandomDispute( + bytes32 _requestId, + IOracle.DisputeStatus _status + ) internal view returns (IOracle.Dispute memory _dispute) { + _dispute = + IOracle.Dispute({disputer: disputer, responseId: bytes32('response'), proposer: proposer, requestId: _requestId}); + } + + function _setBondEscalation( + bytes32 _requestId, + uint256 _numForPledgers, + uint256 _numAgainstPledgers + ) internal returns (address[] memory _forPledgers, address[] memory _againstPledgers) { + _forPledgers = new address[](_numForPledgers); + _againstPledgers = new address[](_numAgainstPledgers); + address _forPledger; + address _againstPledger; + + for (uint256 _i; _i < _numForPledgers; _i++) { + _forPledger = makeAddr(string.concat('forPledger', Strings.toString(_i))); + _forPledgers[_i] = _forPledger; + } + + for (uint256 _j; _j < _numAgainstPledgers; _j++) { + _againstPledger = makeAddr(string.concat('againstPledger', Strings.toString(_j))); + _againstPledgers[_j] = _againstPledger; + } + + bondEscalationModule.forTest_setBondEscalation(_requestId, _forPledgers, _againstPledgers); + + return (_forPledgers, _againstPledgers); + } +} + +contract BondEscalationModule_Unit_ModuleData is BaseTest { + /** + * @notice Test that the moduleName function returns the correct name + */ + function test_moduleName() public { + assertEq(bondEscalationModule.moduleName(), 'BondEscalationModule'); + } + + /** + * @notice Tests that decodeRequestData decodes the data correctly + */ + function test_decodeRequestDataReturnTheCorrectData(IBondEscalationModule.RequestParameters memory _params) + public + assumeFuzzable(address(_params.accountingExtension)) + { + mockRequest.disputeModuleData = abi.encode(_params); + + IBondEscalationModule.RequestParameters memory _decodedParams = + bondEscalationModule.decodeRequestData(mockRequest.disputeModuleData); + + // Check: does the stored data match the provided one? + assertEq(address(_params.accountingExtension), address(_decodedParams.accountingExtension)); + assertEq(address(_params.bondToken), address(_decodedParams.bondToken)); + assertEq(_params.bondSize, _decodedParams.bondSize); + assertEq(_params.maxNumberOfEscalations, _decodedParams.maxNumberOfEscalations); + assertEq(_params.bondEscalationDeadline, _decodedParams.bondEscalationDeadline); + assertEq(_params.tyingBuffer, _decodedParams.tyingBuffer); + assertEq(_params.disputeWindow, _decodedParams.disputeWindow); + } +} + +contract BondEscalationModule_Unit_EscalateDispute is BaseTest { + /** + * @notice Tests that escalateDispute reverts if a dispute is escalated before the bond escalation deadline is over. + * Conditions to reach this check: + * - The _requestId tied to the dispute tied to _disputeId must be valid (non-zero) + * - The block.timestamp has to be <= bond escalation deadline + */ + function test_revertEscalationDuringBondEscalation(IBondEscalationModule.RequestParameters memory _params) + public + assumeFuzzable(address(_params.accountingExtension)) + { + // Set _bondEscalationDeadline to be the current timestamp to reach the second condition. + _params.bondEscalationDeadline = block.timestamp; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + _mockAndExpect( + address(oracle), abi.encodeCall(IOracle.disputeStatus, (_disputeId)), abi.encode(IOracle.DisputeStatus.Escalated) + ); + + // Setting this dispute as the one going through the bond escalation process, as the user can only + // dispute once before the bond escalation deadline is over, and that dispute goes through the escalation module. + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + // Check: does it revert if the bond escalation is not over yet? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_BondEscalationNotOver.selector); + vm.prank(address(oracle)); + bondEscalationModule.onDisputeStatusChange(_disputeId, mockRequest, mockResponse, mockDispute); + } + + /** + * @notice Tests that escalateDispute reverts if a dispute that went through the bond escalation mechanism but isn't active + * anymore is escalated. + * Conditions to reach this check: + * - The _requestId tied to the dispute tied to _disputeId must be valid (non-zero) + * - The block.timestamp has to be > bond escalation deadline + * - The dispute has to have gone through the bond escalation process before + * - The status of the bond escalation mechanism has to be different from Active + */ + function test_revertIfEscalatingNonActiveDispute( + uint8 _status, + IBondEscalationModule.RequestParameters memory _params + ) public assumeFuzzable(address(_params.accountingExtension)) { + // Assume the status will be any available other but Active + vm.assume(_status != uint8(IBondEscalationModule.BondEscalationStatus.Active) && _status < 4); + + _params.accountingExtension = IBondEscalationAccounting(makeAddr('BondEscalationAccounting')); + // Set a tying buffer to show that this can happen even in the tying buffer if the dispute was settled + _params.tyingBuffer = 1000; + // Make the current timestamp be greater than the bond escalation deadline + _params.bondEscalationDeadline = block.timestamp - 1; + + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + // Set the bond escalation status of the given requestId to something different than Active + bondEscalationModule.forTest_setBondEscalationStatus( + _requestId, IBondEscalationModule.BondEscalationStatus(_status) + ); + + _mockAndExpect( + address(oracle), abi.encodeCall(IOracle.disputeStatus, (_disputeId)), abi.encode(IOracle.DisputeStatus.Escalated) + ); + + // Set the dispute to be the one that went through the bond escalation process for the given requestId + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + // Check: does it revert if the dispute is not escalatable? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_NotEscalatable.selector); + vm.prank(address(oracle)); + bondEscalationModule.onDisputeStatusChange(_disputeId, mockRequest, mockResponse, mockDispute); + } + + /** + * @notice Tests that escalateDispute reverts if a dispute that went through the bond escalation mechanism and is still active + * but its pledges are not tied even after the tying buffer is escalated. + * Conditions to reach this check: + * - The _requestId tied to the dispute tied to _disputeId must be valid (non-zero) + * - The block.timestamp has to be > bond escalation deadline + tying buffer + * - The dispute has to have gone or be going through the bond escalation process + * - The pledges must not be tied + */ + function test_revertIfEscalatingDisputeIsNotTied(IBondEscalationModule.RequestParameters memory _params) + public + assumeFuzzable(address(_params.accountingExtension)) + { + // Set a tying buffer to make the test more explicit + _params.tyingBuffer = 1000; + // Set bond escalation deadline to be the current timestamp. We will warp this. + _params.bondEscalationDeadline = block.timestamp; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + // Set the number of pledgers to be different + uint256 _numForPledgers = 1; + uint256 _numAgainstPledgers = 2; + + // Warp the current timestamp so we are past the tyingBuffer + vm.warp(_params.bondEscalationDeadline + _params.tyingBuffer + 1); + + // Set the bond escalation status of the given requestId to Active + bondEscalationModule.forTest_setBondEscalationStatus(_requestId, IBondEscalationModule.BondEscalationStatus.Active); + + // Set the dispute to be the one that went through the bond escalation process for the given requestId + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + // Set the number of pledgers for both sides + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + _mockAndExpect( + address(oracle), abi.encodeCall(IOracle.disputeStatus, (_disputeId)), abi.encode(IOracle.DisputeStatus.Escalated) + ); + + // Check: does it revert if the dispute is not escalatable? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_NotEscalatable.selector); + vm.prank(address(oracle)); + bondEscalationModule.onDisputeStatusChange(_disputeId, mockRequest, mockResponse, mockDispute); + } + + /** + * @notice Tests that escalateDispute escalates the dispute going through the bond escalation mechanism correctly when the + * pledges are tied and the dispute is still active. + * Conditions for the function to succeed: + * - The _requestId tied to the dispute tied to _disputeId must be valid (non-zero) + * - The block.timestamp has to be > bond escalation deadline + * - The dispute has to have gone or be going through the bond escalation process + * - The pledges must be tied + */ + function test_escalateTiedDispute( + address _proposer, + address _disputer, + IBondEscalationModule.RequestParameters memory _params + ) public assumeFuzzable(address(_params.accountingExtension)) { + // Set bond escalation deadline to be the current timestamp. We will warp this. + _params.bondEscalationDeadline = block.timestamp; + // Set a tying buffer + _params.tyingBuffer = 1000; + _params.accountingExtension = IBondEscalationAccounting(makeAddr('BondEscalationAccounting')); + + mockRequest.disputeModuleData = abi.encode(_params); + bytes32 _requestId = _getId(mockRequest); + + mockResponse.requestId = _requestId; + mockResponse.proposer = _proposer; + bytes32 _responseId = _getId(mockResponse); + + mockDispute.requestId = _requestId; + mockDispute.responseId = _responseId; + mockDispute.proposer = _proposer; + mockDispute.disputer = _disputer; + bytes32 _disputeId = _getId(mockDispute); + + // Set the number of pledgers to be the same. This means the pledges are tied. + uint256 _numForPledgers = 2; + uint256 _numAgainstPledgers = 2; + + // Warp so we are still in the tying buffer period. This is to show a dispute can be escalated during the buffer if the pledges are tied. + vm.warp(_params.bondEscalationDeadline + _params.tyingBuffer); + + // Set the bond escalation status of the given requestId to Active + bondEscalationModule.forTest_setBondEscalationStatus(_requestId, IBondEscalationModule.BondEscalationStatus.Active); + + // Set the dispute to be the one that went through the bond escalation process for the given requestId + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + // Set the number of pledgers for both sides + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + // Check: is the event emitted? + vm.expectEmit(true, true, true, true, address(bondEscalationModule)); + emit BondEscalationStatusUpdated(_requestId, _disputeId, IBondEscalationModule.BondEscalationStatus.Escalated); + + // Mock and expect IOracle.createdAt to be called + _mockAndExpect( + address(oracle), abi.encodeCall(IOracle.disputeStatus, (_disputeId)), abi.encode(IOracle.DisputeStatus.Escalated) + ); + + vm.prank(address(oracle)); + bondEscalationModule.onDisputeStatusChange(_disputeId, mockRequest, mockResponse, mockDispute); + + IBondEscalationModule.BondEscalation memory _escalation = bondEscalationModule.getEscalation(_requestId); + // Check: is the bond escalation status properly updated? + assertEq(uint256(_escalation.status), uint256(IBondEscalationModule.BondEscalationStatus.Escalated)); + } +} + +contract BondEscalationModule_Unit_DisputeResponse is BaseTest { + /** + * @notice Tests that disputeResponse reverts the caller is not the oracle address. + */ + function test_revertIfCallerIsNotOracle( + bytes32 _requestId, + bytes32 _responseId, + address _caller, + IOracle.Request calldata _request + ) public { + vm.assume(_caller != address(oracle)); + + // Check: does it revert if not called by the Oracle? + vm.expectRevert(IModule.Module_OnlyOracle.selector); + vm.prank(_caller); + bondEscalationModule.disputeResponse(_request, mockResponse, mockDispute); + } + + /** + * @notice Tests that disputeResponse reverts if the challenge period for the response is over. + */ + function test_revertIfDisputeWindowIsOver( + uint128 _disputeWindow, + IBondEscalationModule.RequestParameters memory _params + ) public assumeFuzzable(address(_params.accountingExtension)) { + // Set mock request data + _params.disputeWindow = _disputeWindow; + mockRequest.disputeModuleData = abi.encode(_params); + + // Compute proper IDs + bytes32 _requestId = _getId(mockRequest); + mockResponse.requestId = _requestId; + + bytes32 _responseId = _getId(mockResponse); + mockDispute.requestId = _requestId; + mockDispute.responseId = _responseId; + + // Warp to a time after the disputeWindow is over. + vm.warp(block.timestamp + _disputeWindow + 1); + + // Mock and expect IOracle.createdAt to be called + _mockAndExpect(address(oracle), abi.encodeCall(IOracle.createdAt, (_responseId)), abi.encode(1)); + + // Check: does it revert if the dispute window is over? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_DisputeWindowOver.selector); + vm.prank(address(oracle)); + bondEscalationModule.disputeResponse(mockRequest, mockResponse, mockDispute); + } + + /** + * @notice Tests that disputeResponse succeeds if someone dispute after the bond escalation deadline is over + */ + function test_succeedIfDisputeAfterBondingEscalationDeadline( + uint256 _timestamp, + IBondEscalationModule.RequestParameters memory _params + ) public assumeFuzzable(address(_params.accountingExtension)) { + _timestamp = bound(_timestamp, 1, type(uint128).max); + // Set deadline to timestamp so we are still in the bond escalation period + _params.bondEscalationDeadline = _timestamp - 1; + _params.disputeWindow = _timestamp + 1; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockResponse.requestId = _requestId; + + bytes32 _responseId = _getId(mockResponse); + + mockDispute.responseId = _responseId; + mockDispute.requestId = _requestId; + + // Mock and expect IOracle.createdAt to be called + _mockAndExpect(address(oracle), abi.encodeCall(IOracle.createdAt, (_responseId)), abi.encode(1)); + + vm.warp(_timestamp); + // Check: does it revert if the bond escalation is over? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_BondEscalationOver.selector); + vm.prank(address(oracle)); + bondEscalationModule.disputeResponse(mockRequest, mockResponse, mockDispute); + } + + /** + * @notice Tests that disputeResponse succeeds in starting the bond escalation mechanism when someone disputes + * the first propose before the bond escalation deadline is over. + */ + function test_firstDisputeThroughBondMechanism( + address _disputer, + IBondEscalationModule.RequestParameters memory _params + ) public assumeFuzzable(address(_params.accountingExtension)) { + // Set deadline to timestamp so we are still in the bond escalation period + _params.disputeWindow = block.timestamp; + _params.bondEscalationDeadline = block.timestamp; + + // Compute proper IDs + mockRequest.disputeModuleData = abi.encode(_params); + bytes32 _requestId = _getId(mockRequest); + + mockResponse.requestId = _requestId; + bytes32 _responseId = _getId(mockResponse); + + mockDispute.disputer = _disputer; + mockDispute.responseId = _responseId; + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + // Mock and expect the accounting extension to be called + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeWithSignature( + 'bond(address,bytes32,address,uint256)', _disputer, _requestId, _params.bondToken, _params.bondSize + ), + abi.encode(true) + ); + + // Mock and expect IOracle.createdAt to be called + _mockAndExpect(address(oracle), abi.encodeCall(IOracle.createdAt, (_responseId)), abi.encode(1)); + + // Check: is the event emitted? + vm.expectEmit(true, true, true, true, address(bondEscalationModule)); + emit BondEscalationStatusUpdated(_requestId, _disputeId, IBondEscalationModule.BondEscalationStatus.Active); + + vm.expectEmit(true, true, true, true, address(bondEscalationModule)); + emit ResponseDisputed({ + _requestId: _requestId, + _responseId: _responseId, + _disputeId: _disputeId, + _dispute: mockDispute, + _blockNumber: block.number + }); + + vm.prank(address(oracle)); + bondEscalationModule.disputeResponse(mockRequest, mockResponse, mockDispute); + + // Check: is the bond escalation status now active? + assertEq( + uint256(bondEscalationModule.getEscalation(_requestId).status), + uint256(IBondEscalationModule.BondEscalationStatus.Active) + ); + + // Check: is the dispute assigned to the bond escalation process? + assertEq(bondEscalationModule.getEscalation(_requestId).disputeId, _disputeId); + } + + function test_emitsEvent( + address _disputer, + address _proposer, + IBondEscalationModule.RequestParameters memory _params + ) public assumeFuzzable(address(_params.accountingExtension)) { + _params.disputeWindow = block.timestamp; + _params.bondEscalationDeadline = block.timestamp; + + // Compute proper IDs + mockRequest.disputeModuleData = abi.encode(_params); + bytes32 _requestId = _getId(mockRequest); + + mockResponse.requestId = _requestId; + mockResponse.proposer = _proposer; + bytes32 _responseId = _getId(mockResponse); + + mockDispute.disputer = _disputer; + mockDispute.requestId = _requestId; + mockDispute.responseId = _responseId; + bytes32 _disputeId = _getId(mockDispute); + + // Mock and expect IOracle.createdAt to be called + _mockAndExpect(address(oracle), abi.encodeCall(IOracle.createdAt, (_responseId)), abi.encode(1)); + + // Mock and expect the accounting extension to be called + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeWithSignature( + 'bond(address,bytes32,address,uint256)', _disputer, _requestId, _params.bondToken, _params.bondSize + ), + abi.encode(true) + ); + + // Check: is the event emitted? + vm.expectEmit(true, true, true, true, address(bondEscalationModule)); + emit ResponseDisputed(_requestId, _responseId, _disputeId, mockDispute, block.number); + + vm.prank(address(oracle)); + bondEscalationModule.disputeResponse(mockRequest, mockResponse, mockDispute); + } +} + +contract BondEscalationModule_Unit_OnDisputeStatusChange is BaseTest { + /** + * @notice Tests that onDisputeStatusChange reverts + */ + function test_revertIfCallerIsNotOracle( + bytes32 _disputeId, + bytes32 _requestId, + address _caller, + uint8 _status, + IOracle.Request calldata _request + ) public { + vm.assume(_caller != address(oracle)); + vm.assume(_status < 4); + + IOracle.DisputeStatus _disputeStatus = IOracle.DisputeStatus(_status); + IOracle.Dispute memory _dispute = _getRandomDispute(_requestId, _disputeStatus); + + // Check: does it revert if not called by the Oracle? + vm.expectRevert(IModule.Module_OnlyOracle.selector); + vm.prank(_caller); + bondEscalationModule.onDisputeStatusChange(_disputeId, _request, mockResponse, mockDispute); + } + + /** + * @notice Tests that onDisputeStatusChange pays the proposer if the disputer lost + */ + function test_callPayIfNormalDisputeLost(IBondEscalationModule.RequestParameters memory _params) + public + assumeFuzzable(address(_params.accountingExtension)) + { + _params.accountingExtension = IBondEscalationAccounting(makeAddr('BondEscalationAccounting')); + mockRequest.disputeModuleData = abi.encode(_params); + bytes32 _requestId = _getId(mockRequest); + + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + // Mock and expect IAccountingExtension.pay to be called + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeCall( + IAccountingExtension.pay, + (_requestId, mockDispute.disputer, mockDispute.proposer, _params.bondToken, _params.bondSize) + ), + abi.encode(true) + ); + + // Mock and expect IOracle.createdAt to be called + _mockAndExpect( + address(oracle), abi.encodeCall(IOracle.disputeStatus, (_disputeId)), abi.encode(IOracle.DisputeStatus.Lost) + ); + + vm.prank(address(oracle)); + bondEscalationModule.onDisputeStatusChange(_disputeId, mockRequest, mockResponse, mockDispute); + } + + /** + * @notice Tests that onDisputeStatusChange pays the disputer if the disputer won + */ + function test_callPayIfNormalDisputeWon(IBondEscalationModule.RequestParameters memory _params) + public + assumeFuzzable(address(_params.accountingExtension)) + { + _params.accountingExtension = IBondEscalationAccounting(makeAddr('BondEscalationAccounting')); + mockRequest.disputeModuleData = abi.encode(_params); + bytes32 _requestId = _getId(mockRequest); + + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + // Mock and expect IAccountingExtension.pay to be called + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeCall( + IAccountingExtension.pay, + (_requestId, mockDispute.proposer, mockDispute.disputer, _params.bondToken, _params.bondSize) + ), + abi.encode(true) + ); + + // Mock and expect IAccountingExtension.pay to be called + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeCall( + IAccountingExtension.release, (mockDispute.disputer, _requestId, _params.bondToken, _params.bondSize) + ), + abi.encode(true) + ); + + // Mock and expect IOracle.createdAt to be called + _mockAndExpect( + address(oracle), abi.encodeCall(IOracle.disputeStatus, (_disputeId)), abi.encode(IOracle.DisputeStatus.Won) + ); + + vm.prank(address(oracle)); + bondEscalationModule.onDisputeStatusChange(_disputeId, mockRequest, mockResponse, mockDispute); + } + + function test_emitsEvent(IBondEscalationModule.RequestParameters memory _params) + public + assumeFuzzable(address(_params.accountingExtension)) + { + IOracle.DisputeStatus _status = IOracle.DisputeStatus.Won; + + mockRequest.disputeModuleData = abi.encode(_params); + bytes32 _requestId = _getId(mockRequest); + + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + // Mock and expect IOracle.createdAt to be called + _mockAndExpect(address(oracle), abi.encodeCall(IOracle.disputeStatus, (_disputeId)), abi.encode(_status)); + + // Mock and expect IAccountingExtension.pay to be called + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeCall( + IAccountingExtension.pay, + (_requestId, mockDispute.proposer, mockDispute.disputer, _params.bondToken, _params.bondSize) + ), + abi.encode(true) + ); + + // Mock and expect IAccountingExtension.release to be called + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeCall( + IAccountingExtension.release, (mockDispute.disputer, _requestId, _params.bondToken, _params.bondSize) + ), + abi.encode(true) + ); + + // Check: is the event emitted? + // TODO: fix event emission in module + // vm.expectEmit(true, true, true, true, address(bondEscalationModule)); + // emit DisputeStatusChanged(_disputeId, mockDispute, IOracle.DisputeStatus.Won); + + vm.prank(address(oracle)); + bondEscalationModule.onDisputeStatusChange(_disputeId, mockRequest, mockResponse, mockDispute); + } + + /** + * @notice Tests that onDisputeStatusChange returns early if the dispute has gone through the bond + * escalation mechanism but no one pledged + */ + function test_earlyReturnIfBondEscalatedDisputeHashNoPledgers(IBondEscalationModule.RequestParameters memory _params) + public + assumeFuzzable(address(_params.accountingExtension)) + { + mockRequest.disputeModuleData = abi.encode(_params); + bytes32 _requestId = _getId(mockRequest); + + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + uint256 _numForPledgers = 0; + uint256 _numAgainstPledgers = 0; + + // Set bond escalation data to have no pledgers + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + // Set this dispute to have gone through the bond escalation process + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + // Set the bond escalation status to Escalated, which is the only possible one for this function + bondEscalationModule.forTest_setBondEscalationStatus( + _requestId, IBondEscalationModule.BondEscalationStatus.Escalated + ); + + // Mock and expect IOracle.createdAt to be called + _mockAndExpect( + address(oracle), abi.encodeCall(IOracle.disputeStatus, (_disputeId)), abi.encode(IOracle.DisputeStatus.Won) + ); + + // Mock and expect IAccountingExtension.pay to be called + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeCall( + IAccountingExtension.pay, + (_requestId, mockDispute.proposer, mockDispute.disputer, _params.bondToken, _params.bondSize) + ), + abi.encode(true) + ); + + // Mock and expect IAccountingExtension.release to be called + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeCall( + IAccountingExtension.release, (mockDispute.disputer, _requestId, _params.bondToken, _params.bondSize) + ), + abi.encode(true) + ); + + vm.prank(address(oracle)); + bondEscalationModule.onDisputeStatusChange(_disputeId, mockRequest, mockResponse, mockDispute); + + // Check: is the bond escalation status properly updated? + assertEq( + uint256(bondEscalationModule.getEscalation(_requestId).status), + uint256(IBondEscalationModule.BondEscalationStatus.Escalated) + ); + } + + /** + * @notice Tests that onDisputeStatusChange changes the status of the bond escalation if the + * dispute went through the bond escalation process, as well as testing that it calls + * payPledgersWon with the correct arguments. In the Won case, this would be, passing + * the users that pledged in favor of the dispute, as they have won. + */ + function test_shouldChangeBondEscalationStatusAndCallPayPledgersWon( + IBondEscalationModule.RequestParameters memory _params + ) public assumeFuzzable(address(_params.accountingExtension)) { + IOracle.DisputeStatus _status = IOracle.DisputeStatus.Won; + + mockRequest.disputeModuleData = abi.encode(_params); + bytes32 _requestId = _getId(mockRequest); + + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + uint256 _numForPledgers = 2; + uint256 _numAgainstPledgers = 2; + + // Set bond escalation data to have pledgers and to return the winning for pledgers as in this case they won the escalation + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + // Set this dispute to have gone through the bond escalation process + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + // Set the bond escalation status to Escalated, which is the only possible one for this function + bondEscalationModule.forTest_setBondEscalationStatus( + _requestId, IBondEscalationModule.BondEscalationStatus.Escalated + ); + + // Mock and expect IOracle.createdAt to be called + _mockAndExpect(address(oracle), abi.encodeCall(IOracle.disputeStatus, (_disputeId)), abi.encode(_status)); + + // Mock and expect IAccountingExtension.pay to be called + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeCall( + IAccountingExtension.pay, + (_requestId, mockDispute.proposer, mockDispute.disputer, _params.bondToken, _params.bondSize) + ), + abi.encode(true) + ); + + // Mock and expect IAccountingExtension.release to be called + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeCall( + IAccountingExtension.release, (mockDispute.disputer, _requestId, _params.bondToken, _params.bondSize) + ), + abi.encode(true) + ); + + // Mock and expect IBondEscalationAccounting.onSettleBondEscalation to be called + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeCall( + IBondEscalationAccounting.onSettleBondEscalation, + (_requestId, _disputeId, true, _params.bondToken, _params.bondSize << 1, _numForPledgers) + ), + abi.encode() + ); + + // Check: is the event emitted? + vm.expectEmit(true, true, true, true, address(bondEscalationModule)); + emit BondEscalationStatusUpdated(_requestId, _disputeId, IBondEscalationModule.BondEscalationStatus.DisputerWon); + + vm.prank(address(oracle)); + bondEscalationModule.onDisputeStatusChange(_disputeId, mockRequest, mockResponse, mockDispute); + + // Check: is the bond escalation status properly updated? + assertEq( + uint256(bondEscalationModule.getEscalation(_requestId).status), + uint256(IBondEscalationModule.BondEscalationStatus.DisputerWon) + ); + } + + /** + * @notice Tests that onDisputeStatusChange changes the status of the bond escalation if the + * dispute went through the bond escalation process, as well as testing that it calls + * payPledgersWon with the correct arguments. In the Lost case, this would be, passing + * the users that pledged against the dispute, as those that pledged in favor have lost . + */ + function test_shouldChangeBondEscalationStatusAndCallPayPledgersLost( + IBondEscalationModule.RequestParameters memory _params + ) public assumeFuzzable(address(_params.accountingExtension)) { + // Set to Lost so the proposer and againstDisputePledgers win + IOracle.DisputeStatus _status = IOracle.DisputeStatus.Lost; + mockRequest.disputeModuleData = abi.encode(_params); + bytes32 _requestId = _getId(mockRequest); + + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + uint256 _numForPledgers = 2; + uint256 _numAgainstPledgers = 2; + + // Set bond escalation data to have pledgers and to return the winning for pledgers as in this case they won the escalation + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + // Set this dispute to have gone through the bond escalation process + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + // Set the bond escalation status to Escalated, which is the only possible one for this function + bondEscalationModule.forTest_setBondEscalationStatus( + _requestId, IBondEscalationModule.BondEscalationStatus.Escalated + ); + + // Mock and expect IOracle.createdAt to be called + _mockAndExpect(address(oracle), abi.encodeCall(IOracle.disputeStatus, (_disputeId)), abi.encode(_status)); + + // Mock and expect IAccountingExtension.pay to be called + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeCall( + IAccountingExtension.pay, + (_requestId, mockDispute.disputer, mockDispute.proposer, _params.bondToken, _params.bondSize) + ), + abi.encode(true) + ); + + // Mock and expect IBondEscalationAccounting.onSettleBondEscalation to be called + vm.mockCall( + address(_params.accountingExtension), + abi.encodeCall( + IBondEscalationAccounting.onSettleBondEscalation, + (_requestId, _disputeId, false, _params.bondToken, _params.bondSize << 1, _numAgainstPledgers) + ), + abi.encode(true) + ); + + // Check: is th event emitted? + vm.expectEmit(true, true, true, true, address(bondEscalationModule)); + emit BondEscalationStatusUpdated(_requestId, _disputeId, IBondEscalationModule.BondEscalationStatus.DisputerLost); + + vm.prank(address(oracle)); + bondEscalationModule.onDisputeStatusChange(_disputeId, mockRequest, mockResponse, mockDispute); + + // Check: is the bond escalation status properly updated? + assertEq( + uint256(bondEscalationModule.getEscalation(_requestId).status), + uint256(IBondEscalationModule.BondEscalationStatus.DisputerLost) + ); + } +} + +contract BondEscalationModule_Unit_PledgeForDispute is BaseTest { + /** + * @notice Tests that pledgeForDispute reverts if the dispute is not going through the bond escalation mechanism. + */ + function test_revertIfTheDisputeIsNotGoingThroughTheBondEscalationProcess( + bytes32 _disputeId, + bytes32 _requestId, + IOracle.Request calldata _request + ) public { + vm.assume(_disputeId > 0); + + mockDispute.requestId = _requestId; + + // Check: does it revert if the dispute is not escalated yet? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_InvalidDispute.selector); + bondEscalationModule.pledgeForDispute(_request, mockDispute); + } + + /** + * @notice Tests that pledgeForDispute reverts if someone tries to pledge after the tying buffer. + */ + function test_revertIfTimestampBeyondTyingBuffer(IBondEscalationModule.RequestParameters memory _params) + public + assumeFuzzable(address(_params.accountingExtension)) + { + _params.bondSize = 1; + _params.maxNumberOfEscalations = 1; + _params.bondEscalationDeadline = block.timestamp; + _params.tyingBuffer = 1000; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + vm.warp(_params.bondEscalationDeadline + _params.tyingBuffer + 1); + + // Check: does it revert if the bond escalation is over? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_BondEscalationOver.selector); + bondEscalationModule.pledgeForDispute(mockRequest, mockDispute); + } + + /** + * @notice Tests that pledgeForDispute reverts if the maximum number of escalations has been reached. + */ + function test_revertIfMaxNumberOfEscalationsReached(IBondEscalationModule.RequestParameters memory _params) + public + assumeFuzzable(address(_params.accountingExtension)) + { + _params.bondSize = 1; + _params.maxNumberOfEscalations = 2; + _params.bondEscalationDeadline = block.timestamp - 1; + _params.tyingBuffer = 1000; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + uint256 _numForPledgers = 2; + uint256 _numAgainstPledgers = _numForPledgers; + + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + // Check: does it revert if the maximum number of escalations is reached? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_MaxNumberOfEscalationsReached.selector); + bondEscalationModule.pledgeForDispute(mockRequest, mockDispute); + } + + /** + * @notice Tests that pledgeForDispute reverts if someone tries to pledge in favor of the dispute when there are + * more pledges in favor of the dispute than against + */ + function test_revertIfThereIsMorePledgedForForDisputeThanAgainst( + IBondEscalationModule.RequestParameters memory _params + ) public assumeFuzzable(address(_params.accountingExtension)) { + _params.tyingBuffer = bound(_params.tyingBuffer, 0, type(uint128).max); + _params.bondSize = 1; + _params.maxNumberOfEscalations = 3; + _params.bondEscalationDeadline = block.timestamp + 1; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + uint256 _numForPledgers = 2; + uint256 _numAgainstPledgers = _numForPledgers - 1; + + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + // Check: does it revert if trying to pledge in a dispute that is already surpassed? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_CanOnlySurpassByOnePledge.selector); + bondEscalationModule.pledgeForDispute(mockRequest, mockDispute); + } + + /** + * @notice Tests that pledgeForDispute reverts if the timestamp is within the tying buffer and someone attempts + * to pledge when the funds are tied, effectively breaking the tie + */ + function test_revertIfAttemptToBreakTieDuringTyingBuffer(IBondEscalationModule.RequestParameters memory _params) + public + { + _params.bondSize = 1; + _params.maxNumberOfEscalations = 3; + _params.bondEscalationDeadline = block.timestamp - 1; + _params.tyingBuffer = 1000; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + uint256 _numForPledgers = 2; + uint256 _numAgainstPledgers = _numForPledgers; + + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + // Check: does it revert if trying to tie outside of the tying buffer? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_CannotBreakTieDuringTyingBuffer.selector); + bondEscalationModule.pledgeForDispute(mockRequest, mockDispute); + } + + /** + * @notice Tests that pledgeForDispute is called successfully + */ + function test_successfulCall(IBondEscalationModule.RequestParameters memory _params) public { + _params.bondSize = 1000; + _params.maxNumberOfEscalations = 3; + _params.bondEscalationDeadline = block.timestamp - 1; + _params.tyingBuffer = 1000; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + // Mock and expect + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + uint256 _numForPledgers = 2; + uint256 _numAgainstPledgers = _numForPledgers + 1; + + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + // Mock and expect IBondEscalationAccounting.pledge to be called + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeCall( + IBondEscalationAccounting.pledge, (address(this), _requestId, _disputeId, _params.bondToken, _params.bondSize) + ), + abi.encode(true) + ); + + // Check: is event emitted? + vm.expectEmit(true, true, true, true, address(bondEscalationModule)); + emit PledgedForDispute(_disputeId, address(this), _params.bondSize); + + bondEscalationModule.pledgeForDispute(mockRequest, mockDispute); + + uint256 _pledgesForDispute = bondEscalationModule.getEscalation(_requestId).amountOfPledgesForDispute; + // Check: is the number of pledges for the dispute properly updated? + assertEq(_pledgesForDispute, _numForPledgers + 1); + + uint256 _userPledges = bondEscalationModule.pledgesForDispute(_requestId, address(this)); + // Check: is the number of pledges for the user properly updated? + assertEq(_userPledges, 1); + } +} + +contract BondEscalationModule_Unit_PledgeAgainstDispute is BaseTest { + /** + * @notice Tests that pledgeAgainstDispute reverts if the dispute is not going through the bond escalation mechanism. + */ + function test_revertIfTheDisputeIsNotGoingThroughTheBondEscalationProcess( + bytes32 _disputeId, + bytes32 _requestId, + IOracle.Request calldata _request + ) public { + vm.assume(_disputeId > 0); + + mockDispute.requestId = _requestId; + + // Check: does it revert if the dispute is not escalated yet? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_InvalidDispute.selector); + bondEscalationModule.pledgeAgainstDispute(_request, mockDispute); + } + + /** + * @notice Tests that pledgeAgainstDispute reverts if someone tries to pledge after the tying buffer. + */ + function test_revertIfTimestampBeyondTyingBuffer(IBondEscalationModule.RequestParameters memory _params) public { + _params.bondSize = 1; + _params.maxNumberOfEscalations = 1; + _params.bondEscalationDeadline = block.timestamp; + _params.tyingBuffer = 1000; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + vm.warp(_params.bondEscalationDeadline + _params.tyingBuffer + 1); + + // Check: does it revert if the bond escalation is over? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_BondEscalationOver.selector); + + bondEscalationModule.pledgeAgainstDispute(mockRequest, mockDispute); + } + + /** + * @notice Tests that pledgeAgainstDispute reverts if the maximum number of escalations has been reached. + */ + function test_revertIfMaxNumberOfEscalationsReached(IBondEscalationModule.RequestParameters memory _params) public { + _params.bondSize = 1; + _params.maxNumberOfEscalations = 2; + _params.bondEscalationDeadline = block.timestamp - 1; + _params.tyingBuffer = 1000; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + uint256 _numForPledgers = 2; + uint256 _numAgainstPledgers = _numForPledgers; + + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + // Check: does it revert if the maximum number of escalations is reached? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_MaxNumberOfEscalationsReached.selector); + + bondEscalationModule.pledgeAgainstDispute(mockRequest, mockDispute); + } + + /** + * @notice Tests that pledgeAgainstDispute reverts if someone tries to pledge in favor of the dispute when there are + * more pledges against of the dispute than in favor of it + */ + function test_revertIfThereIsMorePledgedAgainstDisputeThanFor(IBondEscalationModule.RequestParameters memory _params) + public + { + _params.tyingBuffer = bound(_params.tyingBuffer, 0, type(uint128).max); + _params.bondSize = 1; + _params.maxNumberOfEscalations = 3; + _params.bondEscalationDeadline = block.timestamp + 1; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + uint256 _numAgainstPledgers = 2; + uint256 _numForPledgers = _numAgainstPledgers - 1; + + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + // Check: does it revert if trying to pledge in a dispute that is already surpassed? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_CanOnlySurpassByOnePledge.selector); + + bondEscalationModule.pledgeAgainstDispute(mockRequest, mockDispute); + } + + /** + * @notice Tests that pledgeAgainstDispute reverts if the timestamp is within the tying buffer and someone attempts + * to pledge when the funds are tied, effectively breaking the tie + */ + function test_revertIfAttemptToBreakTieDuringTyingBuffer(IBondEscalationModule.RequestParameters memory _params) + public + { + // Set mock request parameters + _params.bondSize = 1; + _params.maxNumberOfEscalations = 3; + _params.bondEscalationDeadline = block.timestamp - 1; + _params.tyingBuffer = 1000; + mockRequest.disputeModuleData = abi.encode(_params); + + // Compute proper IDs + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + uint256 _numForPledgers = 2; + uint256 _numAgainstPledgers = _numForPledgers; + + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + // Check: does it revert if trying to tie outside of the tying buffer? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_CannotBreakTieDuringTyingBuffer.selector); + bondEscalationModule.pledgeAgainstDispute(mockRequest, mockDispute); + } + + /** + * @notice Tests that pledgeAgainstDispute is called successfully + */ + function test_successfulCall(IBondEscalationModule.RequestParameters memory _params) + public + assumeFuzzable(address(_params.accountingExtension)) + { + _params.bondSize = 1000; + _params.maxNumberOfEscalations = 3; + _params.bondEscalationDeadline = block.timestamp - 1; + _params.tyingBuffer = 1000; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + uint256 _numAgainstPledgers = 2; + uint256 _numForPledgers = _numAgainstPledgers + 1; + + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + _mockAndExpect( + address(_params.accountingExtension), + abi.encodeCall( + IBondEscalationAccounting.pledge, (address(this), _requestId, _disputeId, _params.bondToken, _params.bondSize) + ), + abi.encode(true) + ); + + // Check: is the event emitted? + vm.expectEmit(true, true, true, true, address(bondEscalationModule)); + emit PledgedAgainstDispute(_disputeId, address(this), _params.bondSize); + + bondEscalationModule.pledgeAgainstDispute(mockRequest, mockDispute); + + uint256 _pledgesForDispute = bondEscalationModule.getEscalation(_requestId).amountOfPledgesAgainstDispute; + // Check: is the number of pledges for the dispute properly updated? + assertEq(_pledgesForDispute, _numAgainstPledgers + 1); + + uint256 _userPledges = bondEscalationModule.pledgesAgainstDispute(_requestId, address(this)); + // Check: is the number of pledges for the user properly updated? + assertEq(_userPledges, 1); + } +} + +contract BondEscalationModule_Unit_SettleBondEscalation is BaseTest { + /** + * @notice Tests that settleBondEscalation reverts if someone tries to settle the escalation before the tying buffer + * has elapsed. + */ + function test_revertIfTimestampLessThanEndOfTyingBuffer(IBondEscalationModule.RequestParameters memory _params) + public + { + _params.tyingBuffer = bound(_params.tyingBuffer, 0, type(uint128).max); + _params.bondEscalationDeadline = block.timestamp; + mockRequest.disputeModuleData = abi.encode(_params); + + // Check: does it revert if the bond escalation is not over? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_BondEscalationNotOver.selector); + bondEscalationModule.settleBondEscalation(mockRequest, mockResponse, mockDispute); + } + + /** + * @notice Tests that settleBondEscalation reverts if someone tries to settle a bond-escalated dispute that + * is not active. + */ + function test_revertIfStatusOfBondEscalationIsNotActive(IBondEscalationModule.RequestParameters memory _params) + public + { + _params.bondEscalationDeadline = block.timestamp; + _params.tyingBuffer = 1000; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + + vm.warp(_params.bondEscalationDeadline + _params.tyingBuffer + 1); + + bondEscalationModule.forTest_setBondEscalationStatus(_requestId, IBondEscalationModule.BondEscalationStatus.None); + + // Check: does it revert if the bond escalation is not active? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_BondEscalationCantBeSettled.selector); + bondEscalationModule.settleBondEscalation(mockRequest, mockResponse, mockDispute); + } + + /** + * @notice Tests that settleBondEscalation reverts if someone tries to settle a bond-escalated dispute that + * has the same number of pledgers. + */ + function test_revertIfSameNumberOfPledgers(IBondEscalationModule.RequestParameters memory _params) public { + _params.bondEscalationDeadline = block.timestamp; + _params.tyingBuffer = 1000; + mockRequest.disputeModuleData = abi.encode(_params); + bytes32 _requestId = _getId(mockRequest); + + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + vm.warp(_params.bondEscalationDeadline + _params.tyingBuffer + 1); + + bondEscalationModule.forTest_setBondEscalationStatus(_requestId, IBondEscalationModule.BondEscalationStatus.Active); + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + uint256 _numForPledgers = 5; + uint256 _numAgainstPledgers = _numForPledgers; + + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + // Check: does it revert if the number of pledgers is the same? + vm.expectRevert(IBondEscalationModule.BondEscalationModule_ShouldBeEscalated.selector); + bondEscalationModule.settleBondEscalation(mockRequest, mockResponse, mockDispute); + } + + /** + * @notice Tests that settleBondEscalation is called successfully. + */ + function test_successfulCallDisputerWon(IBondEscalationModule.RequestParameters memory _params) + public + assumeFuzzable(address(_params.accountingExtension)) + { + _params.bondSize = 1000; + _params.bondEscalationDeadline = block.timestamp; + _params.tyingBuffer = 1000; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + vm.warp(_params.bondEscalationDeadline + _params.tyingBuffer + 1); + + bondEscalationModule.forTest_setBondEscalationStatus(_requestId, IBondEscalationModule.BondEscalationStatus.Active); + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + uint256 _numForPledgers = 2; + uint256 _numAgainstPledgers = _numForPledgers - 1; + + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + _mockAndExpect( + address(oracle), + abi.encodeCall(IOracle.updateDisputeStatus, (mockRequest, mockResponse, mockDispute, IOracle.DisputeStatus.Won)), + abi.encode(true) + ); + + // Check: is the event emitted? + vm.expectEmit(true, true, true, true, address(bondEscalationModule)); + emit BondEscalationStatusUpdated(_requestId, _disputeId, IBondEscalationModule.BondEscalationStatus.DisputerWon); + + bondEscalationModule.settleBondEscalation(mockRequest, mockResponse, mockDispute); + // Check: is the bond escalation status properly updated? + assertEq( + uint256(bondEscalationModule.getEscalation(_requestId).status), + uint256(IBondEscalationModule.BondEscalationStatus.DisputerWon) + ); + } + + /** + * @notice Tests that settleBondEscalation is called successfully. + */ + function test_successfulCallDisputerLost(IBondEscalationModule.RequestParameters memory _params) + public + assumeFuzzable(address(_params.accountingExtension)) + { + _params.bondSize = 1000; + _params.bondEscalationDeadline = block.timestamp; + _params.tyingBuffer = 1000; + mockRequest.disputeModuleData = abi.encode(_params); + + bytes32 _requestId = _getId(mockRequest); + mockDispute.requestId = _requestId; + bytes32 _disputeId = _getId(mockDispute); + + vm.warp(_params.bondEscalationDeadline + _params.tyingBuffer + 1); + + bondEscalationModule.forTest_setBondEscalationStatus(_requestId, IBondEscalationModule.BondEscalationStatus.Active); + bondEscalationModule.forTest_setEscalatedDispute(_requestId, _disputeId); + + uint256 _numAgainstPledgers = 2; + uint256 _numForPledgers = _numAgainstPledgers - 1; + + _setBondEscalation(_requestId, _numForPledgers, _numAgainstPledgers); + + _mockAndExpect( + address(oracle), + abi.encodeCall(IOracle.updateDisputeStatus, (mockRequest, mockResponse, mockDispute, IOracle.DisputeStatus.Lost)), + abi.encode(true) + ); + + // Check: is the event emitted? + vm.expectEmit(true, true, true, true, address(bondEscalationModule)); + emit BondEscalationStatusUpdated(_requestId, _disputeId, IBondEscalationModule.BondEscalationStatus.DisputerLost); + + bondEscalationModule.settleBondEscalation(mockRequest, mockResponse, mockDispute); + // Check: is the bond escalation status properly updated? + assertEq( + uint256(bondEscalationModule.getEscalation(_requestId).status), + uint256(IBondEscalationModule.BondEscalationStatus.DisputerLost) + ); + } +}