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 all 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
161 changes: 161 additions & 0 deletions contracts/apps/disputable/DisputableAragonApp.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* 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;

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. We provide a base implementation to ensure that the `onlyAgreement` modifier
* is included. Developers of derived Disputable apps should implement an internal abstract implementation of the hook.
* @param _disputableActionId Identifier of the action to be challenged
* @param _challengeId Identifier of the challenge in the context of the Agreement
* @param _challenger Address that submitted the challenge
*/
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. We provide a base implementation to ensure that the `onlyAgreement` modifier
* is included. Developers of derived Disputable apps should implement an internal abstract implementation of the hook.
* @param _disputableActionId Identifier of the 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. We provide a base implementation to ensure that the `onlyAgreement` modifier
* is included. Developers of derived Disputable apps should implement an internal abstract implementation of the hook.
* @param _disputableActionId Identifier of the 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. We provide a base implementation to ensure that the `onlyAgreement` modifier
* is included. Developers of derived Disputable apps should implement an internal abstract implementation of the hook.
* @param _disputableActionId Identifier of the 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 linked Agreement
* @return Agreement
*/
function getAgreement() external view returns (IAgreement) {
return _getAgreement();
}

/**
* @dev Internal implementation of the `onDisputableActionChallenged` hook
* @param _disputableActionId Identifier of the action to be challenged
* @param _challengeId Identifier of the challenge in the context of the Agreement
* @param _challenger Address that submitted the challenge
*/
function _onDisputableActionChallenged(uint256 _disputableActionId, uint256 _challengeId, address _challenger) internal;

/**
* @dev Internal implementation of the `onDisputableActionRejected` hook
* @param _disputableActionId Identifier of the action to be rejected
*/
function _onDisputableActionRejected(uint256 _disputableActionId) internal;

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

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

/**
* @dev Create a new action in the Agreement
* @param _disputableActionId Identifier of the action in the context of the Disputable
* @param _context Link to human-readable context for the given action
* @param _submitter Address that submitted the action
* @return Unique identifier 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 Identifier of the action in the context of the Agreement
*/
function _closeAgreementAction(uint256 _actionId) internal {
IAgreement agreement = _ensureAgreement();
agreement.closeAction(_actionId);
}

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

/**
* @dev Tell the linked Agreement or revert if it has not been set
* @return Agreement
*/
function _ensureAgreement() internal view returns (IAgreement) {
IAgreement agreement = _getAgreement();
require(agreement != IAgreement(0), ERROR_AGREEMENT_STATE_INVALID);
return agreement;
}
}
103 changes: 103 additions & 0 deletions contracts/apps/disputable/IAgreement.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* 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 SettingChanged(uint256 settingId);
event DisputableAppActivated(address indexed disputable);
event DisputableAppDeactivated(address indexed disputable);
event CollateralRequirementChanged(address indexed disputable, uint256 collateralRequirementId);
event ActionSubmitted(uint256 indexed actionId, address indexed disputable);
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);

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

function sign() external;

function activate(
address _disputable,
ERC20 _collateralToken,
uint256 _actionAmount,
uint256 _challengeAmount,
uint64 _challengeDuration
)
external;

function deactivate(address _disputable) 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 settleAction(uint256 _actionId) external;

function disputeAction(uint256 _actionId, bool _finishedSubmittingEvidence) external;

function getSigner(address _signer) external view returns (uint256 lastSettingIdSigned, bool mustSign);

function getCurrentSettingId() external view returns (uint256);

function getSetting(uint256 _settingId) external view returns (IArbitrator arbitrator, string title, bytes content);

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
);

function getAction(uint256 _actionId) external view
returns (
address disputable,
uint256 disputableActionId,
uint256 collateralRequirementId,
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
);
}
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

event AgreementSet(IAgreement indexed agreement);

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 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;
}
}
62 changes: 62 additions & 0 deletions contracts/lib/arbitration/IArbitrable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
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";


/**
* @title Arbitrable interface
* @dev This interface is the one extended by `IAgreement` so it can be used by `IArbitrator`, its dispute resolution protocol.
* This interface was manually-copied from https://github.com/aragon/aragon-court/blob/v1.1.3/contracts/arbitration/IArbitrable.sol
* since we are using different solidity versions.
*/
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