From 490afa2464105cbc79db18bb57a0129fa349852e Mon Sep 17 00:00:00 2001 From: shaito Date: Wed, 23 Oct 2024 13:33:55 +0200 Subject: [PATCH] feat: remove circuit resolver --- docs/src/SUMMARY.md | 2 - docs/src/content/intro/README.md | 1 - docs/src/content/modules/dispute.md | 5 +- .../dispute/circuit_resolver_module.md | 33 -- .../modules/dispute/CircuitResolverModule.sol | 118 ------ .../dispute/ICircuitResolverModule.sol | 93 ----- solidity/scripts/Deploy.sol | 6 - .../dispute/CircuitResolverModule.t.sol | 390 ------------------ 8 files changed, 2 insertions(+), 646 deletions(-) delete mode 100644 docs/src/content/modules/dispute/circuit_resolver_module.md delete mode 100644 solidity/contracts/modules/dispute/CircuitResolverModule.sol delete mode 100644 solidity/interfaces/modules/dispute/ICircuitResolverModule.sol delete mode 100644 solidity/test/unit/modules/dispute/CircuitResolverModule.t.sol diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 93d54b4c..46d28fd6 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -26,7 +26,6 @@ - [BondedDisputeModule](content/modules/dispute/bonded_dispute_module.md) - [BondEscalationModule](content/modules/dispute/bond_escalation_module.md) - - [CircuitResolverModule](content/modules/dispute/circuit_resolver_module.md) - [RootVerificationModule](content/modules/dispute/root_verification_module.md) - [Resolution](content/modules/resolution.md) @@ -75,7 +74,6 @@ - [❱ dispute](solidity/interfaces/modules/dispute/README.md) - [IBondEscalationModule](solidity/interfaces/modules/dispute/IBondEscalationModule.sol/interface.IBondEscalationModule.md) - [IBondedDisputeModule](solidity/interfaces/modules/dispute/IBondedDisputeModule.sol/interface.IBondedDisputeModule.md) - - [ICircuitResolverModule](solidity/interfaces/modules/dispute/ICircuitResolverModule.sol/interface.ICircuitResolverModule.md) - [IRootVerificationModule](solidity/interfaces/modules/dispute/IRootVerificationModule.sol/interface.IRootVerificationModule.md) - [❱ finality](solidity/interfaces/modules/finality/README.md) - [ICallbackModule](solidity/interfaces/modules/finality/ICallbackModule.sol/interface.ICallbackModule.md) diff --git a/docs/src/content/intro/README.md b/docs/src/content/intro/README.md index 53c968ce..ebbe8b34 100644 --- a/docs/src/content/intro/README.md +++ b/docs/src/content/intro/README.md @@ -33,7 +33,6 @@ Prophet presents a versatile and fully adaptable optimistic oracle solution, tra | [BondedResponseModule](/solidity/interfaces/modules/response/IBondedResponseModule.sol/interface.IBondedResponseModule.md) | [`0x0000000000000000000000000000000000000000`](https://sepolia-optimism.etherscan.io/address/0x0000000000000000000000000000000000000000) | | [BondedDisputeModule](/solidity/interfaces/modules/dispute/IBondedDisputeModule.sol/interface.IBondedDisputeModule.md) | [`0x0000000000000000000000000000000000000000`](https://sepolia-optimism.etherscan.io/address/0x0000000000000000000000000000000000000000) | | [BondEscalationModule](/solidity/interfaces/modules/dispute/IBondEscalationModule.sol/interface.IBondEscalationModule.md) | [`0x0000000000000000000000000000000000000000`](https://sepolia-optimism.etherscan.io/address/0x0000000000000000000000000000000000000000) | -| [CircuitResolverModule](/solidity/interfaces/modules/dispute/ICircuitResolverModule.sol/interface.ICircuitResolverModule.md) | [`0x0000000000000000000000000000000000000000`](https://sepolia-optimism.etherscan.io/address/0x0000000000000000000000000000000000000000) | | [RootVerificationModule](/solidity/interfaces/modules/dispute/IRootVerificationModule.sol/interface.IRootVerificationModule.md) | [`0x0000000000000000000000000000000000000000`](https://sepolia-optimism.etherscan.io/address/0x0000000000000000000000000000000000000000) | | [ArbitratorModule](/solidity/interfaces/modules/resolution/IArbitratorModule.sol/interface.IArbitratorModule.md) | [`0x0000000000000000000000000000000000000000`](https://sepolia-optimism.etherscan.io/address/0x0000000000000000000000000000000000000000) | | [BondEscalationResolutionModule](/solidity/interfaces/modules/resolution/IBondEscalationResolutionModule.sol/interface.IBondEscalationResolutionModule.md) | [`0x0000000000000000000000000000000000000000`](https://sepolia-optimism.etherscan.io/address/0x0000000000000000000000000000000000000000) | diff --git a/docs/src/content/modules/dispute.md b/docs/src/content/modules/dispute.md index 7f0f5997..d77f1cf2 100644 --- a/docs/src/content/modules/dispute.md +++ b/docs/src/content/modules/dispute.md @@ -7,14 +7,13 @@ The Dispute module is a crucial component of the Prophet Framework that manages In Prophet, examples of Dispute modules include: - [BondedDisputeModule](./dispute/bonded_dispute_module.md) that requires a challenger to post a bond first, which will be returned upon successful dispute resolution or slashed in case of an unsuccessful dispute. - [BondEscalationModule](./dispute/bond_escalation_module.md) in which the sides take turns increasing the bond until one of them gives up or until they reach a limit. -- [CircuitResolverModule](./dispute/circuit_resolver_module.md) that allows for the dispute to be resolved on-chain. -- [RootVerificationModule](./dispute/root_verification_module.md) that, similarly to the `CircuitResolverModule`, enables atomical on-chain resolution of disputes. +- [RootVerificationModule](./dispute/root_verification_module.md) enables atomical on-chain resolution of disputes. ## Dispute Types - **Pre-dispute**: This type of Dispute modules aims to settle disputes before they reach the Resolution module. `BondEscalationModule` is an example of a pre-dispute module. -- **Atomical dispute**: This type of dispute relies on an external contract to atomically resolve the dispute as soon as it's started. In this case the Resolution module might not be needed at all. `CircuitResolverModule` and `RootVerificationModule` are examples of atomical dispute modules. +- **Atomical dispute**: This type of dispute relies on an external contract to atomically resolve the dispute as soon as it's started. In this case the Resolution module might not be needed at all. `RootVerificationModule` are examples of atomical dispute modules. ## Developing a Dispute Module diff --git a/docs/src/content/modules/dispute/circuit_resolver_module.md b/docs/src/content/modules/dispute/circuit_resolver_module.md deleted file mode 100644 index c7837596..00000000 --- a/docs/src/content/modules/dispute/circuit_resolver_module.md +++ /dev/null @@ -1,33 +0,0 @@ -# Circuit Resolver Module - -See [ICircuitResolverModule.sol](/solidity/interfaces/modules/dispute/ICircuitResolverModule.sol/interface.ICircuitResolverModule.md) for more details. - -## 1. Introduction - -The Circuit Resolver Module is a pre-dispute module that allows disputers to verify a zero-knowledge circuit for a given request and propose it as a response, starting and resolving the dispute atomically. - -## 2. Contract Details - -### Key Methods - -- `decodeRequestData`: Decodes request parameters. -- `disputeResponse`: Verifies the ZK circuit and compares it to the proposed one. Updates the dispute status after checking if the disputed response is indeed wrong. -- `onDisputeStatusChange`: Updates the status of the dispute and resolves it by proposing the correct circuit as a response and finalizing the request. - -### Request Parameters - -- `callData`: The encoded data forwarded to the verifier. -- `verifier`: The address of the verifier contract. -- `accountingExtension`: The accounting extension to use for payments. -- `bondToken`: The token to use for payments, it must be the same token that was specified for the response module. -- `bondSize`: The size of the payment for winning a dispute, it must be the same amount that was specified for the response module. - -## 3. Key Mechanisms & Concepts - -- **Verifier**: A contract implementing the verification logic, which will be consulted in case of a dispute. -- **Atomical dispute**: With this module, a dispute is initiated and resolved in the same transaction because the answer can be (somewhat expensively) calculated on-chain. - -## 4. Gotchas - -- The disputer is not required to bond any tokens in order to start a dispute, because in case they're wrong the cost of calculating the answer will be the penalty. However, depending on the chosen response module, they might be required to bond as a proposer of a new response. -- The module relies on the correct implementation of the verifier. If the verifier's logic if flawed, the module may not be able to resolve disputes correctly. diff --git a/solidity/contracts/modules/dispute/CircuitResolverModule.sol b/solidity/contracts/modules/dispute/CircuitResolverModule.sol deleted file mode 100644 index e4c955d9..00000000 --- a/solidity/contracts/modules/dispute/CircuitResolverModule.sol +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; - -import {IModule, Module} from '@defi-wonderland/prophet-core/solidity/contracts/Module.sol'; -import {IOracle} from '@defi-wonderland/prophet-core/solidity/interfaces/IOracle.sol'; - -import {IProphetVerifier} from '../../../interfaces/IProphetVerifier.sol'; -import {ICircuitResolverModule} from '../../../interfaces/modules/dispute/ICircuitResolverModule.sol'; - -contract CircuitResolverModule is Module, ICircuitResolverModule { - /// @notice Keeps track of the correct responses to requests - mapping(bytes32 _requestId => bytes _correctResponse) internal _correctResponses; - - constructor(IOracle _oracle) Module(_oracle) {} - - /// @inheritdoc IModule - function moduleName() external pure returns (string memory _moduleName) { - return 'CircuitResolverModule'; - } - - /// @inheritdoc ICircuitResolverModule - function decodeRequestData(bytes calldata _data) public pure returns (RequestParameters memory _params) { - _params = abi.decode(_data, (RequestParameters)); - } - - /// @inheritdoc ICircuitResolverModule - function onDisputeStatusChange( - bytes32 _disputeId, - IOracle.Request calldata _request, - IOracle.Response calldata _response, - IOracle.Dispute calldata _dispute - ) external onlyOracle { - RequestParameters memory _params = decodeRequestData(_request.disputeModuleData); - IOracle.DisputeStatus _status = ORACLE.disputeStatus(_disputeId); - - if (_status == IOracle.DisputeStatus.Won) { - _params.accountingExtension.pay({ - _requestId: _dispute.requestId, - _payer: _dispute.proposer, - _receiver: _dispute.disputer, - _token: _params.bondToken, - _amount: _params.bondSize - }); - - IOracle.Response memory _newResponse = IOracle.Response({ - requestId: _dispute.requestId, - proposer: _dispute.disputer, - response: _correctResponses[_dispute.requestId] - }); - - emit DisputeStatusChanged({_disputeId: _disputeId, _dispute: _dispute, _status: IOracle.DisputeStatus.Won}); - - ORACLE.proposeResponse(_request, _newResponse); - ORACLE.finalize(_request, _newResponse); - } else { - emit DisputeStatusChanged({_disputeId: _disputeId, _dispute: _dispute, _status: IOracle.DisputeStatus.Lost}); - - ORACLE.finalize(_request, _response); - } - - delete _correctResponses[_dispute.requestId]; - } - - /// @inheritdoc ICircuitResolverModule - function disputeResponse( - IOracle.Request calldata _request, - IOracle.Response calldata _response, - IOracle.Dispute calldata _dispute - ) external onlyOracle { - RequestParameters memory _params = decodeRequestData(_request.disputeModuleData); - IOracle.DisputeStatus _status; - - try IProphetVerifier(_params.verifier).prophetVerify(_params.callData) returns (bytes memory _correctResponse) { - _correctResponses[_response.requestId] = _correctResponse; - - _status = _response.response.length != _correctResponse.length - || keccak256(_response.response) != keccak256(_correctResponse) - ? IOracle.DisputeStatus.Won - : IOracle.DisputeStatus.Lost; - } catch { - revert CircuitResolverModule_VerificationFailed(); - } - - emit ResponseDisputed({ - _requestId: _response.requestId, - _responseId: _dispute.responseId, - _disputeId: _getId(_dispute), - _dispute: _dispute - }); - - ORACLE.updateDisputeStatus(_request, _response, _dispute, _status); - } - - /// @inheritdoc IModule - function validateParameters(bytes calldata _encodedParameters) - external - view - override(Module, IModule) - returns (bool _valid) - { - RequestParameters memory _params = decodeRequestData(_encodedParameters); - _valid = address(_params.accountingExtension) != address(0) && address(_params.bondToken) != address(0) - && _params.bondSize != 0 && _targetHasBytecode(_params.verifier) && _params.callData.length != 0; - } - - /** - * @notice Checks if a target address has bytecode - * @param _target The address to check - * @return _hasBytecode Whether the target has bytecode or not - */ - function _targetHasBytecode(address _target) private view returns (bool _hasBytecode) { - uint256 _size; - assembly { - _size := extcodesize(_target) - } - _hasBytecode = _size > 0; - } -} diff --git a/solidity/interfaces/modules/dispute/ICircuitResolverModule.sol b/solidity/interfaces/modules/dispute/ICircuitResolverModule.sol deleted file mode 100644 index b040a5ab..00000000 --- a/solidity/interfaces/modules/dispute/ICircuitResolverModule.sol +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; - -import {IOracle} from '@defi-wonderland/prophet-core/solidity/interfaces/IOracle.sol'; -import {IDisputeModule} from '@defi-wonderland/prophet-core/solidity/interfaces/modules/dispute/IDisputeModule.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; - -import {IAccountingExtension} from '../../extensions/IAccountingExtension.sol'; - -/** - * @title CircuitResolverModule - * @notice Module allowing users to dispute a proposed response by bonding tokens. - * The module will invoke the circuit verifier supplied to calculate - * the proposed response and compare it to the correct response. - * - If the dispute is valid, the disputer wins and their bond is returned along with a reward. - * - If the dispute is invalid, the bond is forfeited and returned to the proposer. - * - * After the dispute is settled, the correct response is automatically proposed to the oracle - * and the request is finalized. - */ -interface ICircuitResolverModule is IDisputeModule { - /*/////////////////////////////////////////////////////////////// - ERRORS - //////////////////////////////////////////////////////////////*/ - - /** - * @notice Thrown when the verification of a response fails - */ - error CircuitResolverModule_VerificationFailed(); - - /*/////////////////////////////////////////////////////////////// - STRUCTS - //////////////////////////////////////////////////////////////*/ - - /** - * @notice Parameters of the request as stored in the module - * - * @param callData The encoded data forwarded to the verifier - * @param verifier The address of the verifier contract - * @param accountingExtension The address of the accounting extension - * @param bondToken The address of the bond token - * @param bondSize The size of the bond - */ - struct RequestParameters { - bytes callData; - address verifier; - IAccountingExtension accountingExtension; - IERC20 bondToken; - uint256 bondSize; - } - - /*/////////////////////////////////////////////////////////////// - LOGIC - //////////////////////////////////////////////////////////////*/ - - /** - * @notice Returns the decoded data for a request - * - * @param _data The encoded request parameters - * @return _params The decoded parameters of the request - */ - function decodeRequestData(bytes calldata _data) external view returns (RequestParameters memory _params); - - /** - * @notice Initiates and resolves the dispute by comparing the proposed response with the one returned by the verifier - * - * @dev This function will notify the oracle about the outcome of the dispute - * @param _request The request that the response was proposed to - * @param _response The response that is being disputed - * @param _dispute The dispute created by the oracle - */ - function disputeResponse( - IOracle.Request calldata _request, - IOracle.Response calldata _response, - IOracle.Dispute calldata _dispute - ) external; - - /** - * @notice Depending on the status of the dispute, either pays the disputer and submits the correct response, - * or pays the proposer. Finalizes the request in any case. - * - * @param _disputeId The id of the dispute - * @param _request The request - * @param _response The response that was disputed - * @param _dispute The dispute - */ - function onDisputeStatusChange( - bytes32 _disputeId, - IOracle.Request calldata _request, - IOracle.Response calldata _response, - IOracle.Dispute calldata _dispute - ) external; -} diff --git a/solidity/scripts/Deploy.sol b/solidity/scripts/Deploy.sol index 53b511e8..ab43b9da 100644 --- a/solidity/scripts/Deploy.sol +++ b/solidity/scripts/Deploy.sol @@ -10,7 +10,6 @@ import {IResolutionModule} from import {BondEscalationModule} from '../contracts/modules/dispute/BondEscalationModule.sol'; import {BondedDisputeModule} from '../contracts/modules/dispute/BondedDisputeModule.sol'; -import {CircuitResolverModule} from '../contracts/modules/dispute/CircuitResolverModule.sol'; import {RootVerificationModule} from '../contracts/modules/dispute/RootVerificationModule.sol'; import {CallbackModule} from '../contracts/modules/finality/CallbackModule.sol'; import {MultipleCallbacksModule} from '../contracts/modules/finality/MultipleCallbacksModule.sol'; @@ -44,7 +43,6 @@ contract Deploy is Script { BondedDisputeModule bondedDisputeModule; BondEscalationModule bondEscalationModule; RootVerificationModule rootVerificationModule; - CircuitResolverModule circuitResolverModule; // Resolution modules ArbitratorModule arbitratorModule; @@ -129,9 +127,5 @@ contract Deploy is Script { authorizedCallers[0] = address(bondEscalationModule); bondEscalationAccounting = new BondEscalationAccounting(oracle, authorizedCallers); console.log('BOND_ESCALATION_ACCOUNTING_EXTENSION:', address(bondEscalationAccounting)); - - // Deploy circuit resolver module - circuitResolverModule = new CircuitResolverModule(oracle); - console.log('CIRCUIT_RESOLVER_MODULE:', address(circuitResolverModule)); } } diff --git a/solidity/test/unit/modules/dispute/CircuitResolverModule.t.sol b/solidity/test/unit/modules/dispute/CircuitResolverModule.t.sol deleted file mode 100644 index 7d071dfd..00000000 --- a/solidity/test/unit/modules/dispute/CircuitResolverModule.t.sol +++ /dev/null @@ -1,390 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; - -import 'forge-std/Test.sol'; - -import {Helpers} from '../../../utils/Helpers.sol'; - -import {IModule} from '@defi-wonderland/prophet-core/solidity/interfaces/IModule.sol'; -import {IOracle} from '@defi-wonderland/prophet-core/solidity/interfaces/IOracle.sol'; -import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; - -import { - CircuitResolverModule, - ICircuitResolverModule -} from '../../../../contracts/modules/dispute/CircuitResolverModule.sol'; - -import {IProphetVerifier} from '../../../../interfaces/IProphetVerifier.sol'; -import {IAccountingExtension} from '../../../../interfaces/extensions/IAccountingExtension.sol'; -import {MockVerifier} from '../../../mocks/MockVerifier.sol'; - -/** - * @dev Harness to set an entry in the correctResponses mapping - */ -contract ForTest_CircuitResolverModule is CircuitResolverModule { - constructor(IOracle _oracle) CircuitResolverModule(_oracle) {} - - function forTest_setCorrectResponse(bytes32 _requestId, bytes memory _data) public { - _correctResponses[_requestId] = _data; - } -} - -/** - * @title Bonded Dispute Module Unit tests - */ -contract BaseTest is Test, Helpers { - // The target contract - ForTest_CircuitResolverModule public circuitResolverModule; - // A mock oracle - IOracle public oracle; - // A mock circuit verifier address - MockVerifier public mockVerifier; - - // Events - event DisputeStatusChanged(bytes32 indexed _disputeId, IOracle.Dispute _dispute, IOracle.DisputeStatus _status); - event ResponseDisputed( - bytes32 indexed _requestId, bytes32 indexed _responseId, bytes32 indexed _disputeId, IOracle.Dispute _dispute - ); - - /** - * @notice Deploy the target and mock oracle+accounting extension - */ - function setUp() public { - oracle = IOracle(makeAddr('Oracle')); - vm.etch(address(oracle), hex'069420'); - - mockVerifier = new MockVerifier(); - - circuitResolverModule = new ForTest_CircuitResolverModule(oracle); - } - - function targetHasBytecode(address _target) public view returns (bool _hasBytecode) { - uint256 _size; - assembly { - _size := extcodesize(_target) - } - _hasBytecode = _size > 0; - } -} - -contract CircuitResolverModule_Unit_ModuleData is BaseTest { - /** - * @notice Test that the decodeRequestData function returns the correct values - */ - function test_decodeRequestData( - IAccountingExtension _accountingExtension, - IERC20 _randomToken, - uint256 _bondSize, - bytes memory _callData - ) public view { - // Mock data - bytes memory _requestData = abi.encode( - ICircuitResolverModule.RequestParameters({ - callData: _callData, - verifier: address(mockVerifier), - accountingExtension: IAccountingExtension(_accountingExtension), - bondToken: IERC20(_randomToken), - bondSize: _bondSize - }) - ); - - // Test: decode the given request data - ICircuitResolverModule.RequestParameters memory _params = circuitResolverModule.decodeRequestData(_requestData); - - // Check: is the request data properly stored? - assertEq( - address(_params.accountingExtension), address(_accountingExtension), 'Mismatch: decoded accounting extension' - ); - assertEq(address(_params.bondToken), address(_randomToken), 'Mismatch: decoded token'); - assertEq(_params.verifier, address(mockVerifier), 'Mismatch: decoded circuit verifier'); - assertEq(_params.bondSize, _bondSize, 'Mismatch: decoded bond size'); - assertEq(_params.callData, _callData, 'Mismatch: decoded calldata'); - } - - /** - * @notice Test that the moduleName function returns the correct name - */ - function test_moduleName() public view { - assertEq(circuitResolverModule.moduleName(), 'CircuitResolverModule'); - } - - /** - * @notice Test that the validateParameters function correctly checks the parameters - */ - function test_validateParameters(ICircuitResolverModule.RequestParameters calldata _params) public view { - if ( - address(_params.accountingExtension) == address(0) || address(_params.bondToken) == address(0) - || _params.bondSize == 0 || !targetHasBytecode(_params.verifier) || _params.callData.length == 0 - ) { - assertFalse(circuitResolverModule.validateParameters(abi.encode(_params))); - } else { - assertTrue(circuitResolverModule.validateParameters(abi.encode(_params))); - } - } -} - -contract CircuitResolverModule_Unit_DisputeResponse is BaseTest { - /** - * @notice Test if dispute incorrect response returns the correct status - */ - function test_disputeIncorrectResponse( - IAccountingExtension _accountingExtension, - IERC20 _randomToken, - uint256 _bondSize, - bytes memory _callData - ) public { - mockRequest.disputeModuleData = abi.encode( - ICircuitResolverModule.RequestParameters({ - callData: _callData, - verifier: address(mockVerifier), - accountingExtension: _accountingExtension, - bondToken: _randomToken, - bondSize: _bondSize - }) - ); - - bytes memory _correctResponse = abi.encode(false); - - mockResponse.requestId = _getId(mockRequest); - mockDispute.requestId = mockResponse.requestId; - mockDispute.responseId = _getId(mockResponse); - - // Mock and expect the call to the verifier - _mockAndExpect( - address(mockVerifier), - abi.encodeWithSelector(IProphetVerifier.prophetVerify.selector, _callData), - abi.encode(_correctResponse) - ); - - // Mock and expect the call the oracle, updating the dispute's status - _mockAndExpect( - address(oracle), - abi.encodeWithSelector( - oracle.updateDisputeStatus.selector, mockRequest, mockResponse, mockDispute, IOracle.DisputeStatus.Won - ), - abi.encode(true) - ); - - // Test: call disputeResponse - vm.prank(address(oracle)); - circuitResolverModule.disputeResponse(mockRequest, mockResponse, mockDispute); - } - - function test_emitsEvent( - IAccountingExtension _accountingExtension, - IERC20 _randomToken, - uint256 _bondSize, - bytes memory _callData - ) public { - mockRequest.disputeModuleData = abi.encode( - ICircuitResolverModule.RequestParameters({ - callData: _callData, - verifier: address(mockVerifier), - accountingExtension: _accountingExtension, - bondToken: _randomToken, - bondSize: _bondSize - }) - ); - - bytes memory _correctResponse = abi.encode(false); - - mockResponse.requestId = _getId(mockRequest); - mockResponse.response = abi.encode(true); - - // Mock and expect the call to the verifier - _mockAndExpect( - address(mockVerifier), - abi.encodeWithSelector(IProphetVerifier.prophetVerify.selector, _callData), - abi.encode(_correctResponse) - ); - - // Mock and expect the call the oracle, updating the dispute's status - _mockAndExpect( - address(oracle), - abi.encodeWithSelector( - oracle.updateDisputeStatus.selector, mockRequest, mockResponse, mockDispute, IOracle.DisputeStatus.Won - ), - abi.encode(true) - ); - - // Check: is the event emitted? - vm.expectEmit(true, true, true, true, address(circuitResolverModule)); - emit ResponseDisputed({ - _requestId: mockResponse.requestId, - _responseId: mockDispute.responseId, - _disputeId: _getId(mockDispute), - _dispute: mockDispute - }); - - vm.prank(address(oracle)); - circuitResolverModule.disputeResponse(mockRequest, mockResponse, mockDispute); - } - - /** - * @notice Test if dispute correct response returns the correct status - */ - function test_disputeCorrectResponse( - IAccountingExtension _accountingExtension, - IERC20 _randomToken, - uint256 _bondSize, - bytes memory _callData - ) public { - mockRequest.disputeModuleData = abi.encode( - ICircuitResolverModule.RequestParameters({ - callData: _callData, - verifier: address(mockVerifier), - accountingExtension: _accountingExtension, - bondToken: _randomToken, - bondSize: _bondSize - }) - ); - - bytes memory _correctResponse = abi.encode(true); - - mockResponse.requestId = _getId(mockRequest); - mockResponse.response = _correctResponse; - - // Mock and expect the call to the verifier - _mockAndExpect( - address(mockVerifier), - abi.encodeWithSelector(IProphetVerifier.prophetVerify.selector, _callData), - abi.encode(_correctResponse) - ); - - // Mock and expect the call the oracle, updating the dispute's status - _mockAndExpect( - address(oracle), - abi.encodeWithSelector( - oracle.updateDisputeStatus.selector, mockRequest, mockResponse, mockDispute, IOracle.DisputeStatus.Lost - ), - abi.encode(true) - ); - - vm.prank(address(oracle)); - circuitResolverModule.disputeResponse(mockRequest, mockResponse, mockDispute); - } - - /** - * @notice Test if dispute response reverts when called by caller who's not the oracle - */ - function test_revertWrongCaller(address _randomCaller) public { - vm.assume(_randomCaller != address(oracle)); - - // Check: does it revert if not called by the Oracle? - vm.expectRevert(IModule.Module_OnlyOracle.selector); - - vm.prank(_randomCaller); - circuitResolverModule.disputeResponse(mockRequest, mockResponse, mockDispute); - } -} - -contract CircuitResolverModule_Unit_OnDisputeStatusChange is BaseTest { - function test_emitsEvent_lostDispute( - IAccountingExtension _accountingExtension, - IERC20 _randomToken, - uint256 _bondSize, - bytes memory _callData - ) public assumeFuzzable(address(_accountingExtension)) { - mockRequest.disputeModuleData = abi.encode( - ICircuitResolverModule.RequestParameters({ - callData: _callData, - verifier: address(mockVerifier), - accountingExtension: _accountingExtension, - bondToken: _randomToken, - bondSize: _bondSize - }) - ); - - bytes32 _requestId = _getId(mockRequest); - bytes memory _encodedCorrectResponse = abi.encode(true); - - circuitResolverModule.forTest_setCorrectResponse(_requestId, _encodedCorrectResponse); - - mockResponse.requestId = _requestId; - mockResponse.response = _encodedCorrectResponse; - mockResponse.proposer = makeAddr('proposer'); - - // Populate the mock dispute with the correct values - mockDispute.responseId = _getId(mockResponse); - mockDispute.requestId = _requestId; - bytes32 _disputeId = _getId(mockDispute); - IOracle.DisputeStatus _status = IOracle.DisputeStatus.Lost; - - // Mock and expect the call to the oracle, getting the dispute status - _mockAndExpect(address(oracle), abi.encodeCall(IOracle.disputeStatus, (_disputeId)), abi.encode(_status)); - - // Mock and expect the call to the oracle, finalizing the request - _mockAndExpect(address(oracle), abi.encodeCall(IOracle.finalize, (mockRequest, mockResponse)), abi.encode()); - - // Check: is the event emitted? - vm.expectEmit(true, true, true, true, address(circuitResolverModule)); - emit DisputeStatusChanged(_disputeId, mockDispute, _status); - - vm.prank(address(oracle)); - circuitResolverModule.onDisputeStatusChange(_disputeId, mockRequest, mockResponse, mockDispute); - } - - function test_emitsEvent_wonDispute( - IAccountingExtension _accountingExtension, - IERC20 _randomToken, - uint256 _bondSize, - bytes memory _callData - ) public assumeFuzzable(address(_accountingExtension)) { - mockRequest.disputeModuleData = abi.encode( - ICircuitResolverModule.RequestParameters({ - callData: _callData, - verifier: address(mockVerifier), - accountingExtension: _accountingExtension, - bondToken: _randomToken, - bondSize: _bondSize - }) - ); - - bytes32 _requestId = _getId(mockRequest); - bytes memory _encodedCorrectResponse = abi.encode(true); - - circuitResolverModule.forTest_setCorrectResponse(_requestId, _encodedCorrectResponse); - - mockResponse.requestId = _requestId; - mockResponse.response = abi.encode(false); - mockResponse.proposer = makeAddr('proposer'); - - // Populate the mock dispute with the correct values - mockDispute.responseId = _getId(mockResponse); - mockDispute.requestId = _requestId; - bytes32 _disputeId = _getId(mockDispute); - IOracle.DisputeStatus _status = IOracle.DisputeStatus.Won; - - // Mock and expect the call to the oracle, getting the dispute status - _mockAndExpect(address(oracle), abi.encodeCall(IOracle.disputeStatus, (_disputeId)), abi.encode(_status)); - - // Mock and expect the call to the accounting extension, paying the disputer - _mockAndExpect( - address(_accountingExtension), - abi.encodeCall( - IAccountingExtension.pay, (_requestId, makeAddr('proposer'), mockDispute.disputer, _randomToken, _bondSize) - ), - abi.encode() - ); - - IOracle.Response memory _newResponse = - IOracle.Response({requestId: _requestId, response: _encodedCorrectResponse, proposer: mockDispute.disputer}); - - // Check: is the event emitted? - vm.expectEmit(true, true, true, true, address(circuitResolverModule)); - emit DisputeStatusChanged(_disputeId, mockDispute, _status); - - // Mock and expect the call to the oracle, proposing the correct response - _mockAndExpect( - address(oracle), - abi.encodeCall(IOracle.proposeResponse, (mockRequest, _newResponse)), - abi.encode(_getId(_newResponse)) - ); - - // Mock and expect the call to the accounting extension, paying the disputer - _mockAndExpect(address(oracle), abi.encodeCall(IOracle.finalize, (mockRequest, _newResponse)), abi.encode()); - - vm.prank(address(oracle)); - circuitResolverModule.onDisputeStatusChange(_disputeId, mockRequest, mockResponse, mockDispute); - } -}