Skip to content

Commit

Permalink
Merge 6f622c4 into 8d40fea
Browse files Browse the repository at this point in the history
  • Loading branch information
facuspagnuolo committed Jun 26, 2020
2 parents 8d40fea + 6f622c4 commit 2dc6f3d
Show file tree
Hide file tree
Showing 11 changed files with 898 additions and 0 deletions.
161 changes: 161 additions & 0 deletions contracts/apps/disputable/DisputableAragonApp.sol
@@ -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);
}

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

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
@@ -0,0 +1,62 @@
/*
* 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 {
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;
}
}

0 comments on commit 2dc6f3d

Please sign in to comment.