embark/dapps/tests/teller-contracts/contracts/teller-network/ArbitrationLicense.sol

231 lines
8.8 KiB
Solidity

/* solium-disable security/no-block-members */
pragma solidity ^0.5.8;
import "./License.sol";
/**
* @title ArbitratorLicense
* @dev Contract for management of an arbitrator license
*/
contract ArbitrationLicense is License {
enum RequestStatus {NONE,AWAIT,ACCEPTED,REJECTED,CLOSED}
struct Request{
address seller;
address arbitrator;
RequestStatus status;
uint date;
}
struct ArbitratorLicenseDetails {
uint id;
bool acceptAny;// accept any seller
}
mapping(address => ArbitratorLicenseDetails) public arbitratorlicenseDetails;
mapping(address => mapping(address => bool)) public permissions;
mapping(address => mapping(address => bool)) public blacklist;
mapping(bytes32 => Request) public requests;
event ArbitratorRequested(bytes32 id, address indexed seller, address indexed arbitrator);
event RequestAccepted(bytes32 id, address indexed arbitrator, address indexed seller);
event RequestRejected(bytes32 id, address indexed arbitrator, address indexed seller);
event RequestCanceled(bytes32 id, address indexed arbitrator, address indexed seller);
event BlacklistSeller(address indexed arbitrator, address indexed seller);
event UnBlacklistSeller(address indexed arbitrator, address indexed seller);
/**
* @param _tokenAddress Address of token used to pay for licenses (SNT)
* @param _price Amount of token needed to buy a license
* @param _burnAddress Burn address where the price of the license is sent
*/
constructor(address _tokenAddress, uint256 _price, address _burnAddress)
License(_tokenAddress, _price, _burnAddress)
public {}
/**
* @notice Buy an arbitrator license
*/
function buy() external returns(uint) {
return _buy(msg.sender, false);
}
/**
* @notice Buy an arbitrator license and set if the arbitrator accepts any seller
* @param _acceptAny When set to true, all sellers are accepted by the arbitrator
*/
function buy(bool _acceptAny) external returns(uint) {
return _buy(msg.sender, _acceptAny);
}
/**
* @notice Buy an arbitrator license and set if the arbitrator accepts any seller. Sets the arbitrator as the address in params instead of the sender
* @param _sender Address of the arbitrator
* @param _acceptAny When set to true, all sellers are accepted by the arbitrator
*/
function _buy(address _sender, bool _acceptAny) internal returns (uint id) {
id = _buyFrom(_sender);
arbitratorlicenseDetails[_sender].id = id;
arbitratorlicenseDetails[_sender].acceptAny = _acceptAny;
}
/**
* @notice Change acceptAny parameter for arbitrator
* @param _acceptAny indicates does arbitrator allow to accept any seller/choose sellers
*/
function changeAcceptAny(bool _acceptAny) public {
require(isLicenseOwner(msg.sender), "Message sender should have a valid arbitrator license");
require(arbitratorlicenseDetails[msg.sender].acceptAny != _acceptAny,
"Message sender should pass parameter different from the current one");
arbitratorlicenseDetails[msg.sender].acceptAny = _acceptAny;
}
/**
* @notice Allows arbitrator to accept a seller
* @param _arbitrator address of a licensed arbitrator
*/
function requestArbitrator(address _arbitrator) public {
require(isLicenseOwner(_arbitrator), "Arbitrator should have a valid license");
require(!arbitratorlicenseDetails[_arbitrator].acceptAny, "Arbitrator already accepts all cases");
bytes32 _id = keccak256(abi.encodePacked(_arbitrator, msg.sender));
RequestStatus _status = requests[_id].status;
require(_status != RequestStatus.AWAIT && _status != RequestStatus.ACCEPTED, "Invalid request status");
if(_status == RequestStatus.REJECTED || _status == RequestStatus.CLOSED){
require(requests[_id].date + 3 days < block.timestamp,
"Must wait 3 days before requesting the arbitrator again");
}
requests[_id] = Request({
seller: msg.sender,
arbitrator: _arbitrator,
status: RequestStatus.AWAIT,
date: block.timestamp
});
emit ArbitratorRequested(_id, msg.sender, _arbitrator);
}
/**
* @dev Get Request Id
* @param _arbitrator Arbitrator address
* @param _account Seller account
* @return Request Id
*/
function getId(address _arbitrator, address _account) external pure returns(bytes32){
return keccak256(abi.encodePacked(_arbitrator,_account));
}
/**
* @notice Allows arbitrator to accept a seller's request
* @param _id request id
*/
function acceptRequest(bytes32 _id) public {
require(isLicenseOwner(msg.sender), "Arbitrator should have a valid license");
require(requests[_id].status == RequestStatus.AWAIT, "This request is not pending");
require(!arbitratorlicenseDetails[msg.sender].acceptAny, "Arbitrator already accepts all cases");
require(requests[_id].arbitrator == msg.sender, "Invalid arbitrator");
requests[_id].status = RequestStatus.ACCEPTED;
address _seller = requests[_id].seller;
permissions[msg.sender][_seller] = true;
emit RequestAccepted(_id, msg.sender, requests[_id].seller);
}
/**
* @notice Allows arbitrator to reject a request
* @param _id request id
*/
function rejectRequest(bytes32 _id) public {
require(isLicenseOwner(msg.sender), "Arbitrator should have a valid license");
require(requests[_id].status == RequestStatus.AWAIT || requests[_id].status == RequestStatus.ACCEPTED,
"Invalid request status");
require(!arbitratorlicenseDetails[msg.sender].acceptAny, "Arbitrator accepts all cases");
require(requests[_id].arbitrator == msg.sender, "Invalid arbitrator");
requests[_id].status = RequestStatus.REJECTED;
requests[_id].date = block.timestamp;
address _seller = requests[_id].seller;
permissions[msg.sender][_seller] = false;
emit RequestRejected(_id, msg.sender, requests[_id].seller);
}
/**
* @notice Allows seller to cancel a request
* @param _id request id
*/
function cancelRequest(bytes32 _id) public {
require(requests[_id].seller == msg.sender, "This request id does not belong to the message sender");
require(requests[_id].status == RequestStatus.AWAIT || requests[_id].status == RequestStatus.ACCEPTED, "Invalid request status");
address arbitrator = requests[_id].arbitrator;
requests[_id].status = RequestStatus.CLOSED;
requests[_id].date = block.timestamp;
address _arbitrator = requests[_id].arbitrator;
permissions[_arbitrator][msg.sender] = false;
emit RequestCanceled(_id, arbitrator, requests[_id].seller);
}
/**
* @notice Allows arbitrator to blacklist a seller
* @param _seller Seller address
*/
function blacklistSeller(address _seller) public {
require(isLicenseOwner(msg.sender), "Arbitrator should have a valid license");
blacklist[msg.sender][_seller] = true;
emit BlacklistSeller(msg.sender, _seller);
}
/**
* @notice Allows arbitrator to remove a seller from the blacklist
* @param _seller Seller address
*/
function unBlacklistSeller(address _seller) public {
require(isLicenseOwner(msg.sender), "Arbitrator should have a valid license");
blacklist[msg.sender][_seller] = false;
emit UnBlacklistSeller(msg.sender, _seller);
}
/**
* @notice Checks if Arbitrator permits to use his/her services
* @param _seller sellers's address
* @param _arbitrator arbitrator's address
*/
function isAllowed(address _seller, address _arbitrator) public view returns(bool) {
return (arbitratorlicenseDetails[_arbitrator].acceptAny && !blacklist[_arbitrator][_seller]) || permissions[_arbitrator][_seller];
}
/**
* @notice Support for "approveAndCall". Callable only by `token()`.
* @param _from Who approved.
* @param _amount Amount being approved, need to be equal `price()`.
* @param _token Token being approved, need to be equal `token()`.
* @param _data Abi encoded data with selector of `buy(and)`.
*/
function receiveApproval(address _from, uint256 _amount, address _token, bytes memory _data) public {
require(_amount == price, "Wrong value");
require(_token == address(token), "Wrong token");
require(_token == address(msg.sender), "Wrong call");
require(_data.length == 4, "Wrong data length");
require(_abiDecodeBuy(_data) == bytes4(0xa6f2ae3a), "Wrong method selector"); //bytes4(keccak256("buy()"))
_buy(_from, false);
}
}