feat: allow specifying a timeout for arbitrators and escalating a dispute to the fallback arbitrator once the timeout passes. (#672)
This commit is contained in:
parent
9be0c1b189
commit
97a966b9f7
|
@ -3,6 +3,7 @@ pragma solidity >=0.5.0 <0.6.0;
|
||||||
|
|
||||||
import "./ArbitrationLicense.sol";
|
import "./ArbitrationLicense.sol";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arbitrable
|
* Arbitrable
|
||||||
* @dev Utils for management of disputes
|
* @dev Utils for management of disputes
|
||||||
|
@ -19,6 +20,8 @@ contract Arbitrable {
|
||||||
|
|
||||||
address public fallbackArbitrator;
|
address public fallbackArbitrator;
|
||||||
|
|
||||||
|
uint public arbitrationTimeout;
|
||||||
|
|
||||||
struct ArbitrationCase {
|
struct ArbitrationCase {
|
||||||
bool open;
|
bool open;
|
||||||
address openBy;
|
address openBy;
|
||||||
|
@ -28,17 +31,19 @@ contract Arbitrable {
|
||||||
ArbitrationMotive motive;
|
ArbitrationMotive motive;
|
||||||
}
|
}
|
||||||
|
|
||||||
event ArbitratorChanged(address arbitrator);
|
event ArbitratorChanged(uint escrowId, address sender, address ogArbitrator, address newArbitrator);
|
||||||
event ArbitrationCanceled(uint escrowId);
|
event ArbitrationCanceled(uint escrowId);
|
||||||
event ArbitrationRequired(uint escrowId, uint timeout);
|
event ArbitrationRequired(uint escrowId, uint timeout);
|
||||||
event ArbitrationResolved(uint escrowId, ArbitrationResult result, address arbitrator);
|
event ArbitrationResolved(uint escrowId, ArbitrationResult result, address arbitrator);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param _arbitratorLicenses Address of the Arbitrator Licenses contract
|
* @param _arbitratorLicenses Address of the Arbitrator Licenses contract
|
||||||
|
* @param _fallbackArbitrator Address of the fallback arbitrator in case the original arbitrator does not work on a dispute
|
||||||
*/
|
*/
|
||||||
constructor(address _arbitratorLicenses, address _fallbackArbitrator) public {
|
constructor(address _arbitratorLicenses, address _fallbackArbitrator) public {
|
||||||
arbitratorLicenses = ArbitrationLicense(_arbitratorLicenses);
|
arbitratorLicenses = ArbitrationLicense(_arbitratorLicenses);
|
||||||
fallbackArbitrator = _fallbackArbitrator;
|
fallbackArbitrator = _fallbackArbitrator;
|
||||||
|
arbitrationTimeout = 5 days;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,8 +88,8 @@ contract Arbitrable {
|
||||||
*/
|
*/
|
||||||
function cancelArbitration(uint _escrowId) external {
|
function cancelArbitration(uint _escrowId) external {
|
||||||
require(arbitrationCases[_escrowId].openBy == msg.sender, "Arbitration can only be canceled by the opener");
|
require(arbitrationCases[_escrowId].openBy == msg.sender, "Arbitration can only be canceled by the opener");
|
||||||
require(arbitrationCases[_escrowId].result == ArbitrationResult.UNSOLVED && arbitrationCases[_escrowId].open,
|
require(arbitrationCases[_escrowId].result == ArbitrationResult.UNSOLVED && arbitrationCases[_escrowId].open,
|
||||||
"Arbitration already solved or not open");
|
"Arbitration already solved or not open");
|
||||||
|
|
||||||
delete arbitrationCases[_escrowId];
|
delete arbitrationCases[_escrowId];
|
||||||
|
|
||||||
|
@ -105,7 +110,7 @@ contract Arbitrable {
|
||||||
|
|
||||||
require(arbitratorAddress != address(0), "Arbitrator is required");
|
require(arbitratorAddress != address(0), "Arbitrator is required");
|
||||||
|
|
||||||
uint timeout = block.timestamp + 5 days;
|
uint timeout = block.timestamp + arbitrationTimeout;
|
||||||
|
|
||||||
arbitrationCases[_escrowId] = ArbitrationCase({
|
arbitrationCases[_escrowId] = ArbitrationCase({
|
||||||
open: true,
|
open: true,
|
||||||
|
@ -119,6 +124,18 @@ contract Arbitrable {
|
||||||
emit ArbitrationRequired(_escrowId, timeout);
|
emit ArbitrationRequired(_escrowId, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Allow participants to escalate dispute to fallback arbitrator after timeout
|
||||||
|
* @param _escrowId Id of the Escrow that is being disputed
|
||||||
|
*/
|
||||||
|
function escalateDispute(uint _escrowId) external {
|
||||||
|
require(arbitrationCases[_escrowId].open && arbitrationCases[_escrowId].result == ArbitrationResult.UNSOLVED, "Case must be open and unsolved");
|
||||||
|
require(block.timestamp > arbitrationCases[_escrowId].arbitratorTimeout, "Arbitration is still active");
|
||||||
|
|
||||||
|
emit ArbitratorChanged(_escrowId, msg.sender, arbitrationCases[_escrowId].arbitrator, fallbackArbitrator);
|
||||||
|
arbitrationCases[_escrowId].arbitrator = fallbackArbitrator;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @notice Set arbitration result in favour of the buyer or seller and transfer funds accordingly
|
* @notice Set arbitration result in favour of the buyer or seller and transfer funds accordingly
|
||||||
* @param _escrowId Id of the escrow
|
* @param _escrowId Id of the escrow
|
||||||
|
@ -128,11 +145,15 @@ contract Arbitrable {
|
||||||
require(arbitrationCases[_escrowId].open && arbitrationCases[_escrowId].result == ArbitrationResult.UNSOLVED,
|
require(arbitrationCases[_escrowId].open && arbitrationCases[_escrowId].result == ArbitrationResult.UNSOLVED,
|
||||||
"Case must be open and unsolved");
|
"Case must be open and unsolved");
|
||||||
require(_result != ArbitrationResult.UNSOLVED, "Arbitration does not have result");
|
require(_result != ArbitrationResult.UNSOLVED, "Arbitration does not have result");
|
||||||
require(arbitratorLicenses.isLicenseOwner(msg.sender), "Only arbitrators can invoke this function");
|
|
||||||
|
|
||||||
if (block.timestamp > arbitrationCases[_escrowId].arbitratorTimeout) {
|
if (msg.sender == fallbackArbitrator) {
|
||||||
require(arbitrationCases[_escrowId].arbitrator == msg.sender || msg.sender == fallbackArbitrator, "Invalid escrow arbitrator");
|
require(block.timestamp > arbitrationCases[_escrowId].arbitratorTimeout, "Arbitration is still active");
|
||||||
|
if (arbitrationCases[_escrowId].arbitrator != msg.sender) {
|
||||||
|
emit ArbitratorChanged(_escrowId, arbitrationCases[_escrowId].arbitrator, msg.sender);
|
||||||
|
arbitrationCases[_escrowId].arbitrator = msg.sender;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
require(arbitratorLicenses.isLicenseOwner(msg.sender), "Only arbitrators can invoke this function");
|
||||||
require(arbitrationCases[_escrowId].arbitrator == msg.sender, "Invalid escrow arbitrator");
|
require(arbitrationCases[_escrowId].arbitrator == msg.sender, "Invalid escrow arbitrator");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +162,7 @@ contract Arbitrable {
|
||||||
|
|
||||||
emit ArbitrationResolved(_escrowId, _result, msg.sender);
|
emit ArbitrationResolved(_escrowId, _result, msg.sender);
|
||||||
|
|
||||||
if(_result == ArbitrationResult.BUYER){
|
if (_result == ArbitrationResult.BUYER) {
|
||||||
_solveDispute(_escrowId, true, msg.sender);
|
_solveDispute(_escrowId, true, msg.sender);
|
||||||
} else {
|
} else {
|
||||||
_solveDispute(_escrowId, false, msg.sender);
|
_solveDispute(_escrowId, false, msg.sender);
|
||||||
|
|
|
@ -94,9 +94,23 @@ contract Escrow is IEscrow, Pausable, MessageSigned, Fees, Arbitrable, Proxiable
|
||||||
feeDestination = _feeDestination;
|
feeDestination = _feeDestination;
|
||||||
feeMilliPercent = _feeMilliPercent;
|
feeMilliPercent = _feeMilliPercent;
|
||||||
paused = false;
|
paused = false;
|
||||||
|
arbitrationTimeout = 5 days;
|
||||||
|
|
||||||
_setOwner(msg.sender);
|
_setOwner(msg.sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Update arbitration timeout. Can only be called by owner
|
||||||
|
* @param _newTimeout new timeout in seconds
|
||||||
|
*/
|
||||||
|
function updateArbitrationTimeout(uint _newTimeout) public onlyOwner {
|
||||||
|
arbitrationTimeout = _newTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Update proxy implementation. Can only be called by owner
|
||||||
|
* @param _newCode New contract implementation address
|
||||||
|
*/
|
||||||
function updateCode(address newCode) public onlyOwner {
|
function updateCode(address newCode) public onlyOwner {
|
||||||
updateCodeAddress(newCode);
|
updateCodeAddress(newCode);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue