-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'dev' into feat/OPT-395
- Loading branch information
Showing
4 changed files
with
212 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
169 changes: 169 additions & 0 deletions
169
solidity/test/integration/ReleaseUnutilizedResponse.t.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.19; | ||
|
||
import './IntegrationBase.sol'; | ||
|
||
contract Integration_ReleaseUnutilizedResponse is IntegrationBase { | ||
address internal _finalizer = makeAddr('finalizer'); | ||
bytes32 _requestId; | ||
bytes32 _responseId; | ||
bytes32 _disputeId; | ||
|
||
function setUp() public override { | ||
super.setUp(); | ||
|
||
_deposit(_accountingExtension, requester, usdc, _expectedReward); | ||
_deposit(_accountingExtension, proposer, usdc, _expectedBondSize); | ||
_deposit(_accountingExtension, disputer, usdc, _expectedBondSize); | ||
|
||
// Create request, response and dispute it | ||
_requestId = _createRequest(); | ||
mockResponse.requestId = _requestId; | ||
|
||
_responseId = _proposeResponse(mockResponse); | ||
mockDispute.requestId = _requestId; | ||
mockDispute.responseId = _responseId; | ||
|
||
_disputeId = _disputeResponse(); | ||
} | ||
|
||
/** | ||
* @notice Tests the release of unutilized response when the request is finalized with an empty response | ||
*/ | ||
function test_releaseUnutilizedResponse_withoutResponse() public { | ||
mockResponse.requestId = bytes32(0); | ||
IOracle.Response memory _emptyResponse = mockResponse; | ||
mockResponse.requestId = _requestId; | ||
|
||
// Finalizing the request with an empty response | ||
_finalizeRequest(_emptyResponse); | ||
|
||
// Check: is request finalized with an empty response? | ||
assertEq(oracle.finalizedResponseId(_requestId), bytes32(0)); | ||
assertEq(oracle.finalizedAt(_requestId), block.timestamp); | ||
|
||
// Check: proposers funds are still bonded? | ||
assertEq(_accountingExtension.bondedAmountOf(proposer, usdc, _requestId), _expectedBondSize, 'Balance check 1'); | ||
|
||
// The dispute is escalated and has no resolution | ||
_escalateAndResolveDispute(IOracle.DisputeStatus.NoResolution); | ||
|
||
// Check: proposers funds are still bonded? | ||
assertEq(_accountingExtension.bondedAmountOf(proposer, usdc, _requestId), _expectedBondSize, 'Balance check 2'); | ||
|
||
// Now the proposer should be able to release their unused response | ||
vm.prank(proposer); | ||
_responseModule.releaseUnutilizedResponse(mockRequest, mockResponse); | ||
|
||
// Check: proposers funds are not bonded anymore? | ||
assertEq(_accountingExtension.bondedAmountOf(proposer, usdc, _requestId), 0, 'Balance check 3'); | ||
|
||
// Check: proposer received their bond back? | ||
assertEq(_accountingExtension.balanceOf(proposer, usdc), _expectedBondSize); | ||
} | ||
|
||
/** | ||
* @notice Tests the release of unutilized response when the request is finalized with a correct response | ||
*/ | ||
function test_releaseUnutilizedResponse_withResponse() public { | ||
IOracle.Response memory _unutilizedResponse = mockResponse; | ||
|
||
IOracle.Response memory _acceptedResponse = mockResponse; | ||
_acceptedResponse.response = bytes('123'); | ||
_deposit(_accountingExtension, proposer, usdc, _expectedBondSize); | ||
_proposeResponse(_acceptedResponse); | ||
|
||
// Check: impossible to release responses before the request is finalized | ||
vm.expectRevert(IBondedResponseModule.BondedResponseModule_InvalidReleaseParameters.selector); | ||
_responseModule.releaseUnutilizedResponse(mockRequest, _unutilizedResponse); | ||
|
||
// Finalizing the request with a correct response | ||
_finalizeRequest(_acceptedResponse); | ||
|
||
// Check: impossible to release utilized responses | ||
vm.expectRevert(IBondedResponseModule.BondedResponseModule_InvalidReleaseParameters.selector); | ||
_responseModule.releaseUnutilizedResponse(mockRequest, _acceptedResponse); | ||
|
||
// Check: is request finalized with an empty response? | ||
assertEq(oracle.finalizedResponseId(_requestId), _getId(_acceptedResponse)); | ||
assertEq(oracle.finalizedAt(_requestId), block.timestamp); | ||
|
||
// Check: proposers funds are still bonded? | ||
assertEq(_accountingExtension.bondedAmountOf(proposer, usdc, _requestId), _expectedBondSize, 'Balance check 1'); | ||
|
||
// The dispute is escalated and has no resolution | ||
_escalateAndResolveDispute(IOracle.DisputeStatus.Lost); | ||
|
||
// Check: proposers funds are still bonded? | ||
assertEq(_accountingExtension.bondedAmountOf(proposer, usdc, _requestId), _expectedBondSize, 'Balance check 2'); | ||
|
||
// Now the proposer should be able to release their unused response | ||
vm.prank(proposer); | ||
_responseModule.releaseUnutilizedResponse(mockRequest, _unutilizedResponse); | ||
|
||
// Check: proposers funds are not bonded anymore? | ||
assertEq(_accountingExtension.bondedAmountOf(proposer, usdc, _requestId), 0, 'Balance check 3'); | ||
|
||
// Check: proposer received | ||
// - their own bonds for 2 responses | ||
// - disputer's bond for winning the dispute | ||
// - the reward for the correct response | ||
assertEq(_accountingExtension.balanceOf(proposer, usdc), _expectedBondSize * 3 + _expectedReward); | ||
} | ||
|
||
/** | ||
* @notice Tests reverts that happen when trying to release a response that is being or that has been successfully disputed | ||
*/ | ||
function test_releaseUnutilizedResponse_withDisputedResponse() public { | ||
mockResponse.requestId = bytes32(0); | ||
IOracle.Response memory _emptyResponse = mockResponse; | ||
mockResponse.requestId = _requestId; | ||
|
||
// Finalizing the request with an empty response | ||
_finalizeRequest(_emptyResponse); | ||
|
||
// Check: is request finalized with an empty response? | ||
assertEq(oracle.finalizedResponseId(_requestId), bytes32(0)); | ||
assertEq(oracle.finalizedAt(_requestId), block.timestamp); | ||
|
||
// Check: impossible to release the disputed response while the dispute is active | ||
vm.expectRevert(IBondedResponseModule.BondedResponseModule_InvalidReleaseParameters.selector); | ||
_responseModule.releaseUnutilizedResponse(mockRequest, mockResponse); | ||
|
||
// The dispute is escalated and has no resolution | ||
_escalateAndResolveDispute(IOracle.DisputeStatus.Won); | ||
|
||
// Check: impossible to release the disputed response if the disputer won | ||
vm.expectRevert(IBondedResponseModule.BondedResponseModule_InvalidReleaseParameters.selector); | ||
_responseModule.releaseUnutilizedResponse(mockRequest, mockResponse); | ||
|
||
// Check: proposers bond is slashed | ||
assertEq(_accountingExtension.bondedAmountOf(proposer, usdc, _requestId), 0); | ||
} | ||
|
||
function _escalateAndResolveDispute(IOracle.DisputeStatus _status) internal { | ||
// Escalate dispute | ||
vm.prank(disputer); | ||
oracle.escalateDispute(mockRequest, mockResponse, mockDispute, _createAccessControl()); | ||
|
||
// Resolve with the provided status | ||
vm.mockCall(address(_mockArbitrator), abi.encodeCall(IArbitrator.getAnswer, (_disputeId)), abi.encode(_status)); | ||
|
||
vm.prank(disputer); | ||
oracle.resolveDispute(mockRequest, mockResponse, mockDispute, _createAccessControl()); | ||
} | ||
|
||
function _finalizeRequest(IOracle.Response memory _response) internal { | ||
// After the deadline has passed, finalize with the given response | ||
vm.warp(block.timestamp + _expectedDeadline); | ||
vm.prank(_finalizer); | ||
oracle.finalize(mockRequest, _response, _createAccessControl()); | ||
} | ||
|
||
function _proposeResponse(IOracle.Response memory _response) internal returns (bytes32 _responseId) { | ||
vm.startPrank(proposer); | ||
_accountingExtension.approveModule(address(_responseModule)); | ||
_responseId = oracle.proposeResponse(mockRequest, _response, _createAccessControl()); | ||
vm.stopPrank(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters