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 8 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
167 changes: 167 additions & 0 deletions contracts/apps/disputable/DisputableAragonApp.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/*
* SPDX-License-Identifier: MIT
*/

pragma solidity ^0.4.24;

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


contract DisputableAragonApp is IDisputable, AragonApp {
/* Validation errors */
string internal constant ERROR_SENDER_NOT_AGREEMENT = "DISPUTABLE_SENDER_NOT_AGREEMENT";
string internal constant ERROR_AGREEMENT_STATE_INVALID = "DISPUTABLE_AGREEMENT_STATE_INVAL";

// This role is used to protect who can challenge actions in derived Disputable apps. However, it is not required
// to be validated in the app itself as the connected Agreement is responsible for performing the check on a challenge.
// 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);
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved

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

/**
* @notice Challenge disputable action #`_disputableActionId`
* @dev This hook must be implemented by Disputable apps. However, we are already providing a base method to make sure it is safely
* override by the developer. As you can see, this base implementation simply adds the `onlyAgreement` modifier and calls an
* internal abstract implementation of the hook that must be implemented by the developer.
* @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);
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* @notice Allow disputable action #`_disputableActionId`
* @dev This hook must be implemented by Disputable apps. However, we are already providing a base method to make sure it is safely
* override by the developer. As you can see, this base implementation simply adds the `onlyAgreement` modifier and calls an
* internal abstract implementation of the hook that must be implemented by the developer.
* @param _disputableActionId Identification number of the disputable action to be allowed
*/
function onDisputableActionAllowed(uint256 _disputableActionId) external onlyAgreement {
_onDisputableActionAllowed(_disputableActionId);
}

/**
* @notice Reject disputable action #`_disputableActionId`
* @dev This hook must be implemented by Disputable apps. However, we are already providing a base method to make sure it is safely
* override by the developer. As you can see, this base implementation simply adds the `onlyAgreement` modifier and calls an
* internal abstract implementation of the hook that must be implemented by the developer.
* @param _disputableActionId Identification number of the disputable action to be rejected
*/
function onDisputableActionRejected(uint256 _disputableActionId) external onlyAgreement {
_onDisputableActionRejected(_disputableActionId);
}

/**
* @notice Void disputable action #`_disputableActionId`
* @dev This hook must be implemented by Disputable apps. However, we are already providing a base method to make sure it is safely
* override by the developer. As you can see, this base implementation simply adds the `onlyAgreement` modifier and calls an
* internal abstract implementation of the hook that must be implemented by the developer.
* @param _disputableActionId Identification number of the disputable action to be voided
*/
function onDisputableActionVoided(uint256 _disputableActionId) external onlyAgreement {
_onDisputableActionVoided(_disputableActionId);
}

/**
* @notice Set Agreement to `_agreement`
* @param _agreement Agreement instance to be set
*/
function setAgreement(IAgreement _agreement) external auth(SET_AGREEMENT_ROLE) {
IAgreement agreement = _getAgreement();
require(agreement == IAgreement(0) && _agreement != IAgreement(0), ERROR_AGREEMENT_STATE_INVALID);

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

/**
* @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 Internal implementation of the `onDisputableActionChallenged` hook
* @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 Internal implementation of the `onDisputableActionRejected` hook
* @param _disputableActionId Identification number of the disputable action to be rejected
*/
function _onDisputableActionRejected(uint256 _disputableActionId) internal;

/**
* @dev Internal implementation of the `onDisputableActionAllowed` hook
* @param _disputableActionId Identification number of the disputable action to be allowed
*/
function _onDisputableActionAllowed(uint256 _disputableActionId) internal;

/**
* @dev Internal implementation of the `onDisputableActionVoided` hook
* @param _disputableActionId Identification number of the disputable action to be voided
*/
function _onDisputableActionVoided(uint256 _disputableActionId) internal;

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

/**
* @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);
}

/**
* @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_STATE_INVALID);
return agreement;
}
}
101 changes: 101 additions & 0 deletions contracts/apps/disputable/IAgreement.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* SPDX-License-Identifier: MIT
*/

pragma solidity ^0.4.24;

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


contract IAgreement is IArbitrable, IACLOracle {

event Signed(address indexed signer, uint256 settingId);
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved
event ActionSubmitted(uint256 indexed actionId);
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved
event ActionClosed(uint256 indexed actionId);
event ActionChallenged(uint256 indexed actionId, uint256 indexed challengeId);
event ActionSettled(uint256 indexed actionId, uint256 indexed challengeId);
event ActionDisputed(uint256 indexed actionId, uint256 indexed challengeId);
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved
event ActionAccepted(uint256 indexed actionId, uint256 indexed challengeId);
event ActionVoided(uint256 indexed actionId, uint256 indexed challengeId);
event ActionRejected(uint256 indexed actionId, uint256 indexed challengeId);
event DisputableAppRegistered(address indexed disputable);
event DisputableAppUnregistered(address indexed disputable);
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved

enum ChallengeState {
Waiting,
Settled,
Disputed,
Rejected,
Accepted,
Voided
}

function sign() external;

function newAction(uint256 _disputableActionId, bytes _context, address _submitter) 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 getSigner(address _signer) external view returns (uint256 lastSettingIdSigned, bool mustSign);

function getAction(uint256 _actionId) external view
returns (
address disputable,
uint256 disputableActionId,
uint256 collateralId,
sohkai marked this conversation as resolved.
Show resolved Hide resolved
uint256 settingId,
address submitter,
bool closed,
bytes context,
uint256 currentChallengeId
);

function getChallenge(uint256 _challengeId) external view
returns (
uint256 actionId,
address challenger,
uint64 endDate,
bytes context,
uint256 settlementOffer,
uint256 arbitratorFeeAmount,
ERC20 arbitratorFeeToken,
ChallengeState state,
bool submitterFinishedEvidence,
bool challengerFinishedEvidence,
uint256 disputeId,
uint256 ruling
);

function getCurrentSettingId() external view returns (uint256);

function getSetting(uint256 _settingId) external view returns (string title, bytes content, IArbitrator arbitrator);
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved

function getDisputableInfo(address _disputable) external view returns (bool registered, uint256 currentCollateralRequirementId);

function getCollateralRequirement(address _disputable, uint256 _collateralId) external view
returns (
ERC20 collateralToken,
uint256 actionAmount,
uint256 challengeAmount,
uint64 challengeDuration
);
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved
}
42 changes: 42 additions & 0 deletions contracts/apps/disputable/IDisputable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* SPDX-License-Identifier: MIT
*/

pragma solidity ^0.4.24;

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


contract IDisputable is 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);

function getDisputableAction(uint256 _disputableActionId) external view returns (uint64 endDate, bool challenged, bool finished);
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved

function canChallenge(uint256 _disputableActionId) external view returns (bool);

function canClose(uint256 _disputableActionId) external view returns (bool);

/**
* @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;
}
}
56 changes: 56 additions & 0 deletions contracts/lib/arbitration/IArbitrable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved
bingen marked this conversation as resolved.
Show resolved Hide resolved
* SPDX-License-Identifier: MIT
*/

pragma solidity ^0.4.24;

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


contract IArbitrable is ERC165 {
facuspagnuolo marked this conversation as resolved.
Show resolved Hide resolved
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;
}
}
Loading