mirror of
https://github.com/embarklabs/embark.git
synced 2025-01-28 14:34:48 +00:00
167 lines
5.2 KiB
Solidity
167 lines
5.2 KiB
Solidity
/* solium-disable security/no-block-members */
|
|
/* solium-disable security/no-inline-assembly */
|
|
pragma solidity >=0.5.0 <0.6.0;
|
|
|
|
import "../common/Ownable.sol";
|
|
import "../token/ERC20Token.sol";
|
|
import "../token/SafeTransfer.sol";
|
|
import "../token/ApproveAndCallFallBack.sol";
|
|
import "../proxy/Proxiable.sol";
|
|
|
|
/**
|
|
* @title License
|
|
* @dev Contract for buying a license
|
|
*/
|
|
contract License is Ownable, ApproveAndCallFallBack, SafeTransfer, Proxiable {
|
|
uint256 public price;
|
|
|
|
ERC20Token token;
|
|
address burnAddress;
|
|
|
|
struct LicenseDetails {
|
|
uint price;
|
|
uint creationTime;
|
|
}
|
|
|
|
address[] public licenseOwners;
|
|
mapping(address => uint) public idxLicenseOwners;
|
|
mapping(address => LicenseDetails) public licenseDetails;
|
|
|
|
event Bought(address buyer, uint256 price);
|
|
event PriceChanged(uint256 _price);
|
|
event BurnAddressChanged(address sender, address prevBurnAddress, address newBurnAddress);
|
|
|
|
/**
|
|
* @dev Changes the burn address
|
|
* @param _burnAddress New burn address
|
|
*/
|
|
function setBurnAddress(address payable _burnAddress) external onlyOwner {
|
|
emit BurnAddressChanged(msg.sender, burnAddress, _burnAddress);
|
|
burnAddress = _burnAddress;
|
|
}
|
|
|
|
/**
|
|
* @param _tokenAddress Address of token used to pay for licenses (SNT)
|
|
* @param _price Price of the licenses
|
|
* @param _burnAddress Address where the license fee is going to be sent
|
|
*/
|
|
constructor(address _tokenAddress, uint256 _price, address _burnAddress) public {
|
|
init(_tokenAddress, _price, _burnAddress);
|
|
}
|
|
|
|
/**
|
|
* @dev Initialize contract (used with proxy). Can only be called once
|
|
* @param _tokenAddress Address of token used to pay for licenses (SNT)
|
|
* @param _price Price of the licenses
|
|
* @param _burnAddress Address where the license fee is going to be sent
|
|
*/
|
|
function init(
|
|
address _tokenAddress,
|
|
uint256 _price,
|
|
address _burnAddress
|
|
) public {
|
|
assert(_initialized == false);
|
|
|
|
_initialized = true;
|
|
|
|
price = _price;
|
|
token = ERC20Token(_tokenAddress);
|
|
burnAddress = _burnAddress;
|
|
|
|
_setOwner(msg.sender);
|
|
}
|
|
|
|
function updateCode(address newCode) public onlyOwner {
|
|
updateCodeAddress(newCode);
|
|
}
|
|
|
|
/**
|
|
* @notice Check if the address already owns a license
|
|
* @param _address The address to check
|
|
* @return bool
|
|
*/
|
|
function isLicenseOwner(address _address) public view returns (bool) {
|
|
return licenseDetails[_address].price != 0 && licenseDetails[_address].creationTime != 0;
|
|
}
|
|
|
|
/**
|
|
* @notice Buy a license
|
|
* @dev Requires value to be equal to the price of the license.
|
|
* The msg.sender must not already own a license.
|
|
*/
|
|
function buy() external returns(uint) {
|
|
uint id = _buyFrom(msg.sender);
|
|
return id;
|
|
}
|
|
|
|
/**
|
|
* @notice Buy a license
|
|
* @dev Requires value to be equal to the price of the license.
|
|
* The _owner must not already own a license.
|
|
*/
|
|
function _buyFrom(address _licenseOwner) internal returns(uint) {
|
|
require(licenseDetails[_licenseOwner].creationTime == 0, "License already bought");
|
|
|
|
licenseDetails[_licenseOwner] = LicenseDetails({
|
|
price: price,
|
|
creationTime: block.timestamp
|
|
});
|
|
|
|
uint idx = licenseOwners.push(_licenseOwner);
|
|
idxLicenseOwners[_licenseOwner] = idx;
|
|
|
|
emit Bought(_licenseOwner, price);
|
|
|
|
require(_safeTransferFrom(token, _licenseOwner, burnAddress, price), "Unsuccessful token transfer");
|
|
|
|
return idx;
|
|
}
|
|
|
|
/**
|
|
* @notice Set the license price
|
|
* @param _price The new price of the license
|
|
* @dev Only the owner of the contract can perform this action
|
|
*/
|
|
function setPrice(uint256 _price) external onlyOwner {
|
|
price = _price;
|
|
emit PriceChanged(_price);
|
|
}
|
|
|
|
/**
|
|
* @dev Get number of license owners
|
|
* @return uint
|
|
*/
|
|
function getNumLicenseOwners() external view returns (uint256) {
|
|
return licenseOwners.length;
|
|
}
|
|
|
|
/**
|
|
* @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()"))
|
|
|
|
_buyFrom(_from);
|
|
}
|
|
|
|
/**
|
|
* @dev Decodes abi encoded data with selector for "buy()".
|
|
* @param _data Abi encoded data.
|
|
* @return Decoded registry call.
|
|
*/
|
|
function _abiDecodeBuy(bytes memory _data) internal pure returns(bytes4 sig) {
|
|
assembly {
|
|
sig := mload(add(_data, add(0x20, 0)))
|
|
}
|
|
}
|
|
}
|