Skip to content

Commit

Permalink
feat: resolve disputes through oracle (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
gas1cent authored Jun 29, 2023
1 parent dbfb4ba commit af489e0
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 61 deletions.
15 changes: 15 additions & 0 deletions solidity/contracts/Oracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,21 @@ contract Oracle is IOracle {
}
}

function resolveDispute(bytes32 _disputeId) external {
Dispute memory _dispute = _disputes[_disputeId];

if (_dispute.createdAt == 0) revert Oracle_InvalidDisputeId(_disputeId);
// Revert if the dispute is not active nor escalated
unchecked {
if (uint256(_dispute.status) - 1 > 1) revert Oracle_CannotResolve(_disputeId);
}

Request memory _request = _requests[_dispute.requestId];
if (address(_request.resolutionModule) == address(0)) revert Oracle_NoResolutionModule(_disputeId);

_request.resolutionModule.resolveDispute(_disputeId);
}

function updateDisputeStatus(bytes32 _disputeId, DisputeStatus _status) external {
Dispute storage _dispute = _disputes[_disputeId];
Request memory _request = _requests[_dispute.requestId];
Expand Down
5 changes: 1 addition & 4 deletions solidity/contracts/modules/ArbitratorModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,11 @@ contract ArbitratorModule is Module, IArbitratorModule {
}

// Store the result of an Active dispute and flag it as Resolved
function resolveDispute(bytes32 _disputeId) external {
function resolveDispute(bytes32 _disputeId) external onlyOracle {
IOracle.Dispute memory _dispute = ORACLE.getDispute(_disputeId);
if (_dispute.status != IOracle.DisputeStatus.Escalated) revert ArbitratorModule_InvalidDisputeId();

address _arbitrator = abi.decode(requestData[_dispute.requestId], (address));

if (msg.sender != _arbitrator) revert ArbitratorModule_OnlyArbitrator();

bool _valid = IArbitrator(_arbitrator).getAnswer(_disputeId);

// Store the answer and the status as resolved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ contract BondEscalationResolutionModule is Module, IBondEscalationResolutionModu
}
}

function resolveDispute(bytes32 _disputeId) external {
function resolveDispute(bytes32 _disputeId) external onlyOracle {
// Cache reused struct
EscalationData storage _escalationData = escalationData[_disputeId];

Expand Down
6 changes: 1 addition & 5 deletions solidity/contracts/modules/ERC20ResolutonModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,7 @@ contract ERC20ResolutionModule is Module, IERC20ResolutionModule {
emit VoteCast(msg.sender, _disputeId, _numberOfVotes);
}

function resolveDispute(bytes32 _disputeId) external {
/*
TODO: check caller?
*/

function resolveDispute(bytes32 _disputeId) external onlyOracle {
// 0. Check that the disputeId actually exists
IOracle.Dispute memory _dispute = ORACLE.getDispute(_disputeId);
if (_dispute.createdAt == 0) revert ERC20ResolutionModule_NonExistentDispute();
Expand Down
3 changes: 3 additions & 0 deletions solidity/interfaces/IOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ interface IOracle {
error Oracle_InvalidFinalizedResponse(bytes32 _responseId);
error Oracle_InvalidDisputeId(bytes32 _disputeId);
error Oracle_CannotEscalate(bytes32 _disputeId);
error Oracle_CannotResolve(bytes32 _disputeId);
error Oracle_NoResolutionModule(bytes32 _disputeId);

struct Request {
bytes requestModuleData;
Expand Down Expand Up @@ -85,6 +87,7 @@ interface IOracle {
function escalateDispute(bytes32 _disputeId) external;
function getFinalizedResponse(bytes32 _requestId) external view returns (Response memory _response);
function getResponseIds(bytes32 _requestId) external view returns (bytes32[] memory _ids);
function resolveDispute(bytes32 _disputeId) external;
function updateDisputeStatus(bytes32 _disputeId, DisputeStatus _status) external;
function getProposers(bytes32 _requestId) external view returns (address[] memory _proposers);
function listRequests(uint256 _startFrom, uint256 _amount) external view returns (Request[] memory _list);
Expand Down
17 changes: 5 additions & 12 deletions solidity/test/unit/ArbitratorModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ contract ArbitratorModule_UnitTest is Test {
);

// Test: resolve the dispute
vm.prank(address(arbitrator));
vm.prank(address(oracle));
arbitratorModule.resolveDispute(_disputeId);

// Check: status is now Resolved?
Expand Down Expand Up @@ -195,7 +195,7 @@ contract ArbitratorModule_UnitTest is Test {
vm.expectRevert(abi.encodeWithSelector(IArbitratorModule.ArbitratorModule_InvalidDisputeId.selector));

// Test: try calling resolve
vm.prank(address(arbitrator));
vm.prank(address(oracle));
arbitratorModule.resolveDispute(_disputeId);
}
}
Expand All @@ -204,21 +204,14 @@ contract ArbitratorModule_UnitTest is Test {
* @notice Test that the resolve function reverts if the caller isn't the arbitrator
*/
function test_resolveDisputeWrongSenderReverts(bytes32 _disputeId, bytes32 _requestId, address _caller) public {
vm.assume(_caller != address(arbitrator));

// Mock and expect the dummy dispute
mockDispute.requestId = _requestId;
mockDispute.status = IOracle.DisputeStatus.Escalated;

vm.mockCall(address(oracle), abi.encodeCall(oracle.getDispute, (_disputeId)), abi.encode(mockDispute));
vm.expectCall(address(oracle), abi.encodeCall(oracle.getDispute, (_disputeId)));
vm.assume(_caller != address(oracle));

// Store the mock dispute
bytes memory _requestData = abi.encode(address(arbitrator));
arbitratorModule.forTest_setRequestData(_requestId, _requestData);

// Check: revert
vm.expectRevert(abi.encodeWithSelector(IArbitratorModule.ArbitratorModule_OnlyArbitrator.selector));
// Check: revert?
vm.expectRevert(IModule.Module_OnlyOracle.selector);

// Test: resolve the dispute
vm.prank(_caller);
Expand Down
9 changes: 9 additions & 0 deletions solidity/test/unit/BondEscalationResolutionModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -356,12 +356,15 @@ contract BondEscalationResolutionModule_UnitTest is Test {
_setMockEscalationData(_disputeId, _resolution, _startTime, _pledgesFor, _pledgesAgainst);

vm.expectRevert(IBondEscalationResolutionModule.BondEscalationResolutionModule_AlreadyResolved.selector);
vm.prank(address(oracle));
module.resolveDispute(_disputeId);

// Revert if dispute not escalated
_resolution = IBondEscalationResolutionModule.Resolution.Unresolved;
_setMockEscalationData(_disputeId, _resolution, _startTime, _pledgesFor, _pledgesAgainst);

vm.expectRevert(IBondEscalationResolutionModule.BondEscalationResolutionModule_NotEscalated.selector);
vm.prank(address(oracle));
module.resolveDispute(_disputeId);

// Revert if we have not yet reached the deadline and the timer has not passed
Expand All @@ -381,7 +384,9 @@ contract BondEscalationResolutionModule_UnitTest is Test {

_startTime = uint128(block.timestamp);
_setMockEscalationData(_disputeId, _resolution, _startTime, _pledgesFor, _pledgesAgainst);

vm.expectRevert(IBondEscalationResolutionModule.BondEscalationResolutionModule_PledgingPhaseNotOver.selector);
vm.prank(address(oracle));
module.resolveDispute(_disputeId);
}

Expand All @@ -403,6 +408,7 @@ contract BondEscalationResolutionModule_UnitTest is Test {
// START OF TEST THRESHOLD NOT REACHED
uint256 _pledgeThreshold = 1000;
_setRequestData(_requestId, percentageDiff, _pledgeThreshold, timeUntilDeadline, timeToBreakInequality);
vm.prank(address(oracle));
module.resolveDispute(_disputeId);

(IBondEscalationResolutionModule.Resolution _trueResStatus,,,) = module.escalationData(_disputeId);
Expand All @@ -429,6 +435,7 @@ contract BondEscalationResolutionModule_UnitTest is Test {

// START OF TIED PLEDGES
_setRequestData(_requestId, percentageDiff, pledgeThreshold, timeUntilDeadline, timeToBreakInequality);
vm.prank(address(oracle));
module.resolveDispute(_disputeId);

(IBondEscalationResolutionModule.Resolution _trueResStatus,,,) = module.escalationData(_disputeId);
Expand Down Expand Up @@ -463,6 +470,7 @@ contract BondEscalationResolutionModule_UnitTest is Test {
);
vm.expectCall(address(oracle), abi.encodeCall(IOracle.updateDisputeStatus, (_disputeId, IOracle.DisputeStatus.Won)));

vm.prank(address(oracle));
module.resolveDispute(_disputeId);

(IBondEscalationResolutionModule.Resolution _trueResStatus,,,) = module.escalationData(_disputeId);
Expand Down Expand Up @@ -499,6 +507,7 @@ contract BondEscalationResolutionModule_UnitTest is Test {
address(oracle), abi.encodeCall(IOracle.updateDisputeStatus, (_disputeId, IOracle.DisputeStatus.Lost))
);

vm.prank(address(oracle));
module.resolveDispute(_disputeId);

(IBondEscalationResolutionModule.Resolution _trueResStatus,,,) = module.escalationData(_disputeId);
Expand Down
Loading

0 comments on commit af489e0

Please sign in to comment.