diff --git a/contracts/standard/arbitration/composed-arbitrable/agreement/MultiPartyAgreements.sol b/contracts/standard/arbitration/composed-arbitrable/agreement/MultiPartyAgreements.sol deleted file mode 100644 index fbb99639..00000000 --- a/contracts/standard/arbitration/composed-arbitrable/agreement/MultiPartyAgreements.sol +++ /dev/null @@ -1,144 +0,0 @@ -pragma solidity ^0.4.24; - -import "../../Arbitrable.sol"; - -/** - * @title MultiPartyAgreements - * @author Enrique Piqueras - - * @dev Agreement part of a composed arbitrable contract. Handles multi-party, multi-choice dispute agreements. - */ -contract MultiPartyAgreements is Arbitrable { - /* Structs */ - - struct Agreement { - address creator; // The agreement's creator. - address[] parties; // The involved parties. - uint numberOfChoices; // The number of choices in a dispute arising from the agreement. - bytes extraData; // The extra data in a dispute arising from the agreement. - uint arbitrationFeesWaitingTime; // The maximum time to wait for arbitration fees. - Arbitrator arbitrator; // The arbitrator to use in a dispute arising from the agreement. - uint disputeID; // The agreement's dispute ID, if disputed. - bool disputed; // Wether the agreement is disputed or not. - bool appealed; // Wether the agreement's dispute has been appealed or not. - uint ruling; // The final ruling for the agreement's dispute. - bool executed; // Wether the agreement has been executed or not. - } - - /* Storage */ - - mapping(bytes32 => Agreement) public agreements; - mapping(address => mapping(uint => bytes32)) public arbitratorAndDisputeIDToAgreementID; - - /* Constructor */ - - /** @dev Constructs the `MultiPartyAgreements` contract. - * @param _arbitrator The arbitrator of the contract. - * @param _arbitratorExtraData Extra data for the arbitrator. - */ - constructor(Arbitrator _arbitrator, bytes _arbitratorExtraData) public Arbitrable(_arbitrator, _arbitratorExtraData) {} - - /* Public */ - - /** @dev Executes the ruling on the specified dispute. - * @param _disputeID The ID of the dispute. - * @param _ruling The ruling. - */ - function rule(uint _disputeID, uint _ruling) public { - require( - agreements[arbitratorAndDisputeIDToAgreementID[msg.sender][_disputeID]].arbitrator == Arbitrator(msg.sender), - "A dispute can only be ruled on by its arbitrator." - ); - emit Ruling(Arbitrator(msg.sender), _disputeID, _ruling); - executeRuling(_disputeID, _ruling); - } - - /* Internal */ - - /** @dev Creates an agreement. - * @param _agreementID The ID of the agreement. - * @param _metaEvidence The meta evidence of the agreement. - * @param _parties The `parties` value of the agreement. - * @param _numberOfChoices The `numberOfChoices` value of the agreement. - * @param _extraData The `extraData` value of the agreement. - * @param _arbitrationFeesWaitingTime The `arbitrationFeesWaitingTime` value of the agreement. - * @param _arbitrator The `arbitrator` value of the agreement. - */ - function _createAgreement( - bytes32 _agreementID, - string _metaEvidence, - address[] _parties, - uint _numberOfChoices, - bytes _extraData, - uint _arbitrationFeesWaitingTime, - Arbitrator _arbitrator - ) internal { - require(agreements[_agreementID].creator == address(0), "The supplied agreement ID is already being used."); - require(_parties.length <= 10, "There cannot be more than 10 parties."); - agreements[_agreementID] = Agreement({ - creator: msg.sender, - parties: _parties, - numberOfChoices: _numberOfChoices, - extraData: _extraData, - arbitrationFeesWaitingTime: _arbitrationFeesWaitingTime, - arbitrator: _arbitrator, - disputeID: 0, - disputed: false, - appealed: false, - ruling: 0, - executed: false - }); - emit MetaEvidence(uint(_agreementID), _metaEvidence); - } - - /** @dev Executes the ruling on the specified agreement. - * @param _agreementID The ID of the agreement. - * @param _ruling The ruling. - */ - function executeAgreementRuling(bytes32 _agreementID, uint _ruling) internal { - Agreement storage agreement = agreements[_agreementID]; - require(agreement.creator != address(0), "The specified agreement does not exist."); - require(!agreement.executed, "The specified agreement has already been executed."); - agreement.ruling = _ruling; - agreement.executed = true; - } - - /** @dev Executes the ruling on the specified dispute. - * @param _disputeID The ID of the dispute. - * @param _ruling The ruling. - */ - function executeRuling(uint _disputeID, uint _ruling) internal { - executeAgreementRuling(arbitratorAndDisputeIDToAgreementID[msg.sender][_disputeID], _ruling); - } - - /* External Views */ - - /** @dev Gets the info on the specified agreement. - * @param _agreementID The ID of the agreement. - * @return The info. - */ - function getAgreementInfo(bytes32 _agreementID) external view returns( - address creator, - address[] parties, - uint numberOfChoices, - bytes extraData, - uint arbitrationFeesWaitingTime, - Arbitrator arbitrator, - uint disputeID, - bool disputed, - bool appealed, - uint ruling, - bool executed - ) { - creator = agreements[_agreementID].creator; - parties = agreements[_agreementID].parties; - numberOfChoices = agreements[_agreementID].numberOfChoices; - extraData = agreements[_agreementID].extraData; - arbitrationFeesWaitingTime = agreements[_agreementID].arbitrationFeesWaitingTime; - arbitrator = agreements[_agreementID].arbitrator; - disputeID = agreements[_agreementID].disputeID; - disputed = agreements[_agreementID].disputed; - appealed = agreements[_agreementID].appealed; - ruling = agreements[_agreementID].ruling; - executed = agreements[_agreementID].executed; - } -} diff --git a/contracts/standard/arbitration/composed-arbitrable/composed/MultiPartyInsurableArbitrableAgreementsBase.sol b/contracts/standard/arbitration/composed-arbitrable/composed/MultiPartyInsurableArbitrableAgreementsBase.sol deleted file mode 100644 index 8281fb1c..00000000 --- a/contracts/standard/arbitration/composed-arbitrable/composed/MultiPartyInsurableArbitrableAgreementsBase.sol +++ /dev/null @@ -1,27 +0,0 @@ -pragma solidity ^0.4.24; - -import "../agreement/MultiPartyAgreements.sol"; -import "../fee/MultiPartyInsurableFees.sol"; -import "../evidence/MultiPartyEvidence.sol"; - -/** - * @title MultiPartyInsurableArbitrableAgreementsBase - * @author Enrique Piqueras - - * @dev Base composed arbitrable contract. Handles multi-party, multi-choice dispute agreements with party evidence and crowdinsured arbitration and appeal fees. - */ -contract MultiPartyInsurableArbitrableAgreementsBase is MultiPartyAgreements, MultiPartyInsurableFees, MultiPartyEvidence { - /* Constructor */ - - /** @dev Constructs the `MultiPartyInsurableArbitrableAgreementsBase` contract. - * @param _arbitrator The arbitrator of the contract. - * @param _arbitratorExtraData Extra data for the arbitrator. - * @param _feeGovernor The fee governor of this contract. - * @param _stake The stake parameter for sharing fees. - */ - constructor( - Arbitrator _arbitrator, - bytes _arbitratorExtraData, - address _feeGovernor, - uint _stake - ) public MultiPartyAgreements(_arbitrator, _arbitratorExtraData) MultiPartyInsurableFees(_feeGovernor, _stake) {} -} diff --git a/contracts/standard/arbitration/composed-arbitrable/evidence/MultiPartyEvidence.sol b/contracts/standard/arbitration/composed-arbitrable/evidence/MultiPartyEvidence.sol deleted file mode 100644 index 2c994913..00000000 --- a/contracts/standard/arbitration/composed-arbitrable/evidence/MultiPartyEvidence.sol +++ /dev/null @@ -1,27 +0,0 @@ -pragma solidity ^0.4.24; - -import "../agreement/MultiPartyAgreements.sol"; - -/** - * @title MultiPartyEvidence - * @author Enrique Piqueras - - * @dev Evidence part of a composed arbitrable contract. Only allows evidence submission from parties involved in the agreement and in the first round. - */ -contract MultiPartyEvidence is MultiPartyAgreements { - /* Public */ - - /** @dev Submits evidence for a dispute arising from the specified agreement. - * @param _agreementID The agreement's ID. - * @param _evidence The evidence. - */ - function submitEvidence(bytes32 _agreementID, string _evidence) public { - require(agreements[_agreementID].creator != address(0), "The specified agreement does not exist."); - require(agreements[_agreementID].disputed, "The specified agreement is not disputed."); - require(!agreements[_agreementID].appealed, "The specified agreement has already been appealed."); - bool _senderIsInvolved = false; - for (uint i = 0; i < agreements[_agreementID].parties.length; i++) - if (agreements[_agreementID].parties[i] == msg.sender) _senderIsInvolved = true; - require(_senderIsInvolved, "The sender is not a party in the specified agreement."); - emit Evidence(agreements[_agreementID].arbitrator, agreements[_agreementID].disputeID, msg.sender, _evidence); - } -} diff --git a/contracts/standard/arbitration/composed-arbitrable/example/TwoPartyArbitrableEscrowPayment.sol b/contracts/standard/arbitration/composed-arbitrable/example/TwoPartyArbitrableEscrowPayment.sol deleted file mode 100644 index af54097b..00000000 --- a/contracts/standard/arbitration/composed-arbitrable/example/TwoPartyArbitrableEscrowPayment.sol +++ /dev/null @@ -1,135 +0,0 @@ -pragma solidity ^0.4.24; - -import "../composed/MultiPartyInsurableArbitrableAgreementsBase.sol"; - -/** - * @title TwoPartyArbitrableEscrowPayment - * @author Enrique Piqueras - - * @dev Implementation of a two party arbitrable escrow service using the `MultiPartyInsurableArbitrableAgreementsBase` contract. - */ -contract TwoPartyArbitrableEscrowPayment is MultiPartyInsurableArbitrableAgreementsBase { - /* Structs */ - - struct Payment { - uint value; - uint createdAt; - uint timeOut; - } - - /* Events */ - - /** @dev Emitted when a payment is executed. - * @param _paymentID The ID of the payment. - * @param _sender The address of the sender. - * @param _receiver The address of the receiver. - * @param _value The value of the payment. - */ - event PaymentExecuted(bytes32 indexed _paymentID, address indexed _sender, address indexed _receiver, uint _value); - - /* Storage */ - - mapping(bytes32 => Payment) public payments; - - /* Constructor */ - - /** @dev Constructs the `TwoPartyArbitrableEscrowPayment` contract. - * @param _arbitrator The arbitrator of the contract. - * @param _arbitratorExtraData Extra data for the arbitrator. - * @param _feeGovernor The fee governor of this contract. - * @param _stake The stake parameter for sharing fees. - */ - constructor( - Arbitrator _arbitrator, - bytes _arbitratorExtraData, - address _feeGovernor, - uint _stake - ) public MultiPartyInsurableArbitrableAgreementsBase(_arbitrator, _arbitratorExtraData, _feeGovernor, _stake) {} - - /* External */ - - /** @dev Creates an escrowed payment. - * @param _paymentID The ID of the payment. - * @param _metaEvidence The meta evidence for the potential dispute. - * @param _to The receiver of the payment. - * @param _arbitrationFeesWaitingTime The maximum time to wait for arbitration fees if the dispute is raised. - * @param _arbitrator The arbitrator to use for the potential dispute. - * @param _timeOut The time to wait before executing the payment if the dispute is not raised. - */ - function createPayment( - bytes32 _paymentID, - string _metaEvidence, - address _to, - uint _arbitrationFeesWaitingTime, - Arbitrator _arbitrator, - uint _timeOut - ) external payable { - require(msg.value > 0, "Payment must be more than zero."); - address[] memory _parties = new address[](2); - _parties[0] = msg.sender; - _parties[1] = _to; - _createAgreement( - _paymentID, - _metaEvidence, - _parties, - 2, - new bytes(0), - _arbitrationFeesWaitingTime, - _arbitrator - ); - payments[_paymentID] = Payment({ - value: msg.value, - createdAt: now, - timeOut: _timeOut - }); - } - - /** @dev Executes a payment that has already timed out and is not disputed. - * @param _paymentID The ID of the payment. - */ - function executePayment(bytes32 _paymentID) external { - Agreement storage agreement = agreements[_paymentID]; - Payment storage payment = payments[_paymentID]; - require(agreement.creator != address(0), "The specified payment does not exist."); - require(!agreement.executed, "The specified payment has already been executed."); - require(!agreement.disputed, "The specified payment is disputed."); - require(now - payment.createdAt > payment.timeOut, "The specified payment has not timed out yet."); - agreement.parties[1].send(payment.value); // Avoid blocking. - agreement.executed = true; - emit PaymentExecuted(_paymentID, agreement.parties[0], agreement.parties[1], payment.value); - } - - /* Internal */ - - /** @dev Executes the ruling on the specified agreement. - * @param _agreementID The ID of the agreement. - * @param _ruling The ruling. - */ - function executeAgreementRuling(bytes32 _agreementID, uint _ruling) internal { - super.executeAgreementRuling(_agreementID, _ruling); - Agreement storage agreement = agreements[_agreementID]; - PaidFees storage _paidFees = paidFees[_agreementID]; - Payment storage payment = payments[_agreementID]; - - address _receiver; - if (_paidFees.stake.length == 1) { // Failed to fund first round. - // Send the value to whoever paid more. - if (_paidFees.totalContributedPerSide[0][0] >= _paidFees.totalContributedPerSide[0][1]) - _receiver = agreement.parties[0]; - else - _receiver = agreement.parties[1]; - } else { // Failed to fund a later round. - // Respect the ruling unless the losing side funded the appeal and the winning side paid less than expected. - if ( - _paidFees.loserFullyFunded[_paidFees.loserFullyFunded.length - 1] && - _paidFees.totalContributedPerSide[_paidFees.totalContributedPerSide.length - 1][0] - _paidFees.stake[_paidFees.stake.length - 1] > _paidFees.totalContributedPerSide[_paidFees.totalContributedPerSide.length - 1][1] - ) - _receiver = agreement.parties[_ruling == 2 ? 0 : 1]; - else - _receiver = agreement.parties[_ruling == 2 ? 1 : 0]; - } - - _receiver.send(payment.value); // Avoid blocking. - agreement.executed = true; - emit PaymentExecuted(_agreementID, agreement.parties[0], _receiver, payment.value); - } -} diff --git a/contracts/standard/arbitration/composed-arbitrable/example/TwoPartyArbitrableEscrowPaymentProxyUser.sol b/contracts/standard/arbitration/composed-arbitrable/example/TwoPartyArbitrableEscrowPaymentProxyUser.sol deleted file mode 100644 index 356c1249..00000000 --- a/contracts/standard/arbitration/composed-arbitrable/example/TwoPartyArbitrableEscrowPaymentProxyUser.sol +++ /dev/null @@ -1,159 +0,0 @@ -pragma solidity ^0.4.24; -pragma experimental ABIEncoderV2; - -import "../proxy/ArbitrableProxyUser.sol"; - -/** - * @title TwoPartyArbitrableEscrowPaymentProxyUser - * @author Enrique Piqueras - - * @dev Implementation of a two party arbitrable escrow service using the `ArbitrableProxyUser` contract. - */ -contract TwoPartyArbitrableEscrowPaymentProxyUser is ArbitrableProxyUser { - /* Structs */ - - struct Payment { - uint value; - uint createdAt; - uint timeOut; - bool executed; - } - - /* Events */ - - /** @dev Emitted when a payment is executed. - * @param _paymentID The ID of the payment. - * @param _sender The address of the sender. - * @param _receiver The address of the receiver. - * @param _value The value of the payment. - */ - event PaymentExecuted(bytes32 indexed _paymentID, address indexed _sender, address indexed _receiver, uint _value); - - /* Storage */ - - mapping(bytes32 => Payment) public payments; - - /* Constructor */ - - /** @dev Constructs the `TwoPartyArbitrableEscrowPaymentProxyUser` contract. - * @param _arbitrableProxy The arbitrable proxy to use. - */ - constructor(ArbitrableProxy _arbitrableProxy) public ArbitrableProxyUser(_arbitrableProxy) {} - - /* External */ - - /** @dev Creates an escrowed payment. - * @param _paymentID The ID of the payment. - * @param _metaEvidence The meta evidence for the potential dispute. - * @param _to The receiver of the payment. - * @param _arbitrationFeesWaitingTime The maximum time to wait for arbitration fees if the dispute is raised. - * @param _arbitrator The arbitrator to use for the potential dispute. - * @param _timeOut The time to wait before executing the payment if the dispute is not raised. - */ - function createPayment( - bytes32 _paymentID, - string _metaEvidence, - address _to, - uint _arbitrationFeesWaitingTime, - Arbitrator _arbitrator, - uint _timeOut - ) external payable { - require(msg.value > 0, "Payment must be more than zero."); - address[] memory _parties = new address[](2); - _parties[0] = msg.sender; - _parties[1] = _to; - arbitrableProxy.createAgreement( - _paymentID, - _metaEvidence, - _parties, - 2, - new bytes(0), - _arbitrationFeesWaitingTime, - _arbitrator - ); - payments[_paymentID] = Payment({ - value: msg.value, - createdAt: now, - timeOut: _timeOut, - executed: false - }); - } - - /** @dev Executes a payment that has already timed out and is not disputed. - * @param _paymentID The ID of the payment. - */ - function executePayment(bytes32 _paymentID) external { - ( - address _creator, - address[] memory _parties, - , - , - , - , - , - bool _disputed, - , - , - ) = arbitrableProxy.getAgreementInfo(_paymentID); - Payment storage payment = payments[_paymentID]; - require(_creator != address(0), "The specified payment does not exist."); - require(!payment.executed, "The specified payment has already been executed."); - require(!_disputed, "The specified payment is disputed."); - require(now - payment.createdAt > payment.timeOut, "The specified payment has not timed out yet."); - _parties[1].send(payment.value); // Avoid blocking. - payment.executed = true; - emit PaymentExecuted(_paymentID, _parties[0], _parties[1], payment.value); - } - - /* Public */ - - /** @dev Executes the ruling on the specified agreement. - * @param _agreementID The ID of the agreement. - * @param _ruling The ruling. - */ - function executeAgreementRuling(bytes32 _agreementID, uint _ruling) public { - super.executeAgreementRuling(_agreementID, _ruling); - ( - , - address[] memory _parties, - , - , - , - , - , - , - , - , - ) = arbitrableProxy.getAgreementInfo(_agreementID); - ( - , - uint[] memory _stake, - , - uint[2][] memory _totalContributedPerSide, - bool[] memory _loserFullyFunded - ) = arbitrableProxy.getFeesInfo(_agreementID); - Payment storage payment = payments[_agreementID]; - require(!payment.executed, "The specified agreement has already been executed."); - - address _receiver; - if (_stake.length == 1) { // Failed to fund first round. - // Send the value to whoever paid more. - if (_totalContributedPerSide[0][0] >= _totalContributedPerSide[0][1]) - _receiver = _parties[0]; - else - _receiver = _parties[1]; - } else { // Failed to fund a later round. - // Respect the ruling unless the losing side funded the appeal and the winning side paid less than expected. - if ( - _loserFullyFunded[_loserFullyFunded.length - 1] && - _totalContributedPerSide[_totalContributedPerSide.length - 1][0] - _stake[_stake.length - 1] > _totalContributedPerSide[_totalContributedPerSide.length - 1][1] - ) - _receiver = _parties[_ruling == 2 ? 0 : 1]; - else - _receiver = _parties[_ruling == 2 ? 1 : 0]; - } - - _receiver.send(payment.value); // Avoid blocking. - payment.executed = true; - emit PaymentExecuted(_agreementID, _parties[0], _receiver, payment.value); - } -} diff --git a/contracts/standard/arbitration/composed-arbitrable/fee/MultiPartyInsurableFees.sol b/contracts/standard/arbitration/composed-arbitrable/fee/MultiPartyInsurableFees.sol deleted file mode 100644 index 6578e4c7..00000000 --- a/contracts/standard/arbitration/composed-arbitrable/fee/MultiPartyInsurableFees.sol +++ /dev/null @@ -1,277 +0,0 @@ -pragma solidity ^0.4.24; - -import "../agreement/MultiPartyAgreements.sol"; - -/** - * @title MultiPartyInsurableFees - * @author Enrique Piqueras - - * @dev Fee part of a composed arbitrable contract. Handles crowdinsured arbitration and appeal fees. - */ -contract MultiPartyInsurableFees is MultiPartyAgreements { - /* Structs */ - - struct PaidFees { - uint firstContributionTime; // The time the first contribution was made at. - uint[] ruling; // The ruling for each round. - uint[] stake; // The stake required for each round. - uint[] totalValue; // The current held value for each round. - uint[2][] totalContributedPerSide; // The total amount contributed per side for each round. - bool[] loserFullyFunded; // Wether the loser fully funded the appeal for each round. - mapping(address => uint[2])[] contributions; // The contributions for each round. - } - struct FundDisputeCache { // Needed to avoid stack depth error in `fundDispute()`. - uint cost; - bool appealing; - uint appealPeriodStart; - uint appealPeriodEnd; - bool appealPeriodSupported; - uint requiredValueForSide; - uint expectedValue; - uint stillRequiredValueForSide; - uint keptValue; - uint refundedValue; - } - - /* Events */ - - /** @dev Emitted when a contribution is made. - * @param _agreementID The ID of the agreement that the contribution was made to. - * @param _round The round of the agreement that the contribution was made to. - * @param _contributor The address that sent the contribution. - * @param _value The value of the contribution. - */ - event Contribution(bytes32 indexed _agreementID, uint indexed _round, address indexed _contributor, uint _value); - - /** @dev Emitted when a contribution reward is withdrawn. - * @param _agreementID The ID of the agreement that the contribution was made to. - * @param _round The round of the agreement that the contribution was made to. - * @param _contributor The address that sent the contribution. - * @param _value The value of the reward. - */ - event RewardWithdrawal(bytes32 indexed _agreementID, uint indexed _round, address indexed _contributor, uint _value); - - /* Storage */ - - address public feeGovernor; - uint public stake; - mapping(bytes32 => PaidFees) public paidFees; - FundDisputeCache public fundDisputeCache; - - /* Constructor */ - - /** @dev Constructs the `MultiPartyInsurableFees` contract. - * @param _feeGovernor The governor of this contract. - * @param _stake The stake parameter for sharing fees. - */ - constructor(address _feeGovernor, uint _stake) public { - feeGovernor = _feeGovernor; - stake = _stake; - } - - /* Public */ - - /** @dev Changes the `feeGovernor` storage variable. - * @param _feeGovernor The new `feeGovernor` storage variable. - */ - function changeFeeGovernor(address _feeGovernor) public { - require(msg.sender == feeGovernor, "The caller is not the fee governor."); - feeGovernor = _feeGovernor; - } - - /** @dev Changes the `stake` storage variable. - * @param _stake The new `stake` storage variable. - */ - function changeStake(uint _stake) public { - require(msg.sender == feeGovernor, "The caller is not the fee governor."); - stake = _stake; - } - - /** @dev Funds the specified side of a dispute for the specified agreement or times out the dispute if it is taking too long to fund. - * @param _agreementID The ID of the agreement. - * @param _side The side. 0 for the side that lost the previous round, if any, and 1 for the one that won. - */ - function fundDispute(bytes32 _agreementID, uint _side) public payable { - Agreement storage agreement = agreements[_agreementID]; - PaidFees storage _paidFees = paidFees[_agreementID]; - require(agreement.creator != address(0), "The specified agreement does not exist."); - require(!agreement.executed, "You cannot fund disputes for executed agreements."); - require( - !agreement.disputed || agreement.arbitrator.disputeStatus(agreement.disputeID) == Arbitrator.DisputeStatus.Appealable, - "The agreement is already disputed and is not appealable." - ); - require(_side <= 1, "There are only two sides."); - require(msg.value > 0, "The value of the contribution cannot be zero."); - - // Prepare storage for first call. - if (_paidFees.firstContributionTime == 0) { - _paidFees.firstContributionTime = now; - _paidFees.ruling.push(0); - _paidFees.stake.push(stake); - _paidFees.totalValue.push(0); - _paidFees.totalContributedPerSide.push([0, 0]); - _paidFees.loserFullyFunded.push(false); - _paidFees.contributions.length++; - } else { // Reset cache - fundDisputeCache.cost = 0; - fundDisputeCache.appealing = false; - (fundDisputeCache.appealPeriodStart, fundDisputeCache.appealPeriodEnd) = (0, 0); - fundDisputeCache.appealPeriodSupported = false; - fundDisputeCache.requiredValueForSide = 0; - fundDisputeCache.expectedValue = 0; - fundDisputeCache.stillRequiredValueForSide = 0; - fundDisputeCache.keptValue = 0; - fundDisputeCache.refundedValue = 0; - } - - // Check time outs and requirements. - if (_paidFees.stake.length == 1) { // First round. - fundDisputeCache.cost = agreement.arbitrator.arbitrationCost(agreement.extraData); - - // Arbitration fees time out. - if (now - _paidFees.firstContributionTime > agreement.arbitrationFeesWaitingTime) { - executeAgreementRuling(_agreementID, 0); - return; - } - } else { // Appeal. - fundDisputeCache.cost = agreement.arbitrator.appealCost(agreement.disputeID, agreement.extraData); - - fundDisputeCache.appealing = true; - (fundDisputeCache.appealPeriodStart, fundDisputeCache.appealPeriodEnd) = agreement.arbitrator.appealPeriod(agreement.disputeID); - fundDisputeCache.appealPeriodSupported = fundDisputeCache.appealPeriodStart != 0 && fundDisputeCache.appealPeriodEnd != 0; - if (fundDisputeCache.appealPeriodSupported) { - if (now < fundDisputeCache.appealPeriodStart + ((fundDisputeCache.appealPeriodEnd - fundDisputeCache.appealPeriodStart) / 2)) // In the first half of the appeal period. - require(_side == 0, "It is the losing side's turn to fund the appeal."); - else // In the second half of the appeal period. - require( - _side == 1 && _paidFees.loserFullyFunded[_paidFees.loserFullyFunded.length - 1], - "It is the winning side's turn to fund the appeal, only if the losing side already fully funded it." - ); - } else require(msg.value >= fundDisputeCache.cost, "Fees must be paid in full if the arbitrator does not support `appealPeriod`."); - } - - // Compute required value. - if (!fundDisputeCache.appealing) // First round. - fundDisputeCache.requiredValueForSide = fundDisputeCache.cost / 2; - else { // Appeal. - if (!fundDisputeCache.appealPeriodSupported) - fundDisputeCache.requiredValueForSide = fundDisputeCache.cost; - else if (_side == 0) // Losing side. - fundDisputeCache.requiredValueForSide = fundDisputeCache.cost + (2 * _paidFees.stake[_paidFees.stake.length - 1]); - else { // Winning side. - fundDisputeCache.expectedValue = _paidFees.totalContributedPerSide[_paidFees.totalContributedPerSide.length - 1][0] - _paidFees.stake[_paidFees.stake.length - 1]; - fundDisputeCache.requiredValueForSide = fundDisputeCache.cost > _paidFees.totalContributedPerSide[_paidFees.totalContributedPerSide.length - 1][0] + fundDisputeCache.expectedValue ? fundDisputeCache.cost - _paidFees.totalContributedPerSide[_paidFees.totalContributedPerSide.length - 1][0] : fundDisputeCache.expectedValue; - } - } - - // Take contribution. - if (_paidFees.totalContributedPerSide[_paidFees.totalContributedPerSide.length - 1][_side] >= fundDisputeCache.requiredValueForSide) - fundDisputeCache.stillRequiredValueForSide = 0; - else - fundDisputeCache.stillRequiredValueForSide = fundDisputeCache.requiredValueForSide - _paidFees.totalContributedPerSide[_paidFees.totalContributedPerSide.length - 1][_side]; - fundDisputeCache.keptValue = fundDisputeCache.stillRequiredValueForSide >= msg.value ? - msg.value : fundDisputeCache.stillRequiredValueForSide; - fundDisputeCache.refundedValue = msg.value - fundDisputeCache.keptValue; - if (fundDisputeCache.keptValue > 0) { - _paidFees.totalValue[_paidFees.totalValue.length - 1] += fundDisputeCache.keptValue; - _paidFees.totalContributedPerSide[_paidFees.totalContributedPerSide.length - 1][_side] += fundDisputeCache.keptValue; - _paidFees.contributions[_paidFees.contributions.length - 1][msg.sender][_side] += fundDisputeCache.keptValue; - } - if (fundDisputeCache.refundedValue > 0) msg.sender.transfer(fundDisputeCache.refundedValue); - emit Contribution(_agreementID, _paidFees.stake.length - 1, msg.sender, fundDisputeCache.keptValue); - - // Check if enough funds have been gathered and act accordingly. - if ( - _paidFees.totalContributedPerSide[_paidFees.totalContributedPerSide.length - 1][_side] >= fundDisputeCache.requiredValueForSide || - (fundDisputeCache.appealing && !fundDisputeCache.appealPeriodSupported) - ) { - if (_side == 0 && (fundDisputeCache.appealing ? fundDisputeCache.appealPeriodSupported : _paidFees.totalContributedPerSide[_paidFees.totalContributedPerSide.length - 1][1] < fundDisputeCache.requiredValueForSide)) { // Losing side and not direct appeal or dispute raise. - if (!_paidFees.loserFullyFunded[_paidFees.loserFullyFunded.length - 1]) - _paidFees.loserFullyFunded[_paidFees.loserFullyFunded.length - 1] = true; - } else { // Winning side or direct appeal. - if (!fundDisputeCache.appealing) { // First round. - if (_paidFees.totalContributedPerSide[_paidFees.totalContributedPerSide.length - 1][_side == 0 ? 1 : 0] < fundDisputeCache.requiredValueForSide) return; - agreement.disputeID = agreement.arbitrator.createDispute.value(fundDisputeCache.cost)(agreement.numberOfChoices, agreement.extraData); - agreement.disputed = true; - arbitratorAndDisputeIDToAgreementID[agreement.arbitrator][agreement.disputeID] = _agreementID; - emit Dispute(agreement.arbitrator, agreement.disputeID, uint(_agreementID)); - } else { // Appeal. - _paidFees.ruling[_paidFees.ruling.length - 1] = agreement.arbitrator.currentRuling(agreement.disputeID); - agreement.arbitrator.appeal.value(fundDisputeCache.cost)(agreement.disputeID, agreement.extraData); - if (!agreement.appealed) agreement.appealed = true; - } - - // Update the total value. - _paidFees.totalValue[_paidFees.totalValue.length - 1] -= fundDisputeCache.cost; - - // Prepare for the next round. - _paidFees.ruling.push(0); - _paidFees.stake.push(stake); - _paidFees.totalValue.push(0); - _paidFees.totalContributedPerSide.push([0, 0]); - _paidFees.loserFullyFunded.push(false); - _paidFees.contributions.length++; - } - } - } - - /** @dev Withdraws the caller's reward for funding the specified round of the specified agreement. - * @param _agreementID The ID of the agreement. - * @param _round The round. - */ - function withdrawReward(bytes32 _agreementID, uint _round) public { - Agreement storage agreement = agreements[_agreementID]; - PaidFees storage _paidFees = paidFees[_agreementID]; - require(agreement.creator != address(0), "The specified agreement does not exist."); - require( - !agreement.disputed || agreement.arbitrator.disputeStatus(agreement.disputeID) == Arbitrator.DisputeStatus.Solved, - "The agreement is still disputed." - ); - require(_round < _paidFees.stake.length, "The specified round of the specified agreement does not exist."); - - uint _reward; - if (_round == 0 || _round == _paidFees.stake.length - 1) { // First or last round. - require(_round != 0 || !agreement.disputed, "There is nothing to withdraw from the first round if the dispute was raised."); - _reward = _paidFees.contributions[_round][msg.sender][0] + _paidFees.contributions[_round][msg.sender][1]; - } else { // Appeal. - uint _winningSide = _paidFees.ruling[_round] != agreement.ruling ? 0 : 1; - _reward = _paidFees.totalContributedPerSide[_round][_winningSide] == 0 ? 0 : ((_paidFees.totalValue[_round] * _paidFees.contributions[_round][msg.sender][_winningSide]) / _paidFees.totalContributedPerSide[_round][_winningSide]); - } - - _paidFees.contributions[_round][msg.sender] = [0, 0]; - msg.sender.transfer(_reward); - emit RewardWithdrawal(_agreementID, _round, msg.sender, _reward); - } - - /* External Views */ - - /** @dev Gets the info on fees paid for the specified agreement. - * @param _agreementID The ID of the agreement. - * @return The info. - */ - function getFeesInfo( - bytes32 _agreementID - ) external view returns( - uint[] ruling, - uint[] _stake, - uint[] totalValue, - uint[2][] totalContributedPerSide, - bool[] loserFullyFunded - ) { - PaidFees storage _paidFees = paidFees[_agreementID]; - ruling = _paidFees.ruling; - _stake = _paidFees.stake; - totalValue = _paidFees.totalValue; - totalContributedPerSide = _paidFees.totalContributedPerSide; - loserFullyFunded = _paidFees.loserFullyFunded; - } - - /** @dev Gets the contributions by the specified contributor in the specified round of the specified agreement. - * @param _agreementID The ID of the agreement. - * @param _round The round. - * @param _contributor The address of the contributor. - * @return The contributions. - */ - function getContributions(bytes32 _agreementID, uint _round, address _contributor) external view returns(uint[2] contributions) { - contributions = paidFees[_agreementID].contributions[_round][_contributor]; - } -} diff --git a/contracts/standard/arbitration/composed-arbitrable/proxy/ArbitrableProxy.sol b/contracts/standard/arbitration/composed-arbitrable/proxy/ArbitrableProxy.sol deleted file mode 100644 index c8544394..00000000 --- a/contracts/standard/arbitration/composed-arbitrable/proxy/ArbitrableProxy.sol +++ /dev/null @@ -1,66 +0,0 @@ -pragma solidity ^0.4.24; - -import "../../Arbitrator.sol"; - -/** - * @title ArbitrableProxy - * @author Enrique Piqueras - - * @dev Base contract for arbitrable proxies. - */ -contract ArbitrableProxy { - /* External */ - - /** @dev Creates an agreement. - * @param _agreementID The ID of the agreement. - * @param _metaEvidence The meta evidence of the agreement. - * @param _parties The `parties` value of the agreement. - * @param _numberOfChoices The `numberOfChoices` value of the agreement. - * @param _extraData The `extraData` value of the agreement. - * @param _arbitrationFeesWaitingTime The `arbitrationFeesWaitingTime` value of the agreement. - * @param _arbitrator The `arbitrator` value of the agreement. - */ - function createAgreement( - bytes32 _agreementID, - string _metaEvidence, - address[] _parties, - uint _numberOfChoices, - bytes _extraData, - uint _arbitrationFeesWaitingTime, - Arbitrator _arbitrator) external; - - /* External Views */ - - /** @dev Gets the info on the specified agreement. - * @param _agreementID The ID of the agreement. - * @return The info. - */ - function getAgreementInfo(bytes32 _agreementID) external view returns( - address creator, - address[] parties, - uint numberOfChoices, - bytes extraData, - uint arbitrationFeesWaitingTime, - Arbitrator arbitrator, - uint disputeID, - bool disputed, - bool appealed, - uint ruling, - bool executed); - - function getFeesInfo( - bytes32 _agreementID - ) external view returns( - uint[] ruling, - uint[] _stake, - uint[] totalValue, - uint[2][] totalContributedPerSide, - bool[] loserFullyFunded); - - /** @dev Gets the contributions by the specified contributor in the specified round of the specified agreement. - * @param _agreementID The ID of the agreement. - * @param _round The round. - * @param _contributor The address of the contributor. - * @return The contributions. - */ - function getContributions(bytes32 _agreementID, uint _round, address _contributor) external view returns(uint[2] contributions); -} diff --git a/contracts/standard/arbitration/composed-arbitrable/proxy/ArbitrableProxyUser.sol b/contracts/standard/arbitration/composed-arbitrable/proxy/ArbitrableProxyUser.sol deleted file mode 100644 index 5fadcdd2..00000000 --- a/contracts/standard/arbitration/composed-arbitrable/proxy/ArbitrableProxyUser.sol +++ /dev/null @@ -1,33 +0,0 @@ -pragma solidity ^0.4.24; - -import "./ArbitrableProxy.sol"; - -/** - * @title ArbitrableProxyUser - * @author Enrique Piqueras - - * @dev Base contract for contracts that use a composed arbitrable proxy. - */ -contract ArbitrableProxyUser { - /* Storage */ - - ArbitrableProxy public arbitrableProxy; - - /* Constructor */ - - /** @dev Constructs the `ArbitrableProxyUser` contract. - * @param _arbitrableProxy The arbitrable proxy to use. - */ - constructor(ArbitrableProxy _arbitrableProxy) public { - arbitrableProxy = _arbitrableProxy; - } - - /* Public */ - - /** @dev Executes the ruling on the specified agreement. - * @param _agreementID The ID of the agreement. - * @param _ruling The ruling. - */ - function executeAgreementRuling(bytes32 _agreementID, uint _ruling) public { - require(ArbitrableProxy(msg.sender) == arbitrableProxy, "The caller must be the arbitrable proxy."); - } -} diff --git a/contracts/standard/arbitration/composed-arbitrable/proxy/MultiPartyInsurableArbitrableAgreementsProxy.sol b/contracts/standard/arbitration/composed-arbitrable/proxy/MultiPartyInsurableArbitrableAgreementsProxy.sol deleted file mode 100644 index 0c52f5ea..00000000 --- a/contracts/standard/arbitration/composed-arbitrable/proxy/MultiPartyInsurableArbitrableAgreementsProxy.sol +++ /dev/null @@ -1,72 +0,0 @@ -pragma solidity ^0.4.24; - -import "../composed/MultiPartyInsurableArbitrableAgreementsBase.sol"; - -import "./ArbitrableProxy.sol"; -import "./ArbitrableProxyUser.sol"; - -/** - * @title MultiPartyInsurableArbitrableAgreementsProxy - * @author Enrique Piqueras - - * @dev Proxy implementation of `MultiPartyInsurableArbitrableAgreementsBase`. - */ -contract MultiPartyInsurableArbitrableAgreementsProxy is ArbitrableProxy, MultiPartyInsurableArbitrableAgreementsBase { - /* Constructor */ - - /** @dev Constructs the `MultiPartyInsurableArbitrableAgreementsProxy` contract. - * @param _arbitrator The arbitrator of the contract. - * @param _arbitratorExtraData Extra data for the arbitrator. - * @param _feeGovernor The fee governor of this contract. - * @param _stake The stake parameter for sharing fees. - */ - constructor( - Arbitrator _arbitrator, - bytes _arbitratorExtraData, - address _feeGovernor, - uint _stake - ) public MultiPartyInsurableArbitrableAgreementsBase(_arbitrator, _arbitratorExtraData, _feeGovernor, _stake) {} - - /* External */ - - /** @dev Creates an agreement. - * @param _agreementID The ID of the agreement. - * @param _metaEvidence The meta evidence of the agreement. - * @param _parties The `parties` value of the agreement. - * @param _numberOfChoices The `numberOfChoices` value of the agreement. - * @param _extraData The `extraData` value of the agreement. - * @param _arbitrationFeesWaitingTime The `arbitrationFeesWaitingTime` value of the agreement. - * @param _arbitrator The `arbitrator` value of the agreement. - */ - function createAgreement( - bytes32 _agreementID, - string _metaEvidence, - address[] _parties, - uint _numberOfChoices, - bytes _extraData, - uint _arbitrationFeesWaitingTime, - Arbitrator _arbitrator - ) external { - return _createAgreement( - _agreementID, - _metaEvidence, - _parties, - _numberOfChoices, - _extraData, - _arbitrationFeesWaitingTime, - _arbitrator - ); - } - - /* Internal */ - - /** @dev Executes the ruling on the specified agreement. - * @param _agreementID The ID of the agreement. - * @param _ruling The ruling. - */ - function executeAgreementRuling(bytes32 _agreementID, uint _ruling) internal { - super.executeAgreementRuling(_agreementID, _ruling); - ArbitrableProxyUser( - agreements[_agreementID].creator - ).executeAgreementRuling(_agreementID, _ruling); - } -} diff --git a/test/two-party-arbitrable-escrow-payment-proxy-user.js b/test/two-party-arbitrable-escrow-payment-proxy-user.js deleted file mode 100644 index 8064d0ce..00000000 --- a/test/two-party-arbitrable-escrow-payment-proxy-user.js +++ /dev/null @@ -1,605 +0,0 @@ -/* globals artifacts, contract, expect, web3 */ -const { - increaseTime -} = require('openzeppelin-solidity/test/helpers/increaseTime') -const { - expectThrow -} = require('openzeppelin-solidity/test/helpers/expectThrow') - -const MultiPartyInsurableArbitrableAgreementsProxy = artifacts.require( - './standard/arbitration/composed-arbitrable/proxy/MultiPartyInsurableArbitrableAgreementsProxy.sol' -) -const TwoPartyArbitrableEscrowPaymentProxyUser = artifacts.require( - './standard/arbitration/composed-arbitrable/example/TwoPartyArbitrableEscrowPaymentProxyUser.sol' -) -const AppealableArbitrator = artifacts.require( - './standard/arbitration/AppealableArbitrator.sol' -) -const EnhancedAppealableArbitrator = artifacts.require( - './standard/arbitration/EnhancedAppealableArbitrator.sol' -) - -// Helpers -const checkOnlyByGovernor = async ( - getter, - value, - method, - nextValue, - invalidFrom, - nextFrom -) => { - await method(nextValue) // Set the next value - expect(await getter()).to.deep.equal( - nextValue === Number(nextValue) ? web3.toBigNumber(nextValue) : nextValue - ) // Check it was set properly - await expectThrow(method(value, { from: invalidFrom })) // Throw when setting from a non governor address - await method(value, nextFrom && { from: nextFrom }) // Set back to the original value -} - -contract('TwoPartyArbitrableEscrowPaymentProxyUser', accounts => - it('Should function as an arbitrable escrow service with crowdinsured fee payments.', async () => { - // Deploy contracts - const governor = accounts[0] - const stake = 10 - const twoTimesStake = stake * 2 - const multiPartyInsurableArbitrableAgreementsProxy = await MultiPartyInsurableArbitrableAgreementsProxy.new( - governor, // _arbitrator - null, // _arbitratorExtraData - governor, // _feeGovernor - stake // _stake - ) - const twoPartyArbitrableEscrowPaymentProxyUser = await TwoPartyArbitrableEscrowPaymentProxyUser.new( - multiPartyInsurableArbitrableAgreementsProxy.address // _arbitrableProxy - ) - const arbitrationPrice = 100 - const halfOfArbitrationPrice = arbitrationPrice / 2 - const timeOut = 1000 - const appealableArbitrator = await AppealableArbitrator.new( - arbitrationPrice, // _arbitrationPrice - governor, // _arbitrator - null, // _arbitratorExtraData - timeOut // _timeOut - ) - await appealableArbitrator.changeArbitrator(appealableArbitrator.address) - const enhancedAppealableArbitrator = await EnhancedAppealableArbitrator.new( - arbitrationPrice, // _arbitrationPrice - governor, // _arbitrator - null, // _arbitratorExtraData - timeOut // _timeOut - ) - await enhancedAppealableArbitrator.changeArbitrator( - enhancedAppealableArbitrator.address - ) - - // Test governance - await checkOnlyByGovernor( - multiPartyInsurableArbitrableAgreementsProxy.feeGovernor, - governor, - multiPartyInsurableArbitrableAgreementsProxy.changeFeeGovernor, - accounts[1], - accounts[2], - accounts[1] - ) - await checkOnlyByGovernor( - multiPartyInsurableArbitrableAgreementsProxy.stake, - stake, - multiPartyInsurableArbitrableAgreementsProxy.changeStake, - 0, - accounts[2] - ) - - // Generate and create payments - const evidence = 'https://kleros.io' - const receiver = accounts[1] - const keepRuling = 1 - const sendRuling = 2 - const payments = [ - { - // Payment time out - ID: '0x01', - arbitrationFeesWaitingTime: -1, - timeOut: 60, - value: 10, - contributionsPerSide: [], - expectedRuling: sendRuling - }, - { - // Arbitration fees time out - ID: '0x02', - arbitrationFeesWaitingTime: 60, - timeOut: 0, - value: 20, - contributionsPerSide: [ - [halfOfArbitrationPrice - 1, halfOfArbitrationPrice - 1] - ], - expectedRuling: keepRuling - }, - { - // Arbitration fees time out, sender pays more - ID: '0x03', - arbitrationFeesWaitingTime: 60, - timeOut: 0, - value: 30, - contributionsPerSide: [ - [halfOfArbitrationPrice, halfOfArbitrationPrice - 1] - ], - expectedRuling: keepRuling - }, - { - // Arbitration fees time out, receiver pays more - ID: '0x04', - arbitrationFeesWaitingTime: 60, - timeOut: 0, - value: 40, - contributionsPerSide: [ - [halfOfArbitrationPrice - 1, halfOfArbitrationPrice] - ], - expectedRuling: sendRuling - }, - { - // Sender fails to fully fund appeal - ID: '0x05', - arbitrationFeesWaitingTime: -1, - timeOut: 0, - value: 50, - contributionsPerSide: [ - [halfOfArbitrationPrice, halfOfArbitrationPrice], - [arbitrationPrice + twoTimesStake, arbitrationPrice + stake], - [arbitrationPrice + twoTimesStake - 1, -1] - ], - expectedRuling: sendRuling - }, - { - // Sender fully funds appeal and pays more - ID: '0x06', - arbitrationFeesWaitingTime: -1, - timeOut: 0, - value: 60, - contributionsPerSide: [ - [halfOfArbitrationPrice, halfOfArbitrationPrice], - [arbitrationPrice + twoTimesStake, arbitrationPrice + stake], - [arbitrationPrice + twoTimesStake, arbitrationPrice + stake - 1] - ], - expectedRuling: keepRuling - }, - { - // Direct appeals - ID: '0x07', - arbitrationFeesWaitingTime: -1, - timeOut: 0, - directAppeal: true, - value: 70, - contributionsPerSide: [ - [halfOfArbitrationPrice, halfOfArbitrationPrice], - [arbitrationPrice, 0], - [arbitrationPrice - 1, 0] - ], - expectedRuling: sendRuling - } - ] - let accTimeOut = 0 - for (const payment of payments) { - const arbitratorAddress = payment.directAppeal - ? appealableArbitrator.address - : enhancedAppealableArbitrator.address - await expectThrow( - // Should throw without value - twoPartyArbitrableEscrowPaymentProxyUser.createPayment( - payment.ID, - evidence, - receiver, - payment.arbitrationFeesWaitingTime, - arbitratorAddress, - payment.timeOut - ) - ) - await twoPartyArbitrableEscrowPaymentProxyUser.createPayment( - payment.ID, - evidence, - receiver, - payment.arbitrationFeesWaitingTime, - arbitratorAddress, - (accTimeOut += payment.timeOut), - { value: payment.value } - ) - } - await expectThrow( - // Should throw when ID is already being used - twoPartyArbitrableEscrowPaymentProxyUser.createPayment( - payments[0].ID, - evidence, - receiver, - payments[0].arbitrationFeesWaitingTime, - payments[0].directAppeal - ? appealableArbitrator.address - : enhancedAppealableArbitrator.address, - payments[0].timeOut - ) - ) - - // Payment time outs - await expectThrow( - // Should throw for non-existent payments - twoPartyArbitrableEscrowPaymentProxyUser.executePayment('0x00') - ) - for (const payment of payments) - if (payment.timeOut > 0) { - await expectThrow( - // Should throw when not disputed - multiPartyInsurableArbitrableAgreementsProxy.submitEvidence( - payment.ID, - evidence - ) - ) - await expectThrow( - // Should throw when not enough time has passed - twoPartyArbitrableEscrowPaymentProxyUser.executePayment(payment.ID) - ) - await increaseTime(payment.timeOut + 1) - await twoPartyArbitrableEscrowPaymentProxyUser.executePayment( - payment.ID - ) - await expectThrow( - // Should throw when already executed - twoPartyArbitrableEscrowPaymentProxyUser.executePayment(payment.ID) - ) - } - - // Arbitration fee time outs - const arbitrationFeesTimeoutPayment = payments.find( - p => p.arbitrationFeesWaitingTime >= 0 - ) - await expectThrow( - // Should throw for non-existent payments - multiPartyInsurableArbitrableAgreementsProxy.fundDispute('0x00', 0, { - value: halfOfArbitrationPrice - }) - ) - await expectThrow( - // Should throw for invalid sides - multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - arbitrationFeesTimeoutPayment.ID, - 2, - { - value: halfOfArbitrationPrice - } - ) - ) - await expectThrow( - // Should throw without value - multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - arbitrationFeesTimeoutPayment.ID, - 0 - ) - ) - for (const payment of payments) - if (payment.arbitrationFeesWaitingTime >= 0) { - for (let i = 0; i < payment.contributionsPerSide[0].length; i++) - await multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - payment.ID, - i, - { - value: payment.contributionsPerSide[0][i] - } - ) - await increaseTime(payment.arbitrationFeesWaitingTime + 1) - await multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - payment.ID, - 0, - { - value: payment.contributionsPerSide[0][0] - } - ) - await expectThrow( - // Should throw for already executed payments - multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - payment.ID, - 0, - { - value: payment.contributionsPerSide[0][0] - } - ) - ) - } - - // Raise disputes for appeal time outs and direct appeals - for (const payment of payments) - if (payment.timeOut <= 0 && payment.arbitrationFeesWaitingTime < 0) - for (let i = 0; i < payment.contributionsPerSide[0].length; i++) - await multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - payment.ID, - i, - { - value: payment.contributionsPerSide[0][i] - } - ) - - // Submit evidence - const appealTimeOutPayment = payments.find( - p => p.timeOut <= 0 && p.arbitrationFeesWaitingTime < 0 && !p.directAppeal - ) - await expectThrow( - // Should throw when payment is disputed - twoPartyArbitrableEscrowPaymentProxyUser.executePayment( - appealTimeOutPayment.ID - ) - ) - await multiPartyInsurableArbitrableAgreementsProxy.submitEvidence( - appealTimeOutPayment.ID, - evidence - ) - await expectThrow( - // Should throw for non-existent payments - multiPartyInsurableArbitrableAgreementsProxy.submitEvidence( - '0x00', - evidence - ) - ) - await expectThrow( - // Should throw when sent from a party that is not involved in the payment - multiPartyInsurableArbitrableAgreementsProxy.submitEvidence( - appealTimeOutPayment.ID, - evidence, - { from: accounts[2] } - ) - ) - - // Test edge cases with one appeal - const rulingDisputeID = Number( - (await multiPartyInsurableArbitrableAgreementsProxy.agreements( - appealTimeOutPayment.ID - ))[5] - ) - await expectThrow( - // Should throw when not appealable - multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - appealTimeOutPayment.ID, - 0, - { - value: appealTimeOutPayment.contributionsPerSide[1][0] - } - ) - ) - await enhancedAppealableArbitrator.giveRuling(rulingDisputeID, sendRuling) - await expectThrow( - // Should throw when not the side's turn - multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - appealTimeOutPayment.ID, - 1, - { - value: appealTimeOutPayment.contributionsPerSide[1][1] - } - ) - ) - await multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - appealTimeOutPayment.ID, - 0, - { value: appealTimeOutPayment.contributionsPerSide[1][0] } - ) - await increaseTime(timeOut + 1) - await expectThrow( - // Should throw when not the side's turn - multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - appealTimeOutPayment.ID, - 0, - { - value: appealTimeOutPayment.contributionsPerSide[1][0] - } - ) - ) - await expectThrow( - // Should throw when not sent from the arbitrator - multiPartyInsurableArbitrableAgreementsProxy.rule( - rulingDisputeID, - sendRuling - ) - ) - await expectThrow( - // Should throw for a non-existent dispute - enhancedAppealableArbitrator.giveRuling(-1, sendRuling) - ) - await multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - appealTimeOutPayment.ID, - 1, - { - value: appealTimeOutPayment.contributionsPerSide[1][1] - } - ) - await expectThrow( - // Should throw when already appealed - multiPartyInsurableArbitrableAgreementsProxy.submitEvidence( - appealTimeOutPayment.ID, - evidence - ) - ) - await expectThrow( - // Should throw when still disputed - multiPartyInsurableArbitrableAgreementsProxy.withdrawReward( - appealTimeOutPayment.ID, - 1 - ) - ) - - // Appeal time outs - for (const payment of payments) - if ( - payment.timeOut <= 0 && - payment.arbitrationFeesWaitingTime < 0 && - !payment.directAppeal - ) { - const paymentDisputeID = Number( - (await multiPartyInsurableArbitrableAgreementsProxy.agreements( - payment.ID - ))[5] - ) - - for (let i = 1; i < payment.contributionsPerSide.length; i++) - if (payment !== appealTimeOutPayment || i > 1) { - await enhancedAppealableArbitrator.giveRuling( - await enhancedAppealableArbitrator.getAppealDisputeID( - paymentDisputeID - ), - sendRuling - ) - - for (let j = 0; j < payment.contributionsPerSide[i].length; j++) { - if (payment.contributionsPerSide[i][j] < 0) - await expectThrow( - // Should throw when losing side did not fully fund - multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - payment.ID, - j, - { - value: payment.contributionsPerSide[i][j] - } - ) - ) - else - await multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - payment.ID, - j, - { - value: payment.contributionsPerSide[i][j] - } - ) - await increaseTime(timeOut / 2) - } - } - - await increaseTime(timeOut / 2 + 1) - await expectThrow( - // Should throw when not called by the arbitrable proxy - twoPartyArbitrableEscrowPaymentProxyUser.executeAgreementRuling( - appealTimeOutPayment.ID, - sendRuling - ) - ) - await enhancedAppealableArbitrator.giveRuling( - await enhancedAppealableArbitrator.getAppealDisputeID( - paymentDisputeID - ), - sendRuling - ) - await expectThrow( - // Should throw when already executed - enhancedAppealableArbitrator.giveRuling( - await enhancedAppealableArbitrator.getAppealDisputeID( - paymentDisputeID - ), - sendRuling - ) - ) - } - - // Direct appeals - for (const payment of payments) - if (payment.directAppeal) { - const paymentDisputeID = Number( - (await multiPartyInsurableArbitrableAgreementsProxy.agreements( - payment.ID - ))[5] - ) - - for (let i = 1; i < payment.contributionsPerSide.length; i++) { - await appealableArbitrator.giveRuling( - await appealableArbitrator.getAppealDisputeID(paymentDisputeID), - sendRuling - ) - - if (payment.contributionsPerSide[i][0] < arbitrationPrice) - await expectThrow( - multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - payment.ID, - 0, - { - value: payment.contributionsPerSide[i][0] - } - ) - ) - else - multiPartyInsurableArbitrableAgreementsProxy.fundDispute( - payment.ID, - 0, - { - value: payment.contributionsPerSide[i][0] - } - ) - } - - await increaseTime(timeOut + 1) - await appealableArbitrator.giveRuling( - await appealableArbitrator.getAppealDisputeID(paymentDisputeID), - sendRuling - ) - } - - // Withdraw contribution rewards - await expectThrow( - // Should throw for a non-existent payment - multiPartyInsurableArbitrableAgreementsProxy.withdrawReward('0x00', 1) - ) - await expectThrow( - // Should throw for an invalid round - multiPartyInsurableArbitrableAgreementsProxy.withdrawReward( - appealTimeOutPayment.ID, - -1 - ) - ) - await expectThrow( - // Should throw for the first round if appealed - multiPartyInsurableArbitrableAgreementsProxy.withdrawReward( - appealTimeOutPayment.ID, - 0 - ) - ) - for (const payment of payments) - for (let i = 0; i < payment.contributionsPerSide.length; i++) - if (i > 0 || (i === 0 && payment.contributionsPerSide.length === 1)) - await multiPartyInsurableArbitrableAgreementsProxy.withdrawReward( - payment.ID, - i - ) - - // Verify rulings and total rewards - let totalReward = 0 - for (const payment of payments) { - const notDisputed = payment.contributionsPerSide.length < 2 - const paymentRuling = Number( - (await multiPartyInsurableArbitrableAgreementsProxy.agreements( - payment.ID - ))[8] - ) - expect(paymentRuling).to.equal(notDisputed ? 0 : sendRuling) - expect( - (await new Promise((resolve, reject) => - twoPartyArbitrableEscrowPaymentProxyUser - .PaymentExecuted({ _paymentID: payment.ID }, { fromBlock: 0 }) - .get((err, logs) => (err ? reject(err) : resolve(logs))) - ))[0].args._receiver - ).to.equal(payment.expectedRuling === sendRuling ? receiver : governor) - - if (!payment.directAppeal) - for (let i = 0; i < payment.contributionsPerSide.length; i++) { - const totalValue = - Math.max(0, payment.contributionsPerSide[i][0]) + - Math.max(0, payment.contributionsPerSide[i][1]) - if ( - (i === 0 && notDisputed) || - i === payment.contributionsPerSide.length - 1 - ) - totalReward += totalValue - else totalReward += totalValue - arbitrationPrice - } - } - - expect(totalReward).to.equal( - (await new Promise((resolve, reject) => - multiPartyInsurableArbitrableAgreementsProxy - .RewardWithdrawal({}, { fromBlock: 0 }) - .get((err, logs) => (err ? reject(err) : resolve(logs))) - )) - .reduce((acc, e) => acc.plus(e.args._value), web3.toBigNumber(0)) - .toNumber() - ) - }) -) diff --git a/test/two-party-arbitrable-escrow-payment.js b/test/two-party-arbitrable-escrow-payment.js deleted file mode 100644 index 1f033104..00000000 --- a/test/two-party-arbitrable-escrow-payment.js +++ /dev/null @@ -1,524 +0,0 @@ -/* globals artifacts, contract, expect, web3 */ -const { - increaseTime -} = require('openzeppelin-solidity/test/helpers/increaseTime') -const { - expectThrow -} = require('openzeppelin-solidity/test/helpers/expectThrow') - -const TwoPartyArbitrableEscrowPayment = artifacts.require( - './standard/arbitration/composed-arbitrable/example/TwoPartyArbitrableEscrowPayment.sol' -) -const AppealableArbitrator = artifacts.require( - './standard/arbitration/AppealableArbitrator.sol' -) -const EnhancedAppealableArbitrator = artifacts.require( - './standard/arbitration/EnhancedAppealableArbitrator.sol' -) - -// Helpers -const checkOnlyByGovernor = async ( - getter, - value, - method, - nextValue, - invalidFrom, - nextFrom -) => { - await method(nextValue) // Set the next value - expect(await getter()).to.deep.equal( - nextValue === Number(nextValue) ? web3.toBigNumber(nextValue) : nextValue - ) // Check it was set properly - await expectThrow(method(value, { from: invalidFrom })) // Throw when setting from a non governor address - await method(value, nextFrom && { from: nextFrom }) // Set back to the original value -} - -contract('TwoPartyArbitrableEscrowPayment', accounts => - it('Should function as an arbitrable escrow service with crowdinsured fee payments.', async () => { - // Deploy contracts - const governor = accounts[0] - const stake = 10 - const twoTimesStake = stake * 2 - const twoPartyArbitrableEscrowPayment = await TwoPartyArbitrableEscrowPayment.new( - governor, // _arbitrator - null, // _arbitratorExtraData - governor, // _feeGovernor - stake // _stake - ) - const arbitrationPrice = 100 - const halfOfArbitrationPrice = arbitrationPrice / 2 - const timeOut = 1000 - const appealableArbitrator = await AppealableArbitrator.new( - arbitrationPrice, // _arbitrationPrice - governor, // _arbitrator - null, // _arbitratorExtraData - timeOut // _timeOut - ) - await appealableArbitrator.changeArbitrator(appealableArbitrator.address) - const enhancedAppealableArbitrator = await EnhancedAppealableArbitrator.new( - arbitrationPrice, // _arbitrationPrice - governor, // _arbitrator - null, // _arbitratorExtraData - timeOut // _timeOut - ) - await enhancedAppealableArbitrator.changeArbitrator( - enhancedAppealableArbitrator.address - ) - - // Test governance - await checkOnlyByGovernor( - twoPartyArbitrableEscrowPayment.feeGovernor, - governor, - twoPartyArbitrableEscrowPayment.changeFeeGovernor, - accounts[1], - accounts[2], - accounts[1] - ) - await checkOnlyByGovernor( - twoPartyArbitrableEscrowPayment.stake, - stake, - twoPartyArbitrableEscrowPayment.changeStake, - 0, - accounts[2] - ) - - // Generate and create payments - const evidence = 'https://kleros.io' - const receiver = accounts[1] - const keepRuling = 1 - const sendRuling = 2 - const payments = [ - { - // Payment time out - ID: '0x01', - arbitrationFeesWaitingTime: -1, - timeOut: 60, - value: 10, - contributionsPerSide: [], - expectedRuling: sendRuling - }, - { - // Arbitration fees time out - ID: '0x02', - arbitrationFeesWaitingTime: 60, - timeOut: 0, - value: 20, - contributionsPerSide: [ - [halfOfArbitrationPrice - 1, halfOfArbitrationPrice - 1] - ], - expectedRuling: keepRuling - }, - { - // Arbitration fees time out, sender pays more - ID: '0x03', - arbitrationFeesWaitingTime: 60, - timeOut: 0, - value: 30, - contributionsPerSide: [ - [halfOfArbitrationPrice, halfOfArbitrationPrice - 1] - ], - expectedRuling: keepRuling - }, - { - // Arbitration fees time out, receiver pays more - ID: '0x04', - arbitrationFeesWaitingTime: 60, - timeOut: 0, - value: 40, - contributionsPerSide: [ - [halfOfArbitrationPrice - 1, halfOfArbitrationPrice] - ], - expectedRuling: sendRuling - }, - { - // Sender fails to fully fund appeal - ID: '0x05', - arbitrationFeesWaitingTime: -1, - timeOut: 0, - value: 50, - contributionsPerSide: [ - [halfOfArbitrationPrice, halfOfArbitrationPrice], - [arbitrationPrice + twoTimesStake, arbitrationPrice + stake], - [arbitrationPrice + twoTimesStake - 1, -1] - ], - expectedRuling: sendRuling - }, - { - // Sender fully funds appeal and pays more - ID: '0x06', - arbitrationFeesWaitingTime: -1, - timeOut: 0, - value: 60, - contributionsPerSide: [ - [halfOfArbitrationPrice, halfOfArbitrationPrice], - [arbitrationPrice + twoTimesStake, arbitrationPrice + stake], - [arbitrationPrice + twoTimesStake, arbitrationPrice + stake - 1] - ], - expectedRuling: keepRuling - }, - { - // Direct appeals - ID: '0x07', - arbitrationFeesWaitingTime: -1, - timeOut: 0, - directAppeal: true, - value: 70, - contributionsPerSide: [ - [halfOfArbitrationPrice, halfOfArbitrationPrice], - [arbitrationPrice, 0], - [arbitrationPrice - 1, 0] - ], - expectedRuling: sendRuling - } - ] - let accTimeOut = 0 - for (const payment of payments) { - const arbitratorAddress = payment.directAppeal - ? appealableArbitrator.address - : enhancedAppealableArbitrator.address - await expectThrow( - // Should throw without value - twoPartyArbitrableEscrowPayment.createPayment( - payment.ID, - evidence, - receiver, - payment.arbitrationFeesWaitingTime, - arbitratorAddress, - payment.timeOut - ) - ) - await twoPartyArbitrableEscrowPayment.createPayment( - payment.ID, - evidence, - receiver, - payment.arbitrationFeesWaitingTime, - arbitratorAddress, - (accTimeOut += payment.timeOut), - { value: payment.value } - ) - } - await expectThrow( - // Should throw when ID is already being used - twoPartyArbitrableEscrowPayment.createPayment( - payments[0].ID, - evidence, - receiver, - payments[0].arbitrationFeesWaitingTime, - payments[0].directAppeal - ? appealableArbitrator.address - : enhancedAppealableArbitrator.address, - payments[0].timeOut - ) - ) - - // Payment time outs - await expectThrow( - // Should throw for non-existent payments - twoPartyArbitrableEscrowPayment.executePayment('0x00') - ) - for (const payment of payments) - if (payment.timeOut > 0) { - await expectThrow( - // Should throw when not disputed - twoPartyArbitrableEscrowPayment.submitEvidence(payment.ID, evidence) - ) - await expectThrow( - // Should throw when not enough time has passed - twoPartyArbitrableEscrowPayment.executePayment(payment.ID) - ) - await increaseTime(payment.timeOut + 1) - await twoPartyArbitrableEscrowPayment.executePayment(payment.ID) - await expectThrow( - // Should throw when already executed - twoPartyArbitrableEscrowPayment.executePayment(payment.ID) - ) - } - - // Arbitration fee time outs - const arbitrationFeesTimeoutPayment = payments.find( - p => p.arbitrationFeesWaitingTime >= 0 - ) - await expectThrow( - // Should throw for non-existent payments - twoPartyArbitrableEscrowPayment.fundDispute('0x00', 0, { - value: halfOfArbitrationPrice - }) - ) - await expectThrow( - // Should throw for invalid sides - twoPartyArbitrableEscrowPayment.fundDispute( - arbitrationFeesTimeoutPayment.ID, - 2, - { - value: halfOfArbitrationPrice - } - ) - ) - await expectThrow( - // Should throw without value - twoPartyArbitrableEscrowPayment.fundDispute( - arbitrationFeesTimeoutPayment.ID, - 0 - ) - ) - for (const payment of payments) - if (payment.arbitrationFeesWaitingTime >= 0) { - for (let i = 0; i < payment.contributionsPerSide[0].length; i++) - await twoPartyArbitrableEscrowPayment.fundDispute(payment.ID, i, { - value: payment.contributionsPerSide[0][i] - }) - await increaseTime(payment.arbitrationFeesWaitingTime + 1) - await twoPartyArbitrableEscrowPayment.fundDispute(payment.ID, 0, { - value: payment.contributionsPerSide[0][0] - }) - await expectThrow( - // Should throw for already executed payments - twoPartyArbitrableEscrowPayment.fundDispute(payment.ID, 0, { - value: payment.contributionsPerSide[0][0] - }) - ) - } - - // Raise disputes for appeal time outs and direct appeals - for (const payment of payments) - if (payment.timeOut <= 0 && payment.arbitrationFeesWaitingTime < 0) - for (let i = 0; i < payment.contributionsPerSide[0].length; i++) - await twoPartyArbitrableEscrowPayment.fundDispute(payment.ID, i, { - value: payment.contributionsPerSide[0][i] - }) - - // Submit evidence - const appealTimeOutPayment = payments.find( - p => p.timeOut <= 0 && p.arbitrationFeesWaitingTime < 0 && !p.directAppeal - ) - await expectThrow( - // Should throw when payment is disputed - twoPartyArbitrableEscrowPayment.executePayment(appealTimeOutPayment.ID) - ) - await twoPartyArbitrableEscrowPayment.submitEvidence( - appealTimeOutPayment.ID, - evidence - ) - await expectThrow( - // Should throw for non-existent payments - twoPartyArbitrableEscrowPayment.submitEvidence('0x00', evidence) - ) - await expectThrow( - // Should throw when sent from a party that is not involved in the payment - twoPartyArbitrableEscrowPayment.submitEvidence( - appealTimeOutPayment.ID, - evidence, - { from: accounts[2] } - ) - ) - - // Test edge cases with one appeal - const rulingDisputeID = Number( - (await twoPartyArbitrableEscrowPayment.agreements( - appealTimeOutPayment.ID - ))[5] - ) - await expectThrow( - // Should throw when not appealable - twoPartyArbitrableEscrowPayment.fundDispute(appealTimeOutPayment.ID, 0, { - value: appealTimeOutPayment.contributionsPerSide[1][0] - }) - ) - await enhancedAppealableArbitrator.giveRuling(rulingDisputeID, sendRuling) - await expectThrow( - // Should throw when not the side's turn - twoPartyArbitrableEscrowPayment.fundDispute(appealTimeOutPayment.ID, 1, { - value: appealTimeOutPayment.contributionsPerSide[1][1] - }) - ) - await twoPartyArbitrableEscrowPayment.fundDispute( - appealTimeOutPayment.ID, - 0, - { value: appealTimeOutPayment.contributionsPerSide[1][0] } - ) - await increaseTime(timeOut + 1) - await expectThrow( - // Should throw when not the side's turn - twoPartyArbitrableEscrowPayment.fundDispute(appealTimeOutPayment.ID, 0, { - value: appealTimeOutPayment.contributionsPerSide[1][0] - }) - ) - await expectThrow( - // Should throw when not sent from the arbitrator - twoPartyArbitrableEscrowPayment.rule(rulingDisputeID, sendRuling) - ) - await expectThrow( - // Should throw for a non-existent dispute - enhancedAppealableArbitrator.giveRuling(-1, sendRuling) - ) - await twoPartyArbitrableEscrowPayment.fundDispute( - appealTimeOutPayment.ID, - 1, - { - value: appealTimeOutPayment.contributionsPerSide[1][1] - } - ) - await expectThrow( - // Should throw when already appealed - twoPartyArbitrableEscrowPayment.submitEvidence( - appealTimeOutPayment.ID, - evidence - ) - ) - await expectThrow( - // Should throw when still disputed - twoPartyArbitrableEscrowPayment.withdrawReward(appealTimeOutPayment.ID, 1) - ) - - // Appeal time outs - for (const payment of payments) - if ( - payment.timeOut <= 0 && - payment.arbitrationFeesWaitingTime < 0 && - !payment.directAppeal - ) { - const paymentDisputeID = Number( - (await twoPartyArbitrableEscrowPayment.agreements(payment.ID))[5] - ) - - for (let i = 1; i < payment.contributionsPerSide.length; i++) - if (payment !== appealTimeOutPayment || i > 1) { - await enhancedAppealableArbitrator.giveRuling( - await enhancedAppealableArbitrator.getAppealDisputeID( - paymentDisputeID - ), - sendRuling - ) - - for (let j = 0; j < payment.contributionsPerSide[i].length; j++) { - if (payment.contributionsPerSide[i][j] < 0) - await expectThrow( - // Should throw when losing side did not fully fund - twoPartyArbitrableEscrowPayment.fundDispute(payment.ID, j, { - value: payment.contributionsPerSide[i][j] - }) - ) - else - await twoPartyArbitrableEscrowPayment.fundDispute( - payment.ID, - j, - { - value: payment.contributionsPerSide[i][j] - } - ) - await increaseTime(timeOut / 2) - } - } - - await increaseTime(timeOut / 2 + 1) - await enhancedAppealableArbitrator.giveRuling( - await enhancedAppealableArbitrator.getAppealDisputeID( - paymentDisputeID - ), - sendRuling - ) - await expectThrow( - // Should throw when already executed - enhancedAppealableArbitrator.giveRuling( - await enhancedAppealableArbitrator.getAppealDisputeID( - paymentDisputeID - ), - sendRuling - ) - ) - } - - // Direct appeals - for (const payment of payments) - if (payment.directAppeal) { - const paymentDisputeID = Number( - (await twoPartyArbitrableEscrowPayment.agreements(payment.ID))[5] - ) - - for (let i = 1; i < payment.contributionsPerSide.length; i++) { - await appealableArbitrator.giveRuling( - await appealableArbitrator.getAppealDisputeID(paymentDisputeID), - sendRuling - ) - - if (payment.contributionsPerSide[i][0] < arbitrationPrice) - await expectThrow( - twoPartyArbitrableEscrowPayment.fundDispute(payment.ID, 0, { - value: payment.contributionsPerSide[i][0] - }) - ) - else - twoPartyArbitrableEscrowPayment.fundDispute(payment.ID, 0, { - value: payment.contributionsPerSide[i][0] - }) - } - - await increaseTime(timeOut + 1) - await appealableArbitrator.giveRuling( - await appealableArbitrator.getAppealDisputeID(paymentDisputeID), - sendRuling - ) - } - - // Withdraw contribution rewards - await expectThrow( - // Should throw for a non-existent payment - twoPartyArbitrableEscrowPayment.withdrawReward('0x00', 1) - ) - await expectThrow( - // Should throw for an invalid round - twoPartyArbitrableEscrowPayment.withdrawReward( - appealTimeOutPayment.ID, - -1 - ) - ) - await expectThrow( - // Should throw for the first round if appealed - twoPartyArbitrableEscrowPayment.withdrawReward(appealTimeOutPayment.ID, 0) - ) - for (const payment of payments) - for (let i = 0; i < payment.contributionsPerSide.length; i++) - if (i > 0 || (i === 0 && payment.contributionsPerSide.length === 1)) - await twoPartyArbitrableEscrowPayment.withdrawReward(payment.ID, i) - - // Verify rulings and total rewards - let totalReward = 0 - for (const payment of payments) { - const notDisputed = payment.contributionsPerSide.length < 2 - const paymentRuling = Number( - (await twoPartyArbitrableEscrowPayment.agreements(payment.ID))[8] - ) - expect(paymentRuling).to.equal(notDisputed ? 0 : sendRuling) - expect( - (await new Promise((resolve, reject) => - twoPartyArbitrableEscrowPayment - .PaymentExecuted({ _paymentID: payment.ID }, { fromBlock: 0 }) - .get((err, logs) => (err ? reject(err) : resolve(logs))) - ))[0].args._receiver - ).to.equal(payment.expectedRuling === sendRuling ? receiver : governor) - - if (!payment.directAppeal) - for (let i = 0; i < payment.contributionsPerSide.length; i++) { - const totalValue = - Math.max(0, payment.contributionsPerSide[i][0]) + - Math.max(0, payment.contributionsPerSide[i][1]) - if ( - (i === 0 && notDisputed) || - i === payment.contributionsPerSide.length - 1 - ) - totalReward += totalValue - else totalReward += totalValue - arbitrationPrice - } - } - - expect(totalReward).to.equal( - (await new Promise((resolve, reject) => - twoPartyArbitrableEscrowPayment - .RewardWithdrawal({}, { fromBlock: 0 }) - .get((err, logs) => (err ? reject(err) : resolve(logs))) - )) - .reduce((acc, e) => acc.plus(e.args._value), web3.toBigNumber(0)) - .toNumber() - ) - }) -)