Last active
February 27, 2018 10:22
-
-
Save sherlock-shi-x/db0a295240f012182202ac08063d6d7e to your computer and use it in GitHub Desktop.
STwithDoor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.20; | |
library SafeMath { | |
/** | |
* @dev Multiplies two numbers, throws on overflow. | |
*/ | |
function mul(uint256 a, uint256 b) internal pure returns (uint256) { | |
if (a == 0) { | |
return 0; | |
} | |
uint256 c = a * b; | |
assert(c / a == b); | |
return c; | |
} | |
/** | |
* @dev Integer division of two numbers, truncating the quotient. | |
*/ | |
function div(uint256 a, uint256 b) internal pure returns (uint256) { | |
// assert(b > 0); // Solidity automatically throws when dividing by 0 | |
uint256 c = a / b; | |
// assert(a == b * c + a % b); // There is no case in which this doesn't hold | |
return c; | |
} | |
/** | |
* @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). | |
*/ | |
function sub(uint256 a, uint256 b) internal pure returns (uint256) { | |
assert(b <= a); | |
return a - b; | |
} | |
/** | |
* @dev Adds two numbers, throws on overflow. | |
*/ | |
function add(uint256 a, uint256 b) internal pure returns (uint256) { | |
uint256 c = a + b; | |
assert(c >= a); | |
return c; | |
} | |
} | |
/// @title Interface for contracts conforming to ERC-721: Non-Fungible Tokens | |
/// @author Dieter Shirley <[email protected]> (https://github.com/dete) | |
contract ERC721 { | |
// Required methods | |
function totalSupply() public view returns (uint256 total); | |
function balanceOf(address _owner) public view returns (uint256 balance); | |
function ownerOf(uint256 _tokenId) public view returns (address owner); | |
function approve(address _to, uint256 _tokenId) public; | |
function transfer(address _to, uint256 _tokenId) public; | |
function transferFrom(address _from, address _to, uint256 _tokenId) public; | |
// Events | |
event Transfer(address from, address to, uint256 tokenId); | |
event Approval(address owner, address approved, uint256 tokenId); | |
// Optional | |
function name() public view returns (string name); | |
function symbol() public view returns (string symbol); | |
// function tokensOfOwner(address _owner) external view returns (uint256[] tokenIds); | |
// function tokenMetadata(uint256 _tokenId, string _preferredTransport) public view returns (string infoUrl); | |
// ERC-165 Compatibility (https://github.com/ethereum/EIPs/issues/165) | |
// function supportsInterface(bytes4 _interfaceID) external view returns (bool); | |
} | |
contract SponsorToken is ERC721{ | |
using SafeMath for uint256; | |
event Bought (uint256 indexed _tokenId, address indexed _owner, uint256 _price); | |
event Sold (uint256 indexed _tokenId, address indexed _owner, uint256 _price); | |
event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); | |
event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); | |
address private owner; | |
uint256 counter; | |
mapping (uint256 => address) private ownerOfToken; | |
mapping (uint256 => uint256) private priceOfToken; | |
mapping (uint256 => address) private approvedOfToken; | |
mapping (uint256 => address) private creatorOfToken; | |
mapping (uint256 => uint256) private parentOfToken; | |
mapping (uint256 => uint256) private balanceOfToken; | |
mapping (uint256 => uint256) private free1OfToken; | |
mapping (uint256 => uint256) private free2OfToken; | |
function SponsorToken () public { | |
owner = msg.sender; | |
creatorOfToken[counter] = ownerOfToken[counter] = msg.sender; | |
priceOfToken[counter] = 1 ether; | |
parentOfToken[counter] = 0; | |
free1OfToken[counter] = 0; | |
free2OfToken[counter] = 0; | |
counter += 1; | |
} | |
/* Modifiers */ | |
modifier onlyOwner(uint256 _tokenId) { | |
require(ownerOfToken[_tokenId] == msg.sender); | |
_; | |
} | |
modifier onlyCreator(uint256 _tokenId) { | |
require(creatorOfToken[_tokenId] == msg.sender); | |
_; | |
} | |
modifier onlyRoot() { | |
require(creatorOfToken[0] == msg.sender); | |
_; | |
} | |
/* Owner */ | |
function setCreator (address _creator, uint _tokenId) onlyCreator(_tokenId) public { | |
creatorOfToken[_tokenId] = _creator; | |
} | |
/* Judge Fake Token */ | |
function judgeFakeToken (uint256 _tokenId) onlyRoot() public { | |
creatorOfToken[_tokenId] = msg.sender; | |
} | |
function judgeFakeTokenAndTransfer (uint256 _tokenId, address _plaintiff) onlyRoot() public { | |
creatorOfToken[_tokenId] = _plaintiff; | |
} | |
/* Withdraw */ | |
function withdrawAllFromRoot () onlyRoot() public { | |
uint256 t = balanceOfToken[0]; | |
balanceOfToken[0] = 0; | |
msg.sender.transfer(t); | |
} | |
function withdrawAllFromToken (uint256 _tokenId) onlyCreator(_tokenId) public { | |
uint256 t = balanceOfToken[_tokenId]; | |
uint256 r = t / 20; | |
balanceOfToken[_tokenId] = 0; | |
balanceOfToken[parentOfToken[_tokenId]] += r; | |
msg.sender.transfer(t - r); | |
} | |
function withdrawAmountFromToken (uint256 _tokenId, uint256 t) onlyCreator(_tokenId) public { | |
if (t > balanceOfToken[_tokenId]) t = balanceOfToken[_tokenId]; | |
uint256 r = t / 20; | |
balanceOfToken[_tokenId] = 0; | |
balanceOfToken[parentOfToken[_tokenId]] += r; | |
msg.sender.transfer(t - r); | |
} | |
function withdrawAll() public { | |
require(msg.sender == owner); | |
owner.transfer(this.balance); | |
} | |
/* Buying */ | |
function calculateNextPrice (uint256 _price) public view returns (uint256 _nextPrice) { | |
return _price.mul(117).div(98); | |
} | |
function calculateDevCut (uint256 _price) public view returns (uint256 _devCut) { | |
return _price.div(20); // 5% | |
} | |
function buy (uint256 _tokenId) payable public { | |
require(priceOf(_tokenId) > 0); | |
require(ownerOf(_tokenId) != address(0)); | |
require(msg.value >= priceOf(_tokenId)); | |
require(ownerOf(_tokenId) != msg.sender); | |
require(!isContract(msg.sender)); | |
require(msg.sender != address(0)); | |
require(now >= free1OfToken[_tokenId]); | |
address oldOwner = ownerOf(_tokenId); | |
address newOwner = msg.sender; | |
uint256 price = priceOf(_tokenId); | |
uint256 excess = msg.value.sub(price); | |
_transfer(oldOwner, newOwner, _tokenId); | |
priceOfToken[_tokenId] = nextPriceOf(_tokenId); | |
Bought(_tokenId, newOwner, price); | |
Sold(_tokenId, oldOwner, price); | |
// Devevloper's cut which is left in contract and accesed by | |
// `withdrawAll` and `withdrawAmountTo` methods. | |
uint256 devCut = calculateDevCut(price); | |
// Transfer payment to old owner minus the developer's cut. | |
oldOwner.transfer(price.sub(devCut)); | |
uint256 shareHolderCut = devCut.div(20); | |
ownerOfToken[parentOfToken[_tokenId]].transfer(shareHolderCut); | |
balanceOfToken[_tokenId] += devCut.sub(shareHolderCut); | |
if (excess > 0) { | |
newOwner.transfer(excess); | |
} | |
} | |
/* ERC721 */ | |
function name() public view returns (string name) { | |
return "sponsortoken.io"; | |
} | |
function symbol() public view returns (string symbol) { | |
return "SST"; | |
} | |
function totalSupply() public view returns (uint256 _totalSupply) { | |
return counter; | |
} | |
function balanceOf (address _owner) public view returns (uint256 _balance) { | |
uint256 t = 0; | |
for (uint256 i = 0; i < counter; i++) { | |
if (ownerOf(i) == _owner) { | |
t++; | |
} | |
} | |
return t; | |
} | |
function ownerOf (uint256 _tokenId) public view returns (address _owner) { | |
return ownerOfToken[_tokenId]; | |
} | |
function creatorOf (uint256 _tokenId) public view returns (address _creator) { | |
return creatorOfToken[_tokenId]; | |
} | |
function parentOf (uint256 _tokenId) public view returns (uint256 _parent) { | |
return parentOfToken[_tokenId]; | |
} | |
function free1Of (uint256 _tokenId) public view returns (uint256 _free) { | |
return free1OfToken[_tokenId]; | |
} | |
function free2Of (uint256 _tokenId) public view returns (uint256 _free) { | |
return free2OfToken[_tokenId]; | |
} | |
function balanceFromToken (uint256 _tokenId) public view returns (uint256 _balance) { | |
return balanceOfToken[_tokenId]; | |
} | |
function tokensOf (address _owner) public view returns (uint256[] _tokenIds) { | |
uint256[] memory tokens = new uint256[](balanceOf(_owner)); | |
uint256 tokenCounter = 0; | |
for (uint256 i = 0; i < counter; i++) { | |
if (ownerOf(i) == _owner) { | |
tokens[tokenCounter] = i; | |
tokenCounter += 1; | |
} | |
} | |
return tokens; | |
} | |
function tokenExists (uint256 _tokenId) public view returns (bool _exists) { | |
return priceOf(_tokenId) > 0; | |
} | |
function approvedFor(uint256 _tokenId) public view returns (address _approved) { | |
return approvedOfToken[_tokenId]; | |
} | |
function approve(address _to, uint256 _tokenId) public { | |
require(msg.sender != _to); | |
require(tokenExists(_tokenId)); | |
require(ownerOf(_tokenId) == msg.sender); | |
if (_to == 0) { | |
if (approvedOfToken[_tokenId] != 0) { | |
delete approvedOfToken[_tokenId]; | |
Approval(msg.sender, 0, _tokenId); | |
} | |
} else { | |
approvedOfToken[_tokenId] = _to; | |
Approval(msg.sender, _to, _tokenId); | |
} | |
} | |
/* Transferring a country to another owner will entitle the new owner the profits from `buy` */ | |
function transfer(address _to, uint256 _tokenId) public { | |
require(msg.sender == ownerOf(_tokenId)); | |
_transfer(msg.sender, _to, _tokenId); | |
} | |
function transferFrom(address _from, address _to, uint256 _tokenId) public { | |
require(approvedFor(_tokenId) == msg.sender); | |
_transfer(_from, _to, _tokenId); | |
} | |
function _transfer(address _from, address _to, uint256 _tokenId) internal { | |
require(tokenExists(_tokenId)); | |
require(ownerOf(_tokenId) == _from); | |
require(_to != address(0)); | |
require(_to != address(this)); | |
ownerOfToken[_tokenId] = _to; | |
approvedOfToken[_tokenId] = 0; | |
Transfer(_from, _to, _tokenId); | |
} | |
/* Read */ | |
function priceOf (uint256 _tokenId) public view returns (uint256 _price) { | |
return priceOfToken[_tokenId]; | |
} | |
function nextPriceOf (uint256 _tokenId) public view returns (uint256 _nextPrice) { | |
return calculateNextPrice(priceOf(_tokenId)); | |
} | |
function allOf (uint256 _tokenId) external view returns (address _owner, address _creator, uint256 _price, uint256 _nextPrice, uint256 _frozen1, uint256 _frozen2, uint256 _parent) { | |
return (ownerOfToken[_tokenId], creatorOfToken[_tokenId], priceOfToken[_tokenId], nextPriceOf(_tokenId), free1OfToken[_tokenId], free2OfToken[_tokenId], parentOfToken[_tokenId]); | |
} | |
/* Util */ | |
function isContract(address addr) internal view returns (bool) { | |
uint size; | |
assembly { size := extcodesize(addr) } // solium-disable-line | |
return size > 0; | |
} | |
function changePrice(uint256 _tokenId, uint256 _price, uint256 _frozen1, uint256 _frozen2) onlyOwner(_tokenId) public { | |
require(now >= free2OfToken[_tokenId]); | |
priceOfToken[_tokenId] = _price; | |
free1OfToken[_tokenId] = now + _frozen1; | |
free2OfToken[_tokenId] = now + _frozen1 + _frozen2; | |
} | |
function issueToken(uint256 _price, uint256 _frozen1, uint256 _frozen2, uint256 _parent) public { | |
require(_parent <= counter); | |
creatorOfToken[counter] = ownerOfToken[counter] = msg.sender; | |
priceOfToken[counter] = _price; | |
parentOfToken[counter] = _parent; | |
free1OfToken[counter] = now + _frozen1; | |
free2OfToken[counter] = now + _frozen1 + _frozen2; | |
counter += 1; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment