/**
*Submitted for verification at Etherscan.io on 2018-09-02
*/
pragma solidity ^0.4.24;
contract ERC721Basic {
event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
function balanceOf(address _owner) public view returns (uint256 _balance);
function ownerOf(uint256 _tokenId) public view returns (address _owner);
function exists(uint256 _tokenId) public view returns (bool _exists);
function approve(address _to, uint256 _tokenId) public;
function getApproved(uint256 _tokenId) public view returns (address _operator);
function setApprovalForAll(address _operator, bool _approved) public;
function isApprovedForAll(address _owner, address _operator) public view returns (bool);
function transferFrom(address _from, address _to, uint256 _tokenId) public;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) public;
// function safeTransferFrom(
// address _from,
// address _to,
// uint256 _tokenId,
// bytes _data
// )
// public;
}
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Enumerable is ERC721Basic {
function totalSupply() public view returns (uint256);
function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256 _tokenId);
function tokenByIndex(uint256 _index) public view returns (uint256);
}
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Metadata is ERC721Basic {
function name() public view returns (string _name);
function symbol() public view returns (string _symbol);
function tokenURI(uint256 _tokenId) public view returns (string);
}
/**
* @title ERC-721 Non-Fungible Token Standard, full implementation interface
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721 is ERC721Basic, ERC721Enumerable, ERC721Metadata {
}
contract ToonInterface is ERC721 {
function isToonInterface() external pure returns (bool);
/**
* @notice Returns an address of the toon author. 0x0 if
* the toon has been created by us.
*/
function authorAddress() external view returns (address);
/**
* @notice Returns maximum supply. In other words there will
* be never more toons that that number. It has to
* be constant.
* If there is no limit function returns 0.
*/
function maxSupply() external view returns (uint256);
function getToonInfo(uint _id) external view returns (
uint genes,
uint birthTime,
address owner
);
}
contract Ownable {
address public owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
contract Pausable is Ownable {
event Pause();
event Unpause();
bool public paused = false;
/**
* @dev modifier to allow actions only when the contract IS paused
*/
modifier whenNotPaused() {
require(!paused);
_;
}
/**
* @dev modifier to allow actions only when the contract IS NOT paused
*/
modifier whenPaused {
require(paused);
_;
}
/**
* @dev called by the owner to pause, triggers stopped state
*/
function pause() public onlyOwner whenNotPaused returns (bool) {
paused = true;
emit Pause();
return true;
}
/**
* @dev called by the owner to unpause, returns to normal state
*/
function unpause() public onlyOwner whenPaused returns (bool) {
paused = false;
emit Unpause();
return true;
}
}
contract Withdrawable {
mapping(address => uint) private pendingWithdrawals;
event Withdrawal(address indexed receiver, uint amount);
event BalanceChanged(address indexed _address, uint oldBalance, uint newBalance);
/**
* Returns amount of wei that given address is able to withdraw.
*/
function getPendingWithdrawal(address _address) public view returns (uint) {
return pendingWithdrawals[_address];
}
/**
* Add pending withdrawal for an address.
*/
function addPendingWithdrawal(address _address, uint _amount) internal {
require(_address != 0x0);
uint oldBalance = pendingWithdrawals[_address];
pendingWithdrawals[_address] += _amount;
emit BalanceChanged(_address, oldBalance, oldBalance + _amount);
}
/**
* Withdraws all pending withdrawals.
*/
function withdraw() external {
uint amount = getPendingWithdrawal(msg.sender);
require(amount > 0);
pendingWithdrawals[msg.sender] = 0;
msg.sender.transfer(amount);
emit Withdrawal(msg.sender, amount);
emit BalanceChanged(msg.sender, amount, 0);
}
}
contract ClockAuctionBase is Withdrawable, Pausable {
// Represents an auction on an NFT
struct Auction {
// Address of a contract
address _contract;
// Current owner of NFT
address seller;
// Price (in wei) at beginning of auction
uint128 startingPrice;
// Price (in wei) at end of auction
uint128 endingPrice;
// Duration (in seconds) of auction
uint64 duration;
// Time when auction started
// NOTE: 0 if this auction has been concluded
uint64 startedAt;
}
// Reference to contract tracking NFT ownership
ToonInterface[] public toonContracts;
mapping(address => uint256) addressToIndex;
// Cut owner takes on each auction, measured in basis points (1/100 of a percent).
// Values 0-10,000 map to 0%-100%
uint256 public ownerCut;
// Values 0-10,000 map to 0%-100%
// Author's share from the owner cut.
uint256 public authorShare;
// Map from token ID to their corresponding auction.
// mapping(uint256 => Auction) tokenIdToAuction;
mapping(address => mapping(uint256 => Auction)) tokenToAuction;
event AuctionCreated(address indexed _contract, uint256 indexed tokenId,
uint256 startingPrice, uint256 endingPrice, uint256 duration);
event AuctionSuccessful(address indexed _contract, uint256 indexed tokenId,
uint256 totalPrice, address indexed winner);
event AuctionCancelled(address indexed _contract, uint256 indexed tokenId);
/**
* @notice Adds a new toon contract.
*/
function addToonContract(address _toonContractAddress) external onlyOwner {
ToonInterface _interface = ToonInterface(_toonContractAddress);
require(_interface.isToonInterface());
uint _index = toonContracts.push(_interface) - 1;
addressToIndex[_toonContractAddress] = _index;
}
/// @dev Returns true if the claimant owns the token.
/// @param _contract - address of a toon contract
/// @param _claimant - Address claiming to own the token.
/// @param _tokenId - ID of token whose ownership to verify.
function _owns(address _contract, address _claimant, uint256 _tokenId)
internal
view
returns (bool) {
ToonInterface _interface = _interfaceByAddress(_contract);
address _owner = _interface.ownerOf(_tokenId);
return (_owner == _claimant);
}
/// @dev Escrows the NFT, assigning ownership to this contract.
/// Throws if the escrow fails.
/// @param _owner - Current owner address of token to escrow.
/// @param _tokenId - ID of token whose approval to verify.
function _escrow(address _contract, address _owner, uint256 _tokenId) internal {
ToonInterface _interface = _interfaceByAddress(_contract);
// it will throw if transfer fails
_interface.transferFrom(_owner, this, _tokenId);
}
/// @dev Transfers an NFT owned by this contract to another address.
/// Returns true if the transfer succeeds.
/// @param _receiver - Address to transfer NFT to.
/// @param _tokenId - ID of token to transfer.
function _transfer(address _contract, address _receiver, uint256 _tokenId) internal {
ToonInterface _interface = _interfaceByAddress(_contract);
// it will throw if transfer fails
_interface.transferFrom(this, _receiver, _tokenId);
}
/// @dev Adds an auction to the list of open auctions. Also fires the
/// AuctionCreated event.
/// @param _tokenId The ID of the token to be put on auction.
/// @param _auction Auction to add.
function _addAuction(address _contract, uint256 _tokenId, Auction _auction) internal {
// Require that all auctions have a duration of
// at least one minute. (Keeps our math from getting hairy!)
require(_auction.duration >= 1 minutes);
_isAddressSupportedContract(_contract);
tokenToAuction[_contract][_tokenId] = _auction;
emit AuctionCreated(
_contract,
uint256(_tokenId),
uint256(_auction.startingPrice),
uint256(_auction.endingPrice),
uint256(_auction.duration)
);
}
/// @dev Cancels an auction unconditionally.
function _cancelAuction(address _contract, uint256 _tokenId, address _seller) internal {
_removeAuction(_contract, _tokenId);
_transfer(_contract, _seller, _tokenId);
emit AuctionCancelled(_contract, _tokenId);
}
/// @dev Computes the price and transfers winnings.
/// Does NOT transfer ownership of token.
function _bid(address _contract, uint256 _tokenId, uint256 _bidAmount)
internal
returns (uint256)
{
// Get a reference to the auction struct
Auction storage auction = tokenToAuction[_contract][_tokenId];
ToonInterface _interface = _interfaceByAddress(auction._contract);
// Explicitly check that this auction is currently live.
// (Because of how Ethereum mappings work, we can't just count
// on the lookup above failing. An invalid _tokenId will just
// return an auction object that is all zeros.)
require(_isOnAuction(auction));
// Check that the bid is greater than or equal to the current price
uint256 price = _currentPrice(auction);
require(_bidAmount >= price);
// Grab a reference to the seller before the auction struct
// gets deleted.
address seller = auction.seller;
// The bid is good! Remove the auction before sending the fees
// to the sender so we can't have a reentrancy attack.
_removeAuction(_contract, _tokenId);
// Transfer proceeds to seller (if there are any!)
if (price > 0) {
// Calculate the auctioneer's cut.
// (NOTE: _computeCut() is guaranteed to return a
// value <= price, so this subtraction can't go negative.)
uint256 auctioneerCut;
uint256 authorCut;
uint256 sellerProceeds;
(auctioneerCut, authorCut, sellerProceeds) = _computeCut(_interface, price);
if (authorCut > 0) {
address authorAddress = _interface.authorAddress();
addPendingWithdrawal(authorAddress, authorCut);
}
addPendingWithdrawal(owner, auctioneerCut);
// NOTE: Doing a transfer() in the middle of a complex
// method like this is generally discouraged because of
// reentrancy attacks and DoS attacks if the seller is
// a contract with an invalid fallback function. We explicitly
// guard against reentrancy attacks by removing the auction
// before calling transfer(), and the only thing the seller
// can DoS is the sale of their own asset! (And if it's an
// accident, they can call cancelAuction(). )
seller.transfer(sellerProceeds);
}
// Calculate any excess funds included with the bid. If the excess
// is anything worth worrying about, transfer it back to bidder.
// NOTE: We checked above that the bid amount is greater than or
// equal to the price so this cannot underflow.
uint256 bidExcess = _bidAmount - price;
// Return the funds. Similar to the previous transfer, this is
// not susceptible to a re-entry attack because the auction is
// removed before any transfers occur.
msg.sender.transfer(bidExcess);
// Tell the world!
emit AuctionSuccessful(_contract, _tokenId, price, msg.sender);
return price;
}
/// @dev Removes an auction from the list of open auctions.
/// @param _tokenId - ID of NFT on auction.
function _removeAuction(address _contract, uint256 _tokenId) internal {
delete tokenToAuction[_contract][_tokenId];
}
/// @dev Returns true if the NFT is on auction.
/// @param _auction - Auction to check.
function _isOnAuction(Auction storage _auction) internal view returns (bool) {
return (_auction.startedAt > 0);
}
/// @dev Returns current price of an NFT on auction. Broken into two
/// functions (this one, that computes the duration from the auction
/// structure, and the other that does the price computation) so we
/// can easily test that the price computation works correctly.
function _currentPrice(Auction storage _auction)
internal
view
returns (uint256)
{
uint256 secondsPassed = 0;
// A bit of insurance against negative values (or wraparound).
// Probably not necessary (since Ethereum guarnatees that the
// now variable doesn't ever go backwards).
if (now > _auction.startedAt) {
secondsPassed = now - _auction.startedAt;
}
return _computeCurrentPrice(
_auction.startingPrice,
_auction.endingPrice,
_auction.duration,
secondsPassed
);
}
/// @dev Computes the current price of an auction. Factored out
/// from _currentPrice so we can run extensive unit tests.
/// When testing, make this function public and turn on
/// `Current price computation` test suite.
function _computeCurrentPrice(
uint256 _startingPrice,
uint256 _endingPrice,
uint256 _duration,
uint256 _secondsPassed
)
internal
pure
returns (uint256)
{
// NOTE: We don't use SafeMath (or similar) in this function because
// all of our public functions carefully cap the maximum values for
// time (at 64-bits) and currency (at 128-bits). _duration is
// also known to be non-zero (see the require() statement in
// _addAuction())
if (_secondsPassed >= _duration) {
// We've reached the end of the dynamic pricing portion
// of the auction, just return the end price.
return _endingPrice;
} else {
// Starting price can be higher than ending price (and often is!), so
// this delta can be negative.
int256 totalPriceChange = int256(_endingPrice) - int256(_startingPrice);
// This multiplication can't overflow, _secondsPassed will easily fit within
// 64-bits, and totalPriceChange will easily fit within 128-bits, their product
// will always fit within 256-bits.
int256 currentPriceChange = totalPriceChange * int256(_secondsPassed) / int256(_duration);
// currentPriceChange can be negative, but if so, will have a magnitude
// less that _startingPrice. Thus, this result will always end up positive.
int256 currentPrice = int256(_startingPrice) + currentPriceChange;
return uint256(currentPrice);
}
}
/// @dev Computes owner's cut of a sale.
/// @param _price - Sale price of NFT.
function _computeCut(ToonInterface _interface, uint256 _price) internal view returns (
uint256 ownerCutValue,
uint256 authorCutValue,
uint256 sellerProceeds
) {
// NOTE: We don't use SafeMath (or similar) in this function because
// all of our entry functions carefully cap the maximum values for
// currency (at 128-bits), and ownerCut <= 10000 (see the require()
// statement in the ClockAuction constructor). The result of this
// function is always guaranteed to be <= _price.
uint256 _totalCut = _price * ownerCut / 10000;
uint256 _authorCut = 0;
uint256 _ownerCut = 0;
if (_interface.authorAddress() != 0x0) {
_authorCut = _totalCut * authorShare / 10000;
}
_ownerCut = _totalCut - _authorCut;
uint256 _sellerProfit = _price - _ownerCut - _authorCut;
require(_sellerProfit + _ownerCut + _authorCut == _price);
return (_ownerCut, _authorCut, _sellerProfit);
}
function _interfaceByAddress(address _address) internal view returns (ToonInterface) {
uint _index = addressToIndex[_address];
ToonInterface _interface = toonContracts[_index];
require(_address == address(_interface));
return _interface;
}
function _isAddressSupportedContract(address _address) internal view returns (bool) {
uint _index = addressToIndex[_address];
ToonInterface _interface = toonContracts[_index];
return _address == address(_interface);
}
}
contract ClockAuction is ClockAuctionBase {
/// @dev The ERC-165 interface signature for ERC-721.
/// Ref: https://github.com/ethereum/EIPs/issues/165
/// Ref: https://github.com/ethereum/EIPs/issues/721
bytes4 constant InterfaceSignature_ERC721 = bytes4(0x9a20483d);
bool public isSaleClockAuction = true;
/// @dev Constructor creates a reference to the NFT ownership contract
/// and verifies the owner cut is in the valid range.
/// @param _ownerCut - percent cut the owner takes on each auction, must be
/// between 0-10,000.
/// @param _authorShare - percent share of the author of the toon.
/// Calculated from the ownerCut
constructor(uint256 _ownerCut, uint256 _authorShare) public {
require(_ownerCut <= 10000);
require(_authorShare <= 10000);
ownerCut = _ownerCut;
authorShare = _authorShare;
}
/// @dev Creates and begins a new auction.
/// @param _tokenId - ID of token to auction, sender must be owner.
/// @param _startingPrice - Price of item (in wei) at beginning of auction.
/// @param _endingPrice - Price of item (in wei) at end of auction.
/// @param _duration - Length of time to move between starting
/// price and ending price (in seconds).
/// @param _seller - Seller, if not the message sender
function createAuction(
address _contract,
uint256 _tokenId,
uint256 _startingPrice,
uint256 _endingPrice,
uint256 _duration,
address _seller
)
external
whenNotPaused
{
require(_isAddressSupportedContract(_contract));
// Sanity check that no inputs overflow how many bits we've allocated
// to store them in the auction struct.
require(_startingPrice == uint256(uint128(_startingPrice)));
require(_endingPrice == uint256(uint128(_endingPrice)));
require(_duration == uint256(uint64(_duration)));
_escrow(_contract, _seller, _tokenId);
Auction memory auction = Auction(
_contract,
_seller,
uint128(_startingPrice),
uint128(_endingPrice),
uint64(_duration),
uint64(now)
);
_addAuction(_contract, _tokenId, auction);
}
/// @dev Bids on an open auction, completing the auction and transferring
/// ownership of the NFT if enough Ether is supplied.
/// @param _tokenId - ID of token to bid on.
function bid(address _contract, uint256 _tokenId)
external
payable
whenNotPaused
{
// _bid will throw if the bid or funds transfer fails
_bid(_contract, _tokenId, msg.value);
_transfer(_contract, msg.sender, _tokenId);
}
/// @dev Cancels an auction that hasn't been won yet.
/// Returns the NFT to original owner.
/// @notice This is a state-modifying function that can
/// be called while the contract is paused.
/// @param _tokenId - ID of token on auction
function cancelAuction(address _contract, uint256 _tokenId)
external
{
Auction storage auction = tokenToAuction[_contract][_tokenId];
require(_isOnAuction(auction));
address seller = auction.seller;
require(msg.sender == seller);
_cancelAuction(_contract, _tokenId, seller);
}
/// @dev Cancels an auction when the contract is paused.
/// Only the owner may do this, and NFTs are returned to
/// the seller. This should only be used in emergencies.
/// @param _tokenId - ID of the NFT on auction to cancel.
function cancelAuctionWhenPaused(address _contract, uint256 _tokenId)
whenPaused
onlyOwner
external
{
Auction storage auction = tokenToAuction[_contract][_tokenId];
require(_isOnAuction(auction));
_cancelAuction(_contract, _tokenId, auction.seller);
}
/// @dev Returns auction info for an NFT on auction.
/// @param _tokenId - ID of NFT on auction.
function getAuction(address _contract, uint256 _tokenId)
external
view
returns
(
address seller,
uint256 startingPrice,
uint256 endingPrice,
uint256 duration,
uint256 startedAt,
uint256 currentPrice
) {
Auction storage auction = tokenToAuction[_contract][_tokenId];
if (!_isOnAuction(auction)) {
return (0x0, 0, 0, 0, 0, 0);
}
return (
auction.seller,
auction.startingPrice,
auction.endingPrice,
auction.duration,
auction.startedAt,
getCurrentPrice(_contract, _tokenId)
);
}
/// @dev Returns the current price of an auction.
/// @param _tokenId - ID of the token price we are checking.
function getCurrentPrice(address _contract, uint256 _tokenId)
public
view
returns (uint256)
{
Auction storage auction = tokenToAuction[_contract][_tokenId];
require(_isOnAuction(auction));
return _currentPrice(auction);
}
}
contract AccessControl is Ownable {
// This facet controls access control for CryptoKitties. There are four roles managed here:
//
// - The CEO: The CEO can reassign other roles and change the addresses of our dependent smart
// contracts. It is also the only role that can unpause the smart contract. It is initially
// set to the address that created the smart contract in the KittyCore constructor.
//
// - The CFO: The CFO can withdraw funds from KittyCore and its auction contracts.
//
// - The COO: The COO can release gen0 kitties to auction, and mint promo cats.
//
// It should be noted that these roles are distinct without overlap in their access abilities, the
// abilities listed for each role above are exhaustive. In particular, while the CEO can assign any
// address to any role, the CEO address itself doesn't have the ability to act in those roles. This
// restriction is intentional so that we aren't tempted to use the CEO address frequently out of
// convenience. The less we use an address, the less likely it is that we somehow compromise the
// account.
// The addresses of the accounts (or contracts) that can execute actions within each roles.
address public ceoAddress;
address public cfoAddress;
address public cooAddress;
// @dev Keeps track whether the contract is paused. When that is true, most actions are blocked
bool public paused = false;
/// @dev Access modifier for CEO-only functionality
modifier onlyCEO() {
require(msg.sender == ceoAddress);
_;
}
/// @dev Access modifier for CFO-only functionality
modifier onlyCFO() {
require(msg.sender == cfoAddress);
_;
}
/// @dev Access modifier for COO-only functionality
modifier onlyCOO() {
require(msg.sender == cooAddress);
_;
}
modifier onlyCLevel() {
require(
msg.sender == cooAddress ||
msg.sender == ceoAddress ||
msg.sender == cfoAddress
);
_;
}
constructor() public {
ceoAddress = owner;
cfoAddress = owner;
cooAddress = owner;
}
/// @dev Assigns a new address to act as the CEO. Only available to the current CEO.
/// @param _newCEO The address of the new CEO
function setCEO(address _newCEO) external onlyCEO {
require(_newCEO != address(0));
ceoAddress = _newCEO;
}
/// @dev Assigns a new address to act as the CFO. Only available to the current CEO.
/// @param _newCFO The address of the new CFO
function setCFO(address _newCFO) external onlyCEO {
require(_newCFO != address(0));
cfoAddress = _newCFO;
}
/// @dev Assigns a new address to act as the COO. Only available to the current CEO.
/// @param _newCOO The address of the new COO
function setCOO(address _newCOO) external onlyCEO {
require(_newCOO != address(0));
cooAddress = _newCOO;
}
/*** Pausable functionality adapted from OpenZeppelin ***/
/// @dev Modifier to allow actions only when the contract IS NOT paused
modifier whenNotPaused() {
require(!paused);
_;
}
/// @dev Modifier to allow actions only when the contract IS paused
modifier whenPaused {
require(paused);
_;
}
/// @dev Called by any "C-level" role to pause the contract. Used only when
/// a bug or exploit is detected and we need to limit damage.
function pause() external onlyCLevel whenNotPaused {
paused = true;
}
/// @dev Unpauses the smart contract. Can only be called by the CEO, since
/// one reason we may pause the contract is when CFO or COO accounts are
/// compromised.
/// @notice This is public rather than external so it can be called by
/// derived contracts.
function unpause() public onlyCEO whenPaused {
// can't unpause if contract was upgraded
paused = false;
}
}
interface ERC165 {
/// @notice Query if a contract implements an interface
/// @param interfaceID The interface identifier, as specified in ERC-165
/// @dev Interface identification is specified in ERC-165. This function
/// uses less than 30,000 gas.
/// @return `true` if the contract implements `interfaceID` and
/// `interfaceID` is not 0xffffffff, `false` otherwise
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
contract ERC165MappingImplementation is ERC165 {
/// @dev You must not set element 0xffffffff to true
mapping(bytes4 => bool) internal supportedInterfaces;
constructor() internal {
supportedInterfaces[this.supportsInterface.selector] = true;
}
function supportsInterface(bytes4 interfaceID) external view returns (bool) {
return supportedInterfaces[interfaceID];
}
}
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) {
return 0;
}
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 a / b;
}
/**
* @dev Subtracts 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 c) {
c = a + b;
assert(c >= a);
return c;
}
function toString(uint i) internal pure returns (string){
if (i == 0) return "0";
uint j = i;
uint length;
while (j != 0){
length++;
j /= 10;
}
bytes memory bstr = new bytes(length);
uint k = length - 1;
while (i != 0){
bstr[k--] = byte(48 + i % 10);
i /= 10;
}
return string(bstr);
}
}
library AddressUtils {
/**
* Returns whether the target address is a contract
* @dev This function will return false if invoked during the constructor of a contract,
* as the code is not actually created until after the constructor finishes.
* @param addr address to check
* @return whether the target address is a contract
*/
function isContract(address addr) internal view returns (bool) {
uint256 size;
// XXX Currently there is no better way to check if there is a contract in an address
// than to check the size of the code at that address.
// See https://ethereum.stackexchange.com/a/14016/36603
// for more details about how this works.
// TODO Check this again before the Serenity release, because all addresses will be
// contracts then.
assembly { size := extcodesize(addr) } // solium-disable-line security/no-inline-assembly
return size > 0;
}
}
contract ERC721Receiver {
/**
* @dev Magic value to be returned upon successful reception of an NFT
* Equals to `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`,
* which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`
*/
bytes4 constant ERC721_RECEIVED = 0xf0b9e5ba;
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a `safetransfer`. This function MAY throw to revert and reject the
* transfer. This function MUST use 50,000 gas or less. Return of other
* than the magic value MUST result in the transaction being reverted.
* Note: the contract address is always the message sender.
* @param _from The sending address
* @param _tokenId The NFT identifier which is being transfered
* @param _data Additional data with no specified format
* @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
*/
function onERC721Received(address _from, uint256 _tokenId, bytes _data) public returns(bytes4);
}
contract ERC721BasicToken is ERC721Basic, ERC165MappingImplementation {
using SafeMath for uint256;
using AddressUtils for address;
// Equals to `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
// which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`
bytes4 constant ERC721_RECEIVED = 0xf0b9e5ba;
// Mapping from token ID to owner
mapping(uint256 => address) internal tokenOwner;
// Mapping from token ID to approved address
mapping(uint256 => address) internal tokenApprovals;
// Mapping from owner to number of owned token
mapping(address => uint256) internal ownedTokensCount;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) internal operatorApprovals;
/**
* @dev Guarantees msg.sender is owner of the given token
* @param _tokenId uint256 ID of the token to validate its ownership belongs to msg.sender
*/
modifier onlyOwnerOf(uint256 _tokenId) {
require(ownerOf(_tokenId) == msg.sender);
_;
}
constructor() public {
supportedInterfaces[0x80ac58cd] = true;
}
/**
* @dev Checks msg.sender can transfer a token, by being owner, approved, or operator
* @param _tokenId uint256 ID of the token to validate
*/
modifier canTransfer(uint256 _tokenId) {
require(isApprovedOrOwner(msg.sender, _tokenId));
_;
}
/**
* @dev Gets the balance of the specified address
* @param _owner address to query the balance of
* @return uint256 representing the amount owned by the passed address
*/
function balanceOf(address _owner) public view returns (uint256) {
require(_owner != address(0));
return ownedTokensCount[_owner];
}
/**
* @dev Gets the owner of the specified token ID
* @param _tokenId uint256 ID of the token to query the owner of
* @return owner address currently marked as the owner of the given token ID
*/
function ownerOf(uint256 _tokenId) public view returns (address) {
address owner = tokenOwner[_tokenId];
require(owner != address(0));
return owner;
}
/**
* @dev Returns whether the specified token exists
* @param _tokenId uint256 ID of the token to query the existence of
* @return whether the token exists
*/
function exists(uint256 _tokenId) public view returns (bool) {
address owner = tokenOwner[_tokenId];
return owner != address(0);
}
/**
* @dev Approves another address to transfer the given token ID
* @dev The zero address indicates there is no approved address.
* @dev There can only be one approved address per token at a given time.
* @dev Can only be called by the token owner or an approved operator.
* @param _to address to be approved for the given token ID
* @param _tokenId uint256 ID of the token to be approved
*/
function approve(address _to, uint256 _tokenId) public {
address owner = ownerOf(_tokenId);
require(_to != owner);
require(msg.sender == owner || isApprovedForAll(owner, msg.sender));
if (getApproved(_tokenId) != address(0) || _to != address(0)) {
tokenApprovals[_tokenId] = _to;
emit Approval(owner, _to, _tokenId);
}
}
/**
* @dev Gets the approved address for a token ID, or zero if no address set
* @param _tokenId uint256 ID of the token to query the approval of
* @return address currently approved for the given token ID
*/
function getApproved(uint256 _tokenId) public view returns (address) {
return tokenApprovals[_tokenId];
}
/**
* @dev Sets or unsets the approval of a given operator
* @dev An operator is allowed to transfer all tokens of the sender on their behalf
* @param _to operator address to set the approval
* @param _approved representing the status of the approval to be set
*/
function setApprovalForAll(address _to, bool _approved) public {
require(_to != msg.sender);
operatorApprovals[msg.sender][_to] = _approved;
emit ApprovalForAll(msg.sender, _to, _approved);
}
/**
* @dev Tells whether an operator is approved by a given owner
* @param _owner owner address which you want to query the approval of
* @param _operator operator address which you want to query the approval of
* @return bool whether the given operator is approved by the given owner
*/
function isApprovedForAll(address _owner, address _operator) public view returns (bool) {
return operatorApprovals[_owner][_operator];
}
/**
* @dev Transfers the ownership of a given token ID to another address
* @dev Usage of this method is discouraged, use `safeTransferFrom` whenever possible
* @dev Requires the msg sender to be the owner, approved, or operator
* @param _from current owner of the token
* @param _to address to receive the ownership of the given token ID
* @param _tokenId uint256 ID of the token to be transferred
*/
function transferFrom(address _from, address _to, uint256 _tokenId) public canTransfer(_tokenId) {
require(_from != address(0));
require(_to != address(0));
clearApproval(_from, _tokenId);
removeTokenFrom(_from, _tokenId);
addTokenTo(_to, _tokenId);
emit Transfer(_from, _to, _tokenId);
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* @dev If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
* @dev Requires the msg sender to be the owner, approved, or operator
* @param _from current owner of the token
* @param _to address to receive the ownership of the given token ID
* @param _tokenId uint256 ID of the token to be transferred
*/
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId
)
public
canTransfer(_tokenId)
{
// solium-disable-next-line arg-overflow
safeTransferFrom(_from, _to, _tokenId, "");
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* @dev If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
* @dev Requires the msg sender to be the owner, approved, or operator
* @param _from current owner of the token
* @param _to address to receive the ownership of the given token ID
* @param _tokenId uint256 ID of the token to be transferred
* @param _data bytes data to send along with a safe transfer check
*/
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes _data
)
public
canTransfer(_tokenId)
{
transferFrom(_from, _to, _tokenId);
// solium-disable-next-line arg-overflow
require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data));
}
/**
* @dev Returns whether the given spender can transfer a given token ID
* @param _spender address of the spender to query
* @param _tokenId uint256 ID of the token to be transferred
* @return bool whether the msg.sender is approved for the given token ID,
* is an operator of the owner, or is the owner of the token
*/
function isApprovedOrOwner(address _spender, uint256 _tokenId) internal view returns (bool) {
address owner = ownerOf(_tokenId);
return _spender == owner || getApproved(_tokenId) == _spender || isApprovedForAll(owner, _spender);
}
/**
* @dev Internal function to mint a new token
* @dev Reverts if the given token ID already exists
* @param _to The address that will own the minted token
* @param _tokenId uint256 ID of the token to be minted by the msg.sender
*/
function _mint(address _to, uint256 _tokenId) internal {
require(_to != address(0));
addTokenTo(_to, _tokenId);
emit Transfer(address(0), _to, _tokenId);
}
/**
* @dev Internal function to clear current approval of a given token ID
* @dev Reverts if the given address is not indeed the owner of the token
* @param _owner owner of the token
* @param _tokenId uint256 ID of the token to be transferred
*/
function clearApproval(address _owner, uint256 _tokenId) internal {
require(ownerOf(_tokenId) == _owner);
if (tokenApprovals[_tokenId] != address(0)) {
tokenApprovals[_tokenId] = address(0);
emit Approval(_owner, address(0), _tokenId);
}
}
/**
* @dev Internal function to add a token ID to the list of a given address
* @param _to address representing the new owner of the given token ID
* @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function addTokenTo(address _to, uint256 _tokenId) internal {
require(tokenOwner[_tokenId] == address(0));
tokenOwner[_tokenId] = _to;
ownedTokensCount[_to] = ownedTokensCount[_to].add(1);
}
/**
* @dev Internal function to remove a token ID from the list of a given address
* @param _from address representing the previous owner of the given token ID
* @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function removeTokenFrom(address _from, uint256 _tokenId) internal {
require(ownerOf(_tokenId) == _from);
ownedTokensCount[_from] = ownedTokensCount[_from].sub(1);
tokenOwner[_tokenId] = address(0);
}
/**
* @dev Internal function to invoke `onERC721Received` on a target address
* @dev The call is not executed if the target address is not a contract
* @param _from address representing the previous owner of the given token ID
* @param _to target address that will receive the tokens
* @param _tokenId uint256 ID of the token to be transferred
* @param _data bytes optional data to send along with the call
* @return whether the call correctly returned the expected magic value
*/
function checkAndCallSafeTransfer(
address _from,
address _to,
uint256 _tokenId,
bytes _data
)
internal
returns (bool)
{
if (!_to.isContract()) {
return true;
}
bytes4 retval = ERC721Receiver(_to).onERC721Received(_from, _tokenId, _data);
return (retval == ERC721_RECEIVED);
}
}
contract ERC721Token is ERC721, ERC721BasicToken {
// Token name
string internal name_;
// Token symbol
string internal symbol_;
// Mapping from owner to list of owned token IDs
mapping(address => uint256[]) internal ownedTokens;
// Mapping from token ID to index of the owner tokens list
mapping(uint256 => uint256) internal ownedTokensIndex;
/**
* @dev Constructor function
*/
constructor(string _name, string _symbol) public {
supportedInterfaces[0x5b5e139f] = true; // ERC721Metadata
supportedInterfaces[0x780e9d63] = true; // ERC721Enumerable
name_ = _name;
symbol_ = _symbol;
}
/**
* @dev Gets the token name
* @return string representing the token name
*/
function name() public view returns (string) {
return name_;
}
/**
* @dev Gets the token symbol
* @return string representing the token symbol
*/
function symbol() public view returns (string) {
return symbol_;
}
/**
* @dev Returns an URI for a given token ID
* @dev Throws if the token ID does not exist. May return an empty string.
* @param _tokenId uint256 ID of the token to query
*/
function tokenURI(uint256 _tokenId) public view returns (string);
/**
* @dev Gets the token ID at a given index of the tokens list of the requested owner
* @param _owner address owning the tokens list to be accessed
* @param _index uint256 representing the index to be accessed of the requested tokens list
* @return uint256 token ID at the given index of the tokens list owned by the requested address
*/
function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256) {
require(_index < balanceOf(_owner));
return ownedTokens[_owner][_index];
}
/**
* @dev Gets the total amount of tokens stored by the contract
* @return uint256 representing the total amount of tokens
*/
function totalSupply() public view returns (uint256);
/**
* @dev Gets the token ID at a given index of all the tokens in this contract
* @dev Reverts if the index is greater or equal to the total number of tokens
* @param _index uint256 representing the index to be accessed of the tokens list
* @return uint256 token ID at the given index of the tokens list
*/
function tokenByIndex(uint256 _index) public view returns (uint256) {
require(_index < totalSupply());
//In our case id is an index and vice versa.
return _index;
}
/**
* @dev Internal function to add a token ID to the list of a given address
* @param _to address representing the new owner of the given token ID
* @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function addTokenTo(address _to, uint256 _tokenId) internal {
super.addTokenTo(_to, _tokenId);
uint256 length = ownedTokens[_to].length;
ownedTokens[_to].push(_tokenId);
ownedTokensIndex[_tokenId] = length;
}
/**
* @dev Internal function to remove a token ID from the list of a given address
* @param _from address representing the previous owner of the given token ID
* @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function removeTokenFrom(address _from, uint256 _tokenId) internal {
super.removeTokenFrom(_from, _tokenId);
uint256 tokenIndex = ownedTokensIndex[_tokenId];
uint256 lastTokenIndex = ownedTokens[_from].length.sub(1);
uint256 lastToken = ownedTokens[_from][lastTokenIndex];
ownedTokens[_from][tokenIndex] = lastToken;
ownedTokens[_from][lastTokenIndex] = 0;
// Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to
// be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping
// the lastToken to the first position, and then dropping the element placed in the last position of the list
ownedTokens[_from].length--;
ownedTokensIndex[_tokenId] = 0;
ownedTokensIndex[lastToken] = tokenIndex;
}
}
library StringUtils {
struct slice {
uint _len;
uint _ptr;
}
/*
* @dev Returns a slice containing the entire string.
* @param self The string to make a slice from.
* @return A newly allocated slice containing the entire string.
*/
function toSlice(string memory self) internal pure returns (slice memory) {
uint ptr;
assembly {
ptr := add(self, 0x20)
}
return slice(bytes(self).length, ptr);
}
/*
* @dev Returns a newly allocated string containing the concatenation of
* `self` and `other`.
* @param self The first slice to concatenate.
* @param other The second slice to concatenate.
* @return The concatenation of the two strings.
*/
function concat(slice memory self, slice memory other) internal pure returns (string memory) {
string memory ret = new string(self._len + other._len);
uint retptr;
assembly { retptr := add(ret, 32) }
memcpy(retptr, self._ptr, self._len);
memcpy(retptr + self._len, other._ptr, other._len);
return ret;
}
function memcpy(uint dest, uint src, uint len) private pure {
// Copy word-length chunks while possible
for(; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
// Copy remaining bytes
uint mask = 256 ** (32 - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
}
contract ToonBase is ERC721Token, AccessControl, ToonInterface {
using StringUtils for *;
using SafeMath for uint;
Toon[] private toons;
uint public maxSupply;
uint32 public maxPromoToons;
address public authorAddress;
string public endpoint = "https://mindhouse.io:3100/metadata/";
constructor(string _name, string _symbol, uint _maxSupply, uint32 _maxPromoToons, address _author)
public
ERC721Token(_name, _symbol) {
require(_maxPromoToons <= _maxSupply);
maxSupply = _maxSupply;
maxPromoToons = _maxPromoToons;
authorAddress = _author;
}
function maxSupply() external view returns (uint) {
return maxSupply;
}
/**
* @dev Gets the total amount of tokens stored by the contract
* @return uint256 representing the total amount of tokens
*/
function totalSupply() public view returns (uint256) {
return toons.length;
}
/**
* @dev Returns an URI for a given token ID
* @dev Throws if the token ID does not exist. May return an empty string.
* @param _tokenId uint256 ID of the token to query
*/
function tokenURI(uint256 _tokenId) public view returns (string) {
require(exists(_tokenId));
string memory slash = "/";
return endpoint.toSlice().concat(name_.toSlice()).toSlice().concat(slash.toSlice()).toSlice().concat(_tokenId.toString().toSlice());
}
function authorAddress() external view returns (address) {
return authorAddress;
}
function changeEndpoint(string newEndpoint) external onlyOwner {
endpoint = newEndpoint;
}
function isToonInterface() external pure returns (bool) {
return true;
}
function _getToon(uint _id) internal view returns (Toon){
require(_id <= totalSupply());
return toons[_id];
}
function _createToon(uint _genes, address _owner) internal {
require(totalSupply() < maxSupply);
Toon memory _toon = Toon(_genes, now);
uint id = toons.push(_toon) - 1;
_mint(_owner, id);
}
struct Toon {
uint256 genes;
uint256 birthTime;
}
}
library SafeMath32 {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint32 a, uint32 b) internal pure returns (uint32 c) {
if (a == 0) {
return 0;
}
c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint32 a, uint32 b) internal pure returns (uint32) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
// uint32 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return a / b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint32 a, uint32 b) internal pure returns (uint32) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint32 a, uint32 b) internal pure returns (uint32 c) {
c = a + b;
assert(c >= a);
return c;
}
}
contract ToonMinting is ToonBase {
using SafeMath32 for uint32;
uint32 public promoToonsMinted = 0;
constructor(string _name, string _symbol, uint _maxSupply, uint32 _maxPromoToons, address _author)
public
ToonBase(_name, _symbol, _maxSupply, _maxPromoToons, _author) {
}
function createPromoToon(uint _genes, address _owner) external onlyCOO {
require(promoToonsMinted < maxPromoToons);
address _toonOwner = _owner;
if (_toonOwner == 0x0) {
_toonOwner = cooAddress;
}
_createToon(_genes, _toonOwner);
promoToonsMinted = promoToonsMinted.add(1);
}
}
contract ToonAuction is ToonMinting {
ClockAuction public saleAuction;
constructor(string _name, string _symbol, uint _maxSupply, uint32 _maxPromoToons, address _author)
public
ToonMinting(_name, _symbol, _maxSupply, _maxPromoToons, _author) {
}
function setSaleAuctionAddress(address _address) external onlyCEO {
ClockAuction candidateContract = ClockAuction(_address);
require(candidateContract.isSaleClockAuction());
// Set the new contract address
saleAuction = candidateContract;
}
function createSaleAuction(
uint256 _toonId,
uint256 _startingPrice,
uint256 _endingPrice,
uint256 _duration
)
external
whenNotPaused
{
// Auction contract checks input sizes
// If toon is already on any auction, this will throw
// because it will be owned by the auction contract.
require(ownerOf(_toonId) == msg.sender);
approve(saleAuction, _toonId);
// Sale auction throws if inputs are invalid and clears
// transfer approval after escrowing the toon.
saleAuction.createAuction(
this,
_toonId,
_startingPrice,
_endingPrice,
_duration,
msg.sender
);
}
}
contract CryptoToon is ToonAuction {
constructor(string _name, string _symbol, uint _maxSupply, uint32 _maxPromoToons, address _author)
public
ToonAuction(_name, _symbol, _maxSupply, _maxPromoToons, _author) {
}
function getToonInfo(uint _id) external view returns (
uint genes,
uint birthTime,
address owner
) {
Toon memory _toon = _getToon(_id);
return (_toon.genes, _toon.birthTime, ownerOf(_id));
}
}
{
"compilationTarget": {
"CryptoToon.sol": "CryptoToon"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"constant":true,"inputs":[{"name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"authorAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cfoAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"name":"","type":"address"}],"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":true,"inputs":[],"name":"ceoAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_id","type":"uint256"}],"name":"getToonInfo","outputs":[{"name":"genes","type":"uint256"},{"name":"birthTime","type":"uint256"},{"name":"owner","type":"address"}],"payable":false,"stateMutability":"view","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":false,"inputs":[{"name":"_newCEO","type":"address"}],"name":"setCEO","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newCOO","type":"address"}],"name":"setCOO","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isToonInterface","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_toonId","type":"uint256"},{"name":"_startingPrice","type":"uint256"},{"name":"_endingPrice","type":"uint256"},{"name":"_duration","type":"uint256"}],"name":"createSaleAuction","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newCFO","type":"address"}],"name":"setCFO","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"exists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"endpoint","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"}],"name":"setSaleAuctionAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newEndpoint","type":"string"}],"name":"changeEndpoint","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_genes","type":"uint256"},{"name":"_owner","type":"address"}],"name":"createPromoToon","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"maxPromoToons","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cooAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"saleAuction","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"promoToonsMinted","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_maxSupply","type":"uint256"},{"name":"_maxPromoToons","type":"uint32"},{"name":"_author","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","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":"_owner","type":"address"},{"indexed":true,"name":"_operator","type":"address"},{"indexed":false,"name":"_approved","type":"bool"}],"name":"ApprovalForAll","type":"event"}]