Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disputable: Implement disputable base app #581

Merged
merged 14 commits into from
Jun 26, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 186 additions & 0 deletions contracts/apps/disputable/DisputableApp.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* SPDX-License-Identitifer: GPL-3.0-or-later
*/

pragma solidity 0.4.24;
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved

import "./IAgreement.sol";
import "./IDisputable.sol";
import "../AragonApp.sol";
import "../../lib/token/ERC20.sol";
import "../../lib/math/SafeMath64.sol";


contract DisputableApp is IDisputable, AragonApp {
/* Validation errors */
string internal constant ERROR_AGREEMENT_NOT_SET = "DISPUTABLE_AGREEMENT_NOT_SET";
string internal constant ERROR_AGREEMENT_ALREADY_SET = "DISPUTABLE_AGREEMENT_ALREADY_SET";
string internal constant ERROR_SENDER_NOT_AGREEMENT = "DISPUTABLE_SENDER_NOT_AGREEMENT";

// This role is not required to be validated in the Disputable app, the Agreement app is already doing the check
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved
// bytes32 public constant CHALLENGE_ROLE = keccak256("CHALLENGE_ROLE");
bytes32 public constant CHALLENGE_ROLE = 0xef025787d7cd1a96d9014b8dc7b44899b8c1350859fb9e1e05f5a546dd65158d;

// bytes32 public constant SET_AGREEMENT_ROLE = keccak256("SET_AGREEMENT_ROLE");
bytes32 public constant SET_AGREEMENT_ROLE = 0x8dad640ab1b088990c972676ada708447affc660890ec9fc9a5483241c49f036;

// bytes32 internal constant AGREEMENT_POSITION = keccak256("aragonOS.appStorage.agreement");
bytes32 internal constant AGREEMENT_POSITION = 0x6dbe80ccdeafbf5f3fff5738b224414f85e9370da36f61bf21c65159df7409e9;

event AgreementSet(IAgreement indexed agreement);

modifier onlyAgreement() {
require(address(_getAgreement()) == msg.sender, ERROR_SENDER_NOT_AGREEMENT);
_;
}

/**
* @notice Set disputable agreements to `_agreement`
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved
* @param _agreement Agreement instance to be linked
*/
function setAgreement(IAgreement _agreement) external auth(SET_AGREEMENT_ROLE) {
IAgreement agreement = _getAgreement();
require(agreement == IAgreement(0) || _agreement == IAgreement(0), ERROR_AGREEMENT_ALREADY_SET);
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved

AGREEMENT_POSITION.setStorageAddress(address(_agreement));
emit AgreementSet(_agreement);
}

/**
* @notice Challenge disputable action #`_disputableActionId`
* @param _disputableActionId Identification number of the disputable action to be challenged
* @param _challengeId Identification number of the challenge in the context of the Agreement
* @param _challenger Address challenging the disputable
*/
function onDisputableActionChallenged(uint256 _disputableActionId, uint256 _challengeId, address _challenger) external onlyAgreement {
_onDisputableActionChallenged(_disputableActionId, _challengeId, _challenger);
}

/**
* @notice Allow disputable action #`_disputableActionId`
* @param _disputableActionId Identification number of the disputable action to be allowed
*/
function onDisputableActionAllowed(uint256 _disputableActionId) external onlyAgreement {
_onDisputableActionAllowed(_disputableActionId);
}

/**
* @notice Reject disputable action #`_disputableActionId`
* @param _disputableActionId Identification number of the disputable action to be rejected
*/
function onDisputableActionRejected(uint256 _disputableActionId) external onlyAgreement {
_onDisputableActionRejected(_disputableActionId);
}

/**
* @notice Void disputable action #`_disputableActionId`
* @param _disputableActionId Identification number of the disputable action to be voided
*/
function onDisputableActionVoided(uint256 _disputableActionId) external onlyAgreement {
_onDisputableActionVoided(_disputableActionId);
}

/**
* @notice Tells whether the Agreement app is a forwarder or not
* @dev IForwarder interface conformance
* @return Always true
*/
function isForwarder() external pure returns (bool) {
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved
return true;
}

/**
* @dev Tell the agreement linked to the disputable instance
* @return Agreement linked to the disputable instance
*/
function getAgreement() external view returns (IAgreement) {
return _getAgreement();
}

/**
* @dev Create a new action in the agreement without lifetime set
* @param _disputableActionId Identification number of the disputable action in the context of the disputable
* @param _submitter Address of the user that has submitted the action
* @param _context Link to a human-readable text giving context for the given action
* @return Unique identification number for the created action in the context of the agreement
*/
function _newAgreementAction(uint256 _disputableActionId, address _submitter, bytes _context) internal returns (uint256) {
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved
return _newAgreementAction(_disputableActionId, 0, _submitter, _context);
}

/**
* @dev Create a new action in the agreement
* @param _disputableActionId Identification number of the disputable action in the context of the disputable
* @param _lifetime Lifetime duration in seconds of the disputable action, it can be set to zero to specify infinite
* @param _submitter Address of the user that has submitted the action
* @param _context Link to a human-readable text giving context for the given action
* @return Unique identification number for the created action in the context of the agreement
*/
function _newAgreementAction(uint256 _disputableActionId, uint64 _lifetime, address _submitter, bytes _context) internal returns (uint256) {
IAgreement agreement = _ensureAgreement();
return agreement.newAction(_disputableActionId, _lifetime, _submitter, _context);
}

/**
* @dev Close action in the agreement
* @param _actionId Identification number of the disputable action in the context of the agreement
*/
function _closeAgreementAction(uint256 _actionId) internal {
IAgreement agreement = _ensureAgreement();
agreement.closeAction(_actionId);
}

/**
sohkai marked this conversation as resolved.
Show resolved Hide resolved
* @dev Reject disputable action
* @param _disputableActionId Identification number of the disputable action to be rejected
*/
function _onDisputableActionRejected(uint256 _disputableActionId) internal;

/**
* @dev Challenge disputable action
* @param _disputableActionId Identification number of the disputable action to be challenged
* @param _challengeId Identification number of the challenge in the context of the Agreement
* @param _challenger Address challenging the disputable
*/
function _onDisputableActionChallenged(uint256 _disputableActionId, uint256 _challengeId, address _challenger) internal;

/**
* @dev Allow disputable action
* @param _disputableActionId Identification number of the disputable action to be allowed
*/
function _onDisputableActionAllowed(uint256 _disputableActionId) internal;

/**
* @dev Void disputable action
* @param _disputableActionId Identification number of the disputable action to be voided
*/
function _onDisputableActionVoided(uint256 _disputableActionId) internal;

/**
* @dev Tell whether an action can proceed or not, i.e. if its not being challenged or disputed
* @param _actionId Identification number of the action being queried in the context of the Agreement app
* @return True if the action can proceed, false otherwise
*/
function _canProceedAgreementAction(uint256 _actionId) internal view returns (bool) {
IAgreement agreement = _ensureAgreement();
return agreement.canProceed(_actionId);
}

/**
* @dev Tell the agreement linked to the disputable instance
* @return Agreement linked to the disputable instance
*/
function _getAgreement() internal view returns (IAgreement) {
return IAgreement(AGREEMENT_POSITION.getStorageAddress());
}

/**
* @dev Tell the agreement linked to the disputable instance
* @return Agreement linked to the disputable instance
*/
function _ensureAgreement() internal view returns (IAgreement) {
IAgreement agreement = _getAgreement();
require(agreement != IAgreement(0), ERROR_AGREEMENT_NOT_SET);
return agreement;
}
}
37 changes: 37 additions & 0 deletions contracts/apps/disputable/IAgreement.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* SPDX-License-Identitifer: MIT
*/

