pragma solidity ^0.4.21;
/// @title Interface for contracts conforming to ERC-721: Non-Fungible Tokens
/// @author MinakoKojima (https://github.com/lychees)
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;
// 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 LuckyPackage is ERC721{
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);
event RollDice(address indexed playerAddr, address indexed prizeIssuer, uint prizeId);
address private owner;
mapping (address => bool) private admins;
uint256 private tokenSize;
mapping (uint256 => address) private ownerOfToken;
mapping (uint256 => address) private approvedOfToken;
struct Package {
uint256 tokenId;
uint256 ratio;
address issuer;
}
Package[] private package;
uint256 private packageSize;
uint256 private sigmaRatio;
function LuckyPackage() public {
owner = msg.sender;
admins[owner] = true;
sigmaRatio = 0;
}
/* Modifiers */
modifier onlyOwner() {
require(owner == msg.sender);
_;
}
modifier onlyAdmins() {
require(admins[msg.sender]);
_;
}
/* Owner */
function setOwner (address _owner) onlyOwner() public {
owner = _owner;
}
function addAdmin (address _admin) onlyOwner() public {
admins[_admin] = true;
}
function removeAdmin (address _admin) onlyOwner() public {
delete admins[_admin];
}
/* Withdraw */
/*
NOTICE: These functions withdraw the developer's cut which is left
in the contract by `buy`. User funds are immediately sent to the old
owner in `buy`, no user funds are left in the contract.
*/
function withdrawAll () onlyAdmins() public {
msg.sender.transfer(address(this).balance);
}
function withdrawAmount (uint256 _amount) onlyAdmins() public {
msg.sender.transfer(_amount);
}
/* ERC721 */
function name() public view returns (string _name) {
return "luckyDraw";
}
function symbol() public view returns (string _symbol) {
return "LCY";
}
function totalSupply() public view returns (uint256 _totalSupply) {
return tokenSize;
}
function balanceOf (address _owner) public view returns (uint256 _balance) {
uint256 counter = 0;
for (uint256 i = 0; i < tokenSize; i++) {
if (ownerOf(i) == _owner) {
counter++;
}
}
return counter;
}
function ownerOf (uint256 _tokenId) public view returns (address _owner) {
return ownerOfToken[_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 < tokenSize; i++) {
if (ownerOf(i) == _owner) {
Tokens[TokenCounter] = i;
TokenCounter += 1;
}
}
return Tokens;
}
function approvedFor(uint256 _tokenId) public view returns (address _approved) {
return approvedOfToken[_tokenId];
}
function approve(address _to, uint256 _tokenId) public {
require(msg.sender != _to);
require(ownerOf(_tokenId) == msg.sender);
if (_to == 0) {
if (approvedOfToken[_tokenId] != 0) {
delete approvedOfToken[_tokenId];
emit Approval(msg.sender, 0, _tokenId);
}
} else {
approvedOfToken[_tokenId] = _to;
emit 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(ownerOf(_tokenId) == _from);
require(_to != address(0));
require(_to != address(this));
ownerOfToken[_tokenId] = _to;
approvedOfToken[_tokenId] = 0;
emit Transfer(_from, _to, _tokenId);
}
/* Read */
function isAdmin (address _admin) public view returns (bool _isAdmin) {
return admins[_admin];
}
function allOf (uint256 _tokenId) external view returns (address _owner) {
return (ownerOf(_tokenId));
}
/* Read */
function getAllPackage() public view returns (uint256[] _id, uint256[] _ratio, address[] _issuer) {
uint256[] memory ID = new uint[](packageSize);
uint256[] memory RATIO = new uint[](packageSize);
address[] memory ISSUER = new address[](packageSize);
for (uint i = 0; i < packageSize; i++) {
ID[i] = package[i].tokenId;
RATIO[i] = package[i].ratio;
ISSUER[i] = package[i].issuer;
}
return (ID, RATIO, ISSUER);
}
/* Util */
function isContract(address addr) internal view returns (bool) {
uint size;
assembly { size := extcodesize(addr) } // solium-disable-line
return size > 0;
}
function putIntoPackage(uint256 _tokenId, uint256 _ratio, address _issuer) onlyAdmins() public {
Issuer issuer = Issuer(_issuer);
require(issuer.ownerOf(_tokenId) == msg.sender);
issuer.transferFrom(msg.sender, address(this), _tokenId);
if (packageSize >= package.length) {
package.push(Package(_tokenId, _ratio, _issuer));
} else {
package[packageSize].tokenId = _tokenId;
package[packageSize].ratio = _ratio;
package[packageSize].issuer = _issuer;
}
packageSize += 1;
sigmaRatio += _ratio;
}
function rollDice(uint256 _tokenId) public {
require(msg.sender == ownerOfToken[_tokenId]);
require(packageSize > 0);
/* recycle the token. */
_transfer(msg.sender, owner, _tokenId);
/* get a random number. */
uint256 result = uint(keccak256(block.timestamp + block.difficulty)); // assume result is the random number
result %= sigmaRatio;
uint256 rt;
for (uint256 i = 0; i < packageSize; i++) {
if (result >= package[i].ratio) {
result -= package[i].ratio;
} else {
rt = i;
break;
}
}
/* transfer */
Issuer issuer = Issuer(package[rt].issuer);
issuer.transfer(msg.sender, package[rt].tokenId);
/* remove */
sigmaRatio -= package[rt].ratio;
package[rt] = package[packageSize-1];
packageSize -= 1;
emit RollDice(msg.sender, package[rt].issuer, package[rt].tokenId);
}
/* Issue */
function issueToken(uint256 _count) onlyAdmins() public {
uint256 l = tokenSize;
uint256 r = tokenSize + _count;
for (uint256 i = l; i < r; i++) {
ownerOfToken[i] = msg.sender;
}
tokenSize += _count;
}
function issueTokenAndTransfer(uint256 _count, address to) onlyAdmins() public {
uint256 l = tokenSize;
uint256 r = tokenSize + _count;
for (uint256 i = l; i < r; i++) {
ownerOfToken[i] = to;
}
tokenSize += _count;
}
function issueTokenAndApprove(uint256 _count, address to) onlyAdmins() public {
uint256 l = tokenSize;
uint256 r = tokenSize + _count;
for (uint256 i = l; i < r; i++) {
ownerOfToken[i] = msg.sender;
approve(to, i);
}
tokenSize += _count;
}
}
interface Issuer {
function transferFrom(address _from, address _to, uint256 _tokenId) external;
function transfer(address _to, uint256 _tokenId) external;
function ownerOf (uint256 _tokenId) external view returns (address _owner);
}
{
"compilationTarget": {
"LuckyPackage.sol": "LuckyPackage"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"withdrawAmount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"_name","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_admin","type":"address"}],"name":"removeAdmin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"_totalSupply","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_count","type":"uint256"},{"name":"to","type":"address"}],"name":"issueTokenAndApprove","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_admin","type":"address"}],"name":"isAdmin","outputs":[{"name":"_isAdmin","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"approvedFor","outputs":[{"name":"_approved","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"allOf","outputs":[{"name":"_owner","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"tokensOf","outputs":[{"name":"_tokenIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"name":"_owner","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAllPackage","outputs":[{"name":"_id","type":"uint256[]"},{"name":"_ratio","type":"uint256[]"},{"name":"_issuer","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_admin","type":"address"}],"name":"addAdmin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"_balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_count","type":"uint256"},{"name":"to","type":"address"}],"name":"issueTokenAndTransfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"withdrawAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"_symbol","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"rollDice","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_count","type":"uint256"}],"name":"issueToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenId","type":"uint256"},{"name":"_ratio","type":"uint256"},{"name":"_issuer","type":"address"}],"name":"putIntoPackage","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_tokenId","type":"uint256"},{"indexed":true,"name":"_owner","type":"address"},{"indexed":false,"name":"_price","type":"uint256"}],"name":"Bought","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_tokenId","type":"uint256"},{"indexed":true,"name":"_owner","type":"address"},{"indexed":false,"name":"_price","type":"uint256"}],"name":"Sold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_approved","type":"address"},{"indexed":false,"name":"_tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"playerAddr","type":"address"},{"indexed":true,"name":"prizeIssuer","type":"address"},{"indexed":false,"name":"prizeId","type":"uint256"}],"name":"RollDice","type":"event"}]