mirror of https://github.com/embarklabs/embark.git
231 lines
8.8 KiB
Solidity
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);
|
|
}
|
|
}
|