pragma solidity ^0.4.24;

import "./IArbitrable.sol";
import "../../acl/IACLOracle.sol";
import "../../lib/token/ERC20.sol";


contract IAgreement is IArbitrable, IACLOracle {
function sign() external;

function newAction(uint256 _disputableActionId, uint64 _lifetime, address _submitter, bytes _context) external returns (uint256);

function closeAction(uint256 _actionId) external;

function challengeAction(uint256 _actionId, uint256 _settlementOffer, bool _finishedSubmittingEvidence, bytes _context) external;

function settle(uint256 _actionId) external;
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved

function disputeAction(uint256 _actionId, bool _finishedSubmittingEvidence) external;

function register(
address _disputable,
sohkai marked this conversation as resolved.
Show resolved Hide resolved
ERC20 _collateralToken,
uint256 _actionAmount,
uint256 _challengeAmount,
uint64 _challengeDuration
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved
)
external;

function unregister(address _disputable) external;
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved

function canProceed(uint256 _actionId) external view returns (bool);
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved
}
56 changes: 56 additions & 0 deletions contracts/apps/disputable/IArbitrable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
sohkai marked this conversation as resolved.
Show resolved Hide resolved
* SPDX-License-Identitifer: MIT
*/

pragma solidity ^0.4.24;

import "./IArbitrator.sol";
import "../../lib/standards/ERC165.sol";


