mirror of
https://github.com/embarklabs/embark.git
synced 2025-01-19 10:15:59 +00:00
327 lines
9.8 KiB
Solidity
327 lines
9.8 KiB
Solidity
pragma solidity >=0.5.0 <0.6.0;
|
|
|
|
import "./UserStore.sol";
|
|
import "./License.sol";
|
|
import "./ArbitrationLicense.sol";
|
|
import "../common/SecuredFunctions.sol";
|
|
import "../common/USDStakable.sol";
|
|
import "../common/Medianizer.sol";
|
|
import "../proxy/Proxiable.sol";
|
|
|
|
|
|
/**
|
|
* @title OfferStore
|
|
* @dev Offers registry
|
|
*/
|
|
contract OfferStore is USDStakable, SecuredFunctions, Proxiable {
|
|
|
|
struct Offer {
|
|
int16 margin;
|
|
uint[] paymentMethods;
|
|
uint limitL;
|
|
uint limitU;
|
|
address asset;
|
|
string currency;
|
|
address payable owner;
|
|
address payable arbitrator;
|
|
bool deleted;
|
|
}
|
|
|
|
License public sellingLicenses;
|
|
ArbitrationLicense public arbitrationLicenses;
|
|
UserStore public userStore;
|
|
|
|
Offer[] public offers;
|
|
mapping(address => uint256[]) public addressToOffers;
|
|
mapping(address => mapping (uint256 => bool)) public offerWhitelist;
|
|
|
|
uint public maxOffers = 10;
|
|
mapping(address => uint) public offerCnt;
|
|
|
|
event OfferAdded(
|
|
address owner,
|
|
uint256 offerId,
|
|
address asset,
|
|
string location,
|
|
string currency,
|
|
string username,
|
|
uint[] paymentMethods,
|
|
uint limitL,
|
|
uint limitU,
|
|
int16 margin
|
|
);
|
|
|
|
event OfferRemoved(address owner, uint256 offerId);
|
|
|
|
/**
|
|
* @param _userStore User store contract address
|
|
* @param _sellingLicenses Sellers licenses contract address
|
|
* @param _arbitrationLicenses Arbitrators licenses contract address
|
|
* @param _burnAddress Address to send slashed offer funds
|
|
* @param _medianizer DAI medianizer to obtain USD price
|
|
*/
|
|
constructor(address _userStore, address _sellingLicenses, address _arbitrationLicenses, address payable _burnAddress, address _medianizer) public
|
|
USDStakable(_burnAddress, _medianizer)
|
|
{
|
|
init(_userStore, _sellingLicenses, _arbitrationLicenses, _burnAddress, _medianizer);
|
|
}
|
|
|
|
/**
|
|
* @dev Initialize contract (used with proxy). Can only be called once
|
|
* @param _userStore User store contract address
|
|
* @param _sellingLicenses Sellers licenses contract address
|
|
* @param _arbitrationLicenses Arbitrators licenses contract address
|
|
* @param _burnAddress Address to send slashed offer funds
|
|
*/
|
|
function init(
|
|
address _userStore,
|
|
address _sellingLicenses,
|
|
address _arbitrationLicenses,
|
|
address payable _burnAddress,
|
|
address _medianizer
|
|
) public {
|
|
assert(_initialized == false);
|
|
|
|
_initialized = true;
|
|
|
|
userStore = UserStore(_userStore);
|
|
sellingLicenses = License(_sellingLicenses);
|
|
arbitrationLicenses = ArbitrationLicense(_arbitrationLicenses);
|
|
burnAddress = _burnAddress;
|
|
|
|
maxOffers = 10;
|
|
basePrice = 1 ether; // 1 USD
|
|
medianizer = Medianizer(_medianizer);
|
|
|
|
_setOwner(msg.sender);
|
|
}
|
|
|
|
function updateCode(address newCode) public onlyOwner {
|
|
updateCodeAddress(newCode);
|
|
}
|
|
|
|
event LicensesChanged(address sender, address oldSellingLicenses, address newSellingLicenses, address oldArbitrationLicenses, address newArbitrationLicenses);
|
|
|
|
/**
|
|
* @dev Change license addresses
|
|
* @param _sellingLicenses Sellers licenses contract address
|
|
* @param _arbitrationLicenses Arbitrators licenses contract address
|
|
*/
|
|
function setLicenses(
|
|
address _sellingLicenses,
|
|
address _arbitrationLicenses
|
|
) public onlyOwner {
|
|
emit LicensesChanged(msg.sender, address(sellingLicenses), address(_sellingLicenses), address(arbitrationLicenses), (_arbitrationLicenses));
|
|
|
|
sellingLicenses = License(_sellingLicenses);
|
|
arbitrationLicenses = ArbitrationLicense(_arbitrationLicenses);
|
|
}
|
|
|
|
event MaxOffersChanged(address sender, uint oldMax, uint newMax);
|
|
|
|
/**
|
|
* @dev Change max offers allowed per seller
|
|
* @param _newMax New max offers amount
|
|
*/
|
|
function setMaxOffers(
|
|
uint _newMax
|
|
) public onlyOwner {
|
|
emit MaxOffersChanged(msg.sender, maxOffers, _newMax);
|
|
maxOffers = _newMax;
|
|
}
|
|
|
|
/**
|
|
* @dev Add a new offer with a new user if needed to the list
|
|
* @param _asset The address of the erc20 to exchange, pass 0x0 for Eth
|
|
* @param _contactData Contact Data ContactType:UserId
|
|
* @param _location The location on earth
|
|
* @param _currency The currency the user want to receive (USD, EUR...)
|
|
* @param _username The username of the user
|
|
* @param _paymentMethods The list of the payment methods the user accept
|
|
* @param _limitL Lower limit accepted
|
|
* @param _limitU Upper limit accepted
|
|
* @param _margin The margin for the user
|
|
* @param _arbitrator The arbitrator used by the offer
|
|
*/
|
|
function addOffer(
|
|
address _asset,
|
|
string memory _contactData,
|
|
string memory _location,
|
|
string memory _currency,
|
|
string memory _username,
|
|
uint[] memory _paymentMethods,
|
|
uint _limitL,
|
|
uint _limitU,
|
|
int16 _margin,
|
|
address payable _arbitrator
|
|
) public payable {
|
|
//require(sellingLicenses.isLicenseOwner(msg.sender), "Not a license owner");
|
|
|
|
require(offerCnt[msg.sender] < maxOffers, "Exceeds the max number of offers");
|
|
require(arbitrationLicenses.isAllowed(msg.sender, _arbitrator), "Arbitrator does not allow this transaction");
|
|
|
|
require(_limitL <= _limitU, "Invalid limits");
|
|
require(msg.sender != _arbitrator, "Cannot arbitrate own offers");
|
|
|
|
userStore.addOrUpdateUser(
|
|
msg.sender,
|
|
_contactData,
|
|
_location,
|
|
_username
|
|
);
|
|
|
|
Offer memory newOffer = Offer(
|
|
_margin,
|
|
_paymentMethods,
|
|
_limitL,
|
|
_limitU,
|
|
_asset,
|
|
_currency,
|
|
msg.sender,
|
|
_arbitrator,
|
|
false
|
|
);
|
|
|
|
uint256 offerId = offers.push(newOffer) - 1;
|
|
offerWhitelist[msg.sender][offerId] = true;
|
|
addressToOffers[msg.sender].push(offerId);
|
|
offerCnt[msg.sender]++;
|
|
|
|
emit OfferAdded(
|
|
msg.sender,
|
|
offerId,
|
|
_asset,
|
|
_location,
|
|
_currency,
|
|
_username,
|
|
_paymentMethods,
|
|
_limitL,
|
|
_limitU,
|
|
_margin);
|
|
|
|
_stake(offerId, msg.sender, _asset);
|
|
}
|
|
|
|
/**
|
|
* @notice Remove user offer
|
|
* @dev Removed offers are marked as deleted instead of being deleted
|
|
* @param _offerId Id of the offer to remove
|
|
*/
|
|
function removeOffer(uint256 _offerId) external {
|
|
require(offerWhitelist[msg.sender][_offerId], "Offer does not exist");
|
|
|
|
offers[_offerId].deleted = true;
|
|
offerWhitelist[msg.sender][_offerId] = false;
|
|
emit OfferRemoved(msg.sender, _offerId);
|
|
|
|
if(offerCnt[msg.sender] - 1 > offerCnt[msg.sender]){
|
|
offerCnt[msg.sender] = 0;
|
|
} else {
|
|
offerCnt[msg.sender]--;
|
|
}
|
|
|
|
_unstake(_offerId);
|
|
}
|
|
|
|
/**
|
|
* @notice Get the offer by Id
|
|
* @dev normally we'd access the offers array, but it would not return the payment methods
|
|
* @param _id Offer id
|
|
* @return Offer data (see Offer struct)
|
|
*/
|
|
function offer(uint256 _id) external view returns (
|
|
address asset,
|
|
string memory currency,
|
|
int16 margin,
|
|
uint[] memory paymentMethods,
|
|
uint limitL,
|
|
uint limitU,
|
|
address payable owner,
|
|
address payable arbitrator,
|
|
bool deleted
|
|
) {
|
|
Offer memory theOffer = offers[_id];
|
|
|
|
// In case arbitrator rejects the seller
|
|
address payable offerArbitrator = theOffer.arbitrator;
|
|
if(!arbitrationLicenses.isAllowed(theOffer.owner, offerArbitrator)){
|
|
offerArbitrator = address(0);
|
|
}
|
|
|
|
return (
|
|
theOffer.asset,
|
|
theOffer.currency,
|
|
theOffer.margin,
|
|
theOffer.paymentMethods,
|
|
theOffer.limitL,
|
|
theOffer.limitU,
|
|
theOffer.owner,
|
|
offerArbitrator,
|
|
theOffer.deleted
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Get the offer's owner by Id
|
|
* @dev Helper function
|
|
* @param _id Offer id
|
|
* @return Seller address
|
|
*/
|
|
function getOfferOwner(uint256 _id) external view returns (address payable) {
|
|
return (offers[_id].owner);
|
|
}
|
|
|
|
/**
|
|
* @notice Get the offer's asset by Id
|
|
* @dev Helper function
|
|
* @param _id Offer id
|
|
* @return Token address used in the offer
|
|
*/
|
|
function getAsset(uint256 _id) external view returns (address) {
|
|
return (offers[_id].asset);
|
|
}
|
|
|
|
/**
|
|
* @notice Get the offer's arbitrator by Id
|
|
* @dev Helper function
|
|
* @param _id Offer id
|
|
* @return Arbitrator address
|
|
*/
|
|
function getArbitrator(uint256 _id) external view returns (address payable) {
|
|
return (offers[_id].arbitrator);
|
|
}
|
|
|
|
/**
|
|
* @notice Get the size of the offers
|
|
* @return Number of offers stored in the contract
|
|
*/
|
|
function offersSize() external view returns (uint256) {
|
|
return offers.length;
|
|
}
|
|
|
|
/**
|
|
* @notice Get all the offer ids of the address in params
|
|
* @param _address Address of the offers
|
|
* @return Array of offer ids for a specific address
|
|
*/
|
|
function getOfferIds(address _address) external view returns (uint256[] memory) {
|
|
return addressToOffers[_address];
|
|
}
|
|
|
|
/**
|
|
* @dev Slash offer stake. If the sender is not the escrow contract, nothing will happen
|
|
* @param _offerId Offer Id to slash
|
|
*/
|
|
function slashStake(uint _offerId) external onlyAllowedContracts {
|
|
_slash(_offerId);
|
|
}
|
|
|
|
/**
|
|
* @dev Refunds a stake. Can be called automatically after an escrow is released
|
|
* @param _offerId Offer Id to slash
|
|
*/
|
|
function refundStake(uint _offerId) external onlyAllowedContracts {
|
|
_refundStake(_offerId);
|
|
}
|
|
}
|