contract IArbitrable is ERC165 {
bytes4 internal constant ERC165_INTERFACE_ID = bytes4(0x01ffc9a7);
bytes4 internal constant ARBITRABLE_INTERFACE_ID = bytes4(0x88f3ee69);

/**
* @dev Emitted when an IArbitrable instance's dispute is ruled by an IArbitrator
* @param arbitrator IArbitrator instance ruling the dispute
* @param disputeId Identification number of the dispute being ruled by the arbitrator
* @param ruling Ruling given by the arbitrator
*/
event Ruled(IArbitrator indexed arbitrator, uint256 indexed disputeId, uint256 ruling);

/**
* @dev Emitted when new evidence is submitted for the IArbitrable instance's dispute
* @param arbitrator IArbitrator submitting the evidence for
* @param disputeId Identification number of the dispute receiving new evidence
* @param submitter Address of the account submitting the evidence
* @param evidence Data submitted for the evidence of the dispute
* @param finished Whether or not the submitter has finished submitting evidence
*/
event EvidenceSubmitted(IArbitrator indexed arbitrator, uint256 indexed disputeId, address indexed submitter, bytes evidence, bool finished);

/**
* @dev Submit evidence for a dispute
* @param _disputeId Id of the dispute in the Court
* @param _evidence Data submitted for the evidence related to the dispute
* @param _finished Whether or not the submitter has finished submitting evidence
*/
function submitEvidence(uint256 _disputeId, bytes _evidence, bool _finished) external;

/**
* @dev Give a ruling for a certain dispute, the account calling it must have rights to rule on the contract
* @param _disputeId Identification number of the dispute to be ruled
* @param _ruling Ruling given by the arbitrator, where 0 is reserved for "refused to make a decision"
*/
function rule(uint256 _disputeId, uint256 _ruling) external;

/**
* @dev ERC165 - Query if a contract implements a certain interface
* @param _interfaceId The interface identifier being queried, as specified in ERC-165
* @return True if this contract supports the given interface, false otherwise
*/
function supportsInterface(bytes4 _interfaceId) external pure returns (bool) {
return _interfaceId == ARBITRABLE_INTERFACE_ID || _interfaceId == ERC165_INTERFACE_ID;
}
}
47 changes: 47 additions & 0 deletions contracts/apps/disputable/IArbitrator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* SPDX-License-Identitifer: MIT
*/

pragma solidity ^0.4.24;

import "../../lib/token/ERC20.sol";


interface IArbitrator {
/**
* @dev Create a dispute over the Arbitrable sender with a number of possible rulings
* @param _possibleRulings Number of possible rulings allowed for the dispute
* @param _metadata Optional metadata that can be used to provide additional information on the dispute to be created
* @return Dispute identification number
*/
function createDispute(uint256 _possibleRulings, bytes _metadata) external returns (uint256);

/**
* @dev Close the evidence period of a dispute
* @param _disputeId Identification number of the dispute to close its evidence submitting period
*/
function closeEvidencePeriod(uint256 _disputeId) external;

/**
* @dev Execute the Arbitrable associated to a dispute based on its final ruling
* @param _disputeId Identification number of the dispute to be executed
*/
function executeRuling(uint256 _disputeId) external;

/**
* @dev Tell the dispute fees information to create a dispute
* @return recipient Address where the corresponding dispute fees must be transferred to
* @return feeToken ERC20 token used for the fees
* @return feeAmount Total amount of fees that must be allowed to the recipient
*/
function getDisputeFees() external view returns (address recipient, ERC20 feeToken, uint256 feeAmount);

/**
* @dev Tell the subscription fees information for a subscriber to be up-to-date
* @param _subscriber Address of the account paying the subscription fees for
* @return recipient Address where the corresponding subscriptions fees must be transferred to
* @return feeToken ERC20 token used for the subscription fees
* @return feeAmount Total amount of fees that must be allowed to the recipient
*/
function getSubscriptionFees(address _subscriber) external view returns (address recipient, ERC20 feeToken, uint256 feeAmount);
}
37 changes: 37 additions & 0 deletions contracts/apps/disputable/IDisputable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* SPDX-License-Identitifer: MIT
*/

pragma solidity ^0.4.24;

import "./IAgreement.sol";
import "../../common/IForwarder.sol";
import "../../lib/token/ERC20.sol";
import "../../lib/standards/ERC165.sol";


contract IDisputable is IForwarder, ERC165 {
bytes4 internal constant ERC165_INTERFACE_ID = bytes4(0x01ffc9a7);
bytes4 internal constant DISPUTABLE_INTERFACE_ID = bytes4(0xef113021);
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved

function setAgreement(IAgreement _agreement) external;

function onDisputableActionChallenged(uint256 _disputableActionId, uint256 _challengeId, address _challenger) external;

function onDisputableActionAllowed(uint256 _disputableActionId) external;

function onDisputableActionRejected(uint256 _disputableActionId) external;

function onDisputableActionVoided(uint256 _disputableActionId) external;

function getAgreement() external view returns (IAgreement);

/**
* @dev Query if a contract implements a certain interface
* @param _interfaceId The interface identifier being queried, as specified in ERC-165
* @return True if the contract implements the requested interface and if its not 0xffffffff, false otherwise
*/
function supportsInterface(bytes4 _interfaceId) external pure returns (bool) {
return _interfaceId == DISPUTABLE_INTERFACE_ID || _interfaceId == ERC165_INTERFACE_ID;
}
}
Loading