ETH Price: $1,947.74 (+1.06%)

Transaction Decoder

Block:
7524088 at Apr-07-2019 11:50:58 PM +UTC
Transaction Fee:
0.000178627 ETH $0.35
Gas Used:
178,627 Gas / 1 Gwei

Emitted Events:

104 AxieCore.Approval( _owner=[Sender] 0xe800419e5c0b3d355cc7f2c5273e8f2a6b553558, _approved=0x00000000...000000000, _tokenId=20264 )
105 AxieCore.Transfer( _from=[Sender] 0xe800419e5c0b3d355cc7f2c5273e8f2a6b553558, _to=[Receiver] AxieSiringClockAuction, _tokenId=20264 )
106 AxieSiringClockAuction.AuctionCreated( _axieId=20264, _startingPrice=38000000000000000, _endingPrice=38000000000000000, _duration=86400, _seller=[Sender] 0xe800419e5c0b3d355cc7f2c5273e8f2a6b553558 )

Account State Difference:

  Address   Before After State Difference Code
(Ethpool 2)
291.361206727955488195 Eth291.361385354955488195 Eth0.000178627
0x60cE035D...98948973b
0xe800419E...a6B553558
0.109457316993452386 Eth
Nonce: 1525
0.109278689993452386 Eth
Nonce: 1526
0.000178627
0xF5b0A3eF...F3FFEcb8d

Execution Trace

AxieSiringClockAuction.createAuction( _axieId=20264, _startingPrice=38000000000000000, _endingPrice=38000000000000000, _duration=86400 )
  • AxieCore.ownerOf( _tokenId=20264 ) => ( 0xe800419E5c0b3d355cC7f2C5273E8f2a6B553558 )
  • Axie Infinity: Breeding Contract #2 (Deprecated).bcf7bd0b( )
    • 0x10e304a53351b272dc415ad049ad06565ebdfe34.893bb0bf( )
    • AxieCore.transferFrom( _from=0xe800419E5c0b3d355cC7f2C5273E8f2a6B553558, _to=0x60cE035Dc589C3fd185B224A7Ca03C598948973b, _tokenId=20264 )
      • 0xe8bd438d0383cf4d19641eaa4793eddc6cebeaf1.f7ebc39a( )
        • AxieCore.CALL( )
          File 1 of 2: AxieSiringClockAuction
          pragma solidity ^0.4.23;
          
          // File: contracts/breeding/AxieIncubatorInterface.sol
          
          interface AxieIncubatorInterface {
            function breedingFee() external view returns (uint256);
          
            function requireEnoughExpForBreeding(
              uint256 _axieId
            )
              external
              view;
          
            function breedAxies(
              uint256 _sireId,
              uint256 _matronId,
              uint256 _birthPlace
            )
              external
              payable
              returns (uint256 _axieId);
          }
          
          // File: contracts/erc/erc721/IERC721Base.sol
          
          /// @title ERC-721 Non-Fungible Token Standard
          /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
          ///  Note: the ERC-165 identifier for this interface is 0x6466353c
          interface IERC721Base /* is IERC165  */ {
            /// @dev This emits when ownership of any NFT changes by any mechanism.
            ///  This event emits when NFTs are created (`from` == 0) and destroyed
            ///  (`to` == 0). Exception: during contract creation, any number of NFTs
            ///  may be created and assigned without emitting Transfer. At the time of
            ///  any transfer, the approved address for that NFT (if any) is reset to none.
            event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
          
            /// @dev This emits when the approved address for an NFT is changed or
            ///  reaffirmed. The zero address indicates there is no approved address.
            ///  When a Transfer event emits, this also indicates that the approved
            ///  address for that NFT (if any) is reset to none.
            event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
          
            /// @dev This emits when an operator is enabled or disabled for an owner.
            ///  The operator can manage all NFTs of the owner.
            event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
          
            /// @notice Count all NFTs assigned to an owner
            /// @dev NFTs assigned to the zero address are considered invalid, and this
            ///  function throws for queries about the zero address.
            /// @param _owner An address for whom to query the balance
            /// @return The number of NFTs owned by `_owner`, possibly zero
            function balanceOf(address _owner) external view returns (uint256);
          
            /// @notice Find the owner of an NFT
            /// @param _tokenId The identifier for an NFT
            /// @dev NFTs assigned to zero address are considered invalid, and queries
            ///  about them do throw.
            /// @return The address of the owner of the NFT
            function ownerOf(uint256 _tokenId) external view returns (address);
          
            /// @notice Transfers the ownership of an NFT from one address to another address
            /// @dev Throws unless `msg.sender` is the current owner, an authorized
            ///  operator, or the approved address for this NFT. Throws if `_from` is
            ///  not the current owner. Throws if `_to` is the zero address. Throws if
            ///  `_tokenId` is not a valid NFT. When transfer is complete, this function
            ///  checks if `_to` is a smart contract (code size > 0). If so, it calls
            ///  `onERC721Received` on `_to` and throws if the return value is not
            ///  `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`.
            /// @param _from The current owner of the NFT
            /// @param _to The new owner
            /// @param _tokenId The NFT to transfer
            /// @param _data Additional data with no specified format, sent in call to `_to`
            // solium-disable-next-line arg-overflow
            function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes _data) external payable;
          
            /// @notice Transfers the ownership of an NFT from one address to another address
            /// @dev This works identically to the other function with an extra data parameter,
            ///  except this function just sets data to []
            /// @param _from The current owner of the NFT
            /// @param _to The new owner
            /// @param _tokenId The NFT to transfer
            function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
          
            /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
            ///  TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
            ///  THEY MAY BE PERMANENTLY LOST
            /// @dev Throws unless `msg.sender` is the current owner, an authorized
            ///  operator, or the approved address for this NFT. Throws if `_from` is
            ///  not the current owner. Throws if `_to` is the zero address. Throws if
            ///  `_tokenId` is not a valid NFT.
            /// @param _from The current owner of the NFT
            /// @param _to The new owner
            /// @param _tokenId The NFT to transfer
            function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
          
            /// @notice Set or reaffirm the approved address for an NFT
            /// @dev The zero address indicates there is no approved address.
            /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
            ///  operator of the current owner.
            /// @param _approved The new approved NFT controller
            /// @param _tokenId The NFT to approve
            function approve(address _approved, uint256 _tokenId) external payable;
          
            /// @notice Enable or disable approval for a third party ("operator") to manage
            ///  all your asset.
            /// @dev Emits the ApprovalForAll event
            /// @param _operator Address to add to the set of authorized operators.
            /// @param _approved True if the operators is approved, false to revoke approval
            function setApprovalForAll(address _operator, bool _approved) external;
          
            /// @notice Get the approved address for a single NFT
            /// @dev Throws if `_tokenId` is not a valid NFT
            /// @param _tokenId The NFT to find the approved address for
            /// @return The approved address for this NFT, or the zero address if there is none
            function getApproved(uint256 _tokenId) external view returns (address);
          
            /// @notice Query if an address is an authorized operator for another address
            /// @param _owner The address that owns the NFTs
            /// @param _operator The address that acts on behalf of the owner
            /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
            function isApprovedForAll(address _owner, address _operator) external view returns (bool);
          }
          
          // File: zeppelin/contracts/ownership/Ownable.sol
          
          /**
           * @title Ownable
           * @dev The Ownable contract has an owner address, and provides basic authorization control
           * functions, this simplifies the implementation of "user permissions".
           */
          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.
             */
            function Ownable() {
              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) onlyOwner public {
              require(newOwner != address(0));
              OwnershipTransferred(owner, newOwner);
              owner = newOwner;
            }
          
          }
          
          // File: zeppelin/contracts/lifecycle/Pausable.sol
          
          /**
           * @title Pausable
           * @dev Base contract which allows children to implement an emergency stop mechanism.
           */
          contract Pausable is Ownable {
            event Pause();
            event Unpause();
          
            bool public paused = false;
          
          
            /**
             * @dev Modifier to make a function callable only when the contract is not paused.
             */
            modifier whenNotPaused() {
              require(!paused);
              _;
            }
          
            /**
             * @dev Modifier to make a function callable only when the contract is paused.
             */
            modifier whenPaused() {
              require(paused);
              _;
            }
          
            /**
             * @dev called by the owner to pause, triggers stopped state
             */
            function pause() onlyOwner whenNotPaused public {
              paused = true;
              Pause();
            }
          
            /**
             * @dev called by the owner to unpause, returns to normal state
             */
            function unpause() onlyOwner whenPaused public {
              paused = false;
              Unpause();
            }
          }
          
          // File: zeppelin/contracts/ownership/HasNoContracts.sol
          
          /**
           * @title Contracts that should not own Contracts
           * @author Remco Bloemen <remco@2π.com>
           * @dev Should contracts (anything Ownable) end up being owned by this contract, it allows the owner
           * of this contract to reclaim ownership of the contracts.
           */
          contract HasNoContracts is Ownable {
          
            /**
             * @dev Reclaim ownership of Ownable contracts
             * @param contractAddr The address of the Ownable to be reclaimed.
             */
            function reclaimContract(address contractAddr) external onlyOwner {
              Ownable contractInst = Ownable(contractAddr);
              contractInst.transferOwnership(owner);
            }
          }
          
          // File: zeppelin/contracts/token/ERC20Basic.sol
          
          /**
           * @title ERC20Basic
           * @dev Simpler version of ERC20 interface
           * @dev see https://github.com/ethereum/EIPs/issues/179
           */
          contract ERC20Basic {
            uint256 public totalSupply;
            function balanceOf(address who) public constant returns (uint256);
            function transfer(address to, uint256 value) public returns (bool);
            event Transfer(address indexed from, address indexed to, uint256 value);
          }
          
          // File: zeppelin/contracts/token/ERC20.sol
          
          /**
           * @title ERC20 interface
           * @dev see https://github.com/ethereum/EIPs/issues/20
           */
          contract ERC20 is ERC20Basic {
            function allowance(address owner, address spender) public constant returns (uint256);
            function transferFrom(address from, address to, uint256 value) public returns (bool);
            function approve(address spender, uint256 value) public returns (bool);
            event Approval(address indexed owner, address indexed spender, uint256 value);
          }
          
          // File: zeppelin/contracts/token/SafeERC20.sol
          
          /**
           * @title SafeERC20
           * @dev Wrappers around ERC20 operations that throw on failure.
           * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
           * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
           */
          library SafeERC20 {
            function safeTransfer(ERC20Basic token, address to, uint256 value) internal {
              assert(token.transfer(to, value));
            }
          
            function safeTransferFrom(ERC20 token, address from, address to, uint256 value) internal {
              assert(token.transferFrom(from, to, value));
            }
          
            function safeApprove(ERC20 token, address spender, uint256 value) internal {
              assert(token.approve(spender, value));
            }
          }
          
          // File: zeppelin/contracts/ownership/CanReclaimToken.sol
          
          /**
           * @title Contracts that should be able to recover tokens
           * @author SylTi
           * @dev This allow a contract to recover any ERC20 token received in a contract by transferring the balance to the contract owner.
           * This will prevent any accidental loss of tokens.
           */
          contract CanReclaimToken is Ownable {
            using SafeERC20 for ERC20Basic;
          
            /**
             * @dev Reclaim all ERC20Basic compatible tokens
             * @param token ERC20Basic The address of the token contract
             */
            function reclaimToken(ERC20Basic token) external onlyOwner {
              uint256 balance = token.balanceOf(this);
              token.safeTransfer(owner, balance);
            }
          
          }
          
          // File: zeppelin/contracts/ownership/HasNoTokens.sol
          
          /**
           * @title Contracts that should not own Tokens
           * @author Remco Bloemen <remco@2π.com>
           * @dev This blocks incoming ERC23 tokens to prevent accidental loss of tokens.
           * Should tokens (any ERC20Basic compatible) end up in the contract, it allows the
           * owner to reclaim the tokens.
           */
          contract HasNoTokens is CanReclaimToken {
          
           /**
            * @dev Reject all ERC23 compatible tokens
            * @param from_ address The address that is transferring the tokens
            * @param value_ uint256 the amount of the specified token
            * @param data_ Bytes The data passed from the caller.
            */
            function tokenFallback(address from_, uint256 value_, bytes data_) external {
              revert();
            }
          
          }
          
          // File: contracts/marketplace/AxieSiringClockAuction.sol
          
          /// @title Clock auction for Axie siring.
          contract AxieSiringClockAuction is HasNoContracts, HasNoTokens, Pausable {
            // Represents an auction on an NFT.
            struct Auction {
              // 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;
            }
          
            // 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;
          
            IERC721Base coreContract;
            AxieIncubatorInterface incubatorContract;
          
            // Map from Axie ID to their corresponding auction.
            mapping (uint256 => Auction) public auctions;
          
            event AuctionCreated(
              uint256 indexed _axieId,
              uint256 _startingPrice,
              uint256 _endingPrice,
              uint256 _duration,
              address _seller
            );
          
            event AuctionSuccessful(
              uint256 indexed _sireId,
              uint256 indexed _matronId,
              uint256 _totalPrice,
              address _winner
            );
          
            event AuctionCancelled(uint256 indexed _axieId);
          
            /// @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.
            constructor(uint256 _ownerCut) public {
              require(_ownerCut <= 10000);
              ownerCut = _ownerCut;
            }
          
            function () external payable onlyOwner {
            }
          
            // Modifiers to check that inputs can be safely stored with a certain
            // number of bits. We use constants and multiple modifiers to save gas.
            modifier canBeStoredWith64Bits(uint256 _value) {
              require(_value <= 18446744073709551615);
              _;
            }
          
            modifier canBeStoredWith128Bits(uint256 _value) {
              require(_value < 340282366920938463463374607431768211455);
              _;
            }
          
            function reclaimEther() external onlyOwner {
              owner.transfer(address(this).balance);
            }
          
            function setCoreContract(address _coreAddress) external onlyOwner {
              coreContract = IERC721Base(_coreAddress);
            }
          
            function setIncubatorContract(address _incubatorAddress) external onlyOwner {
              incubatorContract = AxieIncubatorInterface(_incubatorAddress);
            }
          
            /// @dev Returns auction info for an NFT on auction.
            /// @param _axieId - ID of NFT on auction.
            function getAuction(
              uint256 _axieId
            )
              external
              view
              returns (
                address seller,
                uint256 startingPrice,
                uint256 endingPrice,
                uint256 duration,
                uint256 startedAt
              )
            {
              Auction storage _auction = auctions[_axieId];
              require(_isOnAuction(_auction));
              return (
                _auction.seller,
                _auction.startingPrice,
                _auction.endingPrice,
                _auction.duration,
                _auction.startedAt
              );
            }
          
            /// @dev Returns the current price of an auction.
            /// @param _axieId - ID of the Axie price we are checking.
            function getCurrentPrice(
              uint256 _axieId
            )
              external
              view
              returns (uint256)
            {
              Auction storage _auction = auctions[_axieId];
              require(_isOnAuction(_auction));
              return _getCurrentPrice(_auction);
            }
          
            /// @dev Creates and begins a new auction.
            /// @param _axieId - ID of Axie 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).
            function createAuction(
              uint256 _axieId,
              uint256 _startingPrice,
              uint256 _endingPrice,
              uint256 _duration
            )
              external
              whenNotPaused
              canBeStoredWith128Bits(_startingPrice)
              canBeStoredWith128Bits(_endingPrice)
              canBeStoredWith64Bits(_duration)
            {
              address _seller = msg.sender;
          
              require(coreContract.ownerOf(_axieId) == _seller);
              incubatorContract.requireEnoughExpForBreeding(_axieId); // Validate EXP for breeding.
          
              _escrow(_seller, _axieId);
          
              Auction memory _auction = Auction(
                _seller,
                uint128(_startingPrice),
                uint128(_endingPrice),
                uint64(_duration),
                uint64(now)
              );
          
              _addAuction(
                _axieId,
                _auction,
                _seller
              );
            }
          
            /// @dev Bids on an siring auction and completing it.
            /// @param _sireId - ID of Axie to bid on siring.
            /// @param _matronId - ID of matron Axie.
            function bidOnSiring(
              uint256 _sireId,
              uint256 _matronId,
              uint256 _birthPlace
            )
              external
              payable
              whenNotPaused
              returns (uint256 /* _axieId */)
            {
              Auction storage _auction = auctions[_sireId];
              require(_isOnAuction(_auction));
          
              require(msg.sender == coreContract.ownerOf(_matronId));
          
              // Save seller address here since `_bid` will clear it.
              address _seller = _auction.seller;
          
              // _bid will throw if the bid or funds transfer fails.
              _bid(_sireId, _matronId, msg.value, _auction);
          
              uint256 _axieId = incubatorContract.breedAxies.value(
                incubatorContract.breedingFee()
              )(
                _sireId,
                _matronId,
                _birthPlace
              );
          
              _transfer(_seller, _sireId);
          
              return _axieId;
            }
          
            /// @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 _axieId - ID of Axie on auction.
            function cancelAuction(uint256 _axieId) external {
              Auction storage _auction = auctions[_axieId];
              require(_isOnAuction(_auction));
              require(msg.sender == _auction.seller);
              _cancelAuction(_axieId, _auction.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 _axieId - ID of the NFT on auction to cancel.
            function cancelAuctionWhenPaused(
              uint256 _axieId
            )
              external
              whenPaused
              onlyOwner
            {
              Auction storage _auction = auctions[_axieId];
              require(_isOnAuction(_auction));
              _cancelAuction(_axieId, _auction.seller);
            }
          
            /// @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 _getCurrentPrice(
              Auction storage _auction
            )
              internal
              view
              returns (uint256)
            {
              uint256 _secondsPassed = 0;
          
              // A bit of insurance against negative values (or wraparound).
              // Probably not necessary (since Ethereum guarantees 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 external 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 external 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 Adds an auction to the list of open auctions. Also fires the
            ///  AuctionCreated event.
            /// @param _axieId The ID of the Axie to be put on auction.
            /// @param _auction Auction to add.
            function _addAuction(
              uint256 _axieId,
              Auction memory _auction,
              address _seller
            )
              internal
            {
              // Require that all auctions have a duration of
              // at least one minute. (Keeps our math from getting hairy!).
              require(_auction.duration >= 1 minutes);
          
              auctions[_axieId] = _auction;
          
              emit AuctionCreated(
                _axieId,
                uint256(_auction.startingPrice),
                uint256(_auction.endingPrice),
                uint256(_auction.duration),
                _seller
              );
            }
          
            /// @dev Removes an auction from the list of open auctions.
            /// @param _axieId - ID of NFT on auction.
            function _removeAuction(uint256 _axieId) internal {
              delete auctions[_axieId];
            }
          
            /// @dev Cancels an auction unconditionally.
            function _cancelAuction(uint256 _axieId, address _seller) internal {
              _removeAuction(_axieId);
              _transfer(_seller, _axieId);
              emit AuctionCancelled(_axieId);
            }
          
            /// @dev Escrows the NFT, assigning ownership to this contract.
            /// Throws if the escrow fails.
            /// @param _owner - Current owner address of Axie to escrow.
            /// @param _axieId - ID of Axie whose approval to verify.
            function _escrow(address _owner, uint256 _axieId) internal {
              // It will throw if transfer fails.
              coreContract.transferFrom(_owner, this, _axieId);
            }
          
            /// @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 _axieId - ID of Axie to transfer.
            function _transfer(address _receiver, uint256 _axieId) internal {
              // It will throw if transfer fails
              coreContract.transferFrom(this, _receiver, _axieId);
            }
          
            /// @dev Computes owner's cut of a sale.
            /// @param _price - Sale price of NFT.
            function _computeCut(uint256 _price) internal view returns (uint256) {
              // 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.
              return _price * ownerCut / 10000;
            }
          
            /// @dev Computes the price and transfers winnings.
            /// Does NOT transfer ownership of Axie.
            function _bid(
              uint256 _sireId,
              uint256 _matronId,
              uint256 _bidAmount,
              Auction storage _auction
            )
              internal
              returns (uint256)
            {
              // Check that the incoming bid is higher than the current price.
              uint256 _price = _getCurrentPrice(_auction);
              uint256 _priceWithFee = _price + incubatorContract.breedingFee();
          
              // Technically this shouldn't happen as `_price` fits in 128 bits.
              // However, we could set `breedingFee` to a very large number accidentally.
              assert(_priceWithFee >= _price);
          
              require(_bidAmount >= _priceWithFee);
          
              // 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(_sireId);
          
              // 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 = _computeCut(_price);
                uint256 _sellerProceeds = _price - _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);
              }
          
              if (_bidAmount > _priceWithFee) {
                // 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 - _priceWithFee;
          
                // 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(
                _sireId,
                _matronId,
                _price,
                msg.sender
              );
          
              return _price;
            }
          }

          File 2 of 2: AxieCore
          pragma solidity ^0.4.19;
          
          // File: contracts/erc/erc165/IERC165.sol
          
          /// @title ERC-165 Standard Interface Detection
          /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
          interface IERC165 {
            /// @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);
          }
          
          // File: contracts/erc/erc165/ERC165.sol
          
          contract ERC165 is IERC165 {
            /// @dev You must not set element 0xffffffff to true
            mapping (bytes4 => bool) internal supportedInterfaces;
          
            function ERC165() internal {
              supportedInterfaces[0x01ffc9a7] = true; // ERC-165
            }
          
            function supportsInterface(bytes4 interfaceID) external view returns (bool) {
              return supportedInterfaces[interfaceID];
            }
          }
          
          // File: contracts/erc/erc721/IERC721Base.sol
          
          /// @title ERC-721 Non-Fungible Token Standard
          /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
          ///  Note: the ERC-165 identifier for this interface is 0x6466353c
          interface IERC721Base /* is IERC165  */ {
            /// @dev This emits when ownership of any NFT changes by any mechanism.
            ///  This event emits when NFTs are created (`from` == 0) and destroyed
            ///  (`to` == 0). Exception: during contract creation, any number of NFTs
            ///  may be created and assigned without emitting Transfer. At the time of
            ///  any transfer, the approved address for that NFT (if any) is reset to none.
            event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
          
            /// @dev This emits when the approved address for an NFT is changed or
            ///  reaffirmed. The zero address indicates there is no approved address.
            ///  When a Transfer event emits, this also indicates that the approved
            ///  address for that NFT (if any) is reset to none.
            event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
          
            /// @dev This emits when an operator is enabled or disabled for an owner.
            ///  The operator can manage all NFTs of the owner.
            event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
          
            /// @notice Count all NFTs assigned to an owner
            /// @dev NFTs assigned to the zero address are considered invalid, and this
            ///  function throws for queries about the zero address.
            /// @param _owner An address for whom to query the balance
            /// @return The number of NFTs owned by `_owner`, possibly zero
            function balanceOf(address _owner) external view returns (uint256);
          
            /// @notice Find the owner of an NFT
            /// @param _tokenId The identifier for an NFT
            /// @dev NFTs assigned to zero address are considered invalid, and queries
            ///  about them do throw.
            /// @return The address of the owner of the NFT
            function ownerOf(uint256 _tokenId) external view returns (address);
          
            /// @notice Transfers the ownership of an NFT from one address to another address
            /// @dev Throws unless `msg.sender` is the current owner, an authorized
            ///  operator, or the approved address for this NFT. Throws if `_from` is
            ///  not the current owner. Throws if `_to` is the zero address. Throws if
            ///  `_tokenId` is not a valid NFT. When transfer is complete, this function
            ///  checks if `_to` is a smart contract (code size > 0). If so, it calls
            ///  `onERC721Received` on `_to` and throws if the return value is not
            ///  `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`.
            /// @param _from The current owner of the NFT
            /// @param _to The new owner
            /// @param _tokenId The NFT to transfer
            /// @param _data Additional data with no specified format, sent in call to `_to`
            // solium-disable-next-line arg-overflow
            function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes _data) external payable;
          
            /// @notice Transfers the ownership of an NFT from one address to another address
            /// @dev This works identically to the other function with an extra data parameter,
            ///  except this function just sets data to []
            /// @param _from The current owner of the NFT
            /// @param _to The new owner
            /// @param _tokenId The NFT to transfer
            function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
          
            /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
            ///  TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
            ///  THEY MAY BE PERMANENTLY LOST
            /// @dev Throws unless `msg.sender` is the current owner, an authorized
            ///  operator, or the approved address for this NFT. Throws if `_from` is
            ///  not the current owner. Throws if `_to` is the zero address. Throws if
            ///  `_tokenId` is not a valid NFT.
            /// @param _from The current owner of the NFT
            /// @param _to The new owner
            /// @param _tokenId The NFT to transfer
            function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
          
            /// @notice Set or reaffirm the approved address for an NFT
            /// @dev The zero address indicates there is no approved address.
            /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
            ///  operator of the current owner.
            /// @param _approved The new approved NFT controller
            /// @param _tokenId The NFT to approve
            function approve(address _approved, uint256 _tokenId) external payable;
          
            /// @notice Enable or disable approval for a third party ("operator") to manage
            ///  all your asset.
            /// @dev Emits the ApprovalForAll event
            /// @param _operator Address to add to the set of authorized operators.
            /// @param _approved True if the operators is approved, false to revoke approval
            function setApprovalForAll(address _operator, bool _approved) external;
          
            /// @notice Get the approved address for a single NFT
            /// @dev Throws if `_tokenId` is not a valid NFT
            /// @param _tokenId The NFT to find the approved address for
            /// @return The approved address for this NFT, or the zero address if there is none
            function getApproved(uint256 _tokenId) external view returns (address);
          
            /// @notice Query if an address is an authorized operator for another address
            /// @param _owner The address that owns the NFTs
            /// @param _operator The address that acts on behalf of the owner
            /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
            function isApprovedForAll(address _owner, address _operator) external view returns (bool);
          }
          
          // File: contracts/erc/erc721/IERC721Enumerable.sol
          
          /// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
          /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
          ///  Note: the ERC-165 identifier for this interface is 0x780e9d63
          interface IERC721Enumerable /* is IERC721Base */ {
            /// @notice Count NFTs tracked by this contract
            /// @return A count of valid NFTs tracked by this contract, where each one of
            ///  them has an assigned and queryable owner not equal to the zero address
            function totalSupply() external view returns (uint256);
          
            /// @notice Enumerate valid NFTs
            /// @dev Throws if `_index` >= `totalSupply()`.
            /// @param _index A counter less than `totalSupply()`
            /// @return The token identifier for the `_index`th NFT,
            ///  (sort order not specified)
            function tokenByIndex(uint256 _index) external view returns (uint256);
          
            /// @notice Enumerate NFTs assigned to an owner
            /// @dev Throws if `_index` >= `balanceOf(_owner)` or if
            ///  `_owner` is the zero address, representing invalid NFTs.
            /// @param _owner An address where we are interested in NFTs owned by them
            /// @param _index A counter less than `balanceOf(_owner)`
            /// @return The token identifier for the `_index`th NFT assigned to `_owner`,
            ///   (sort order not specified)
            function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256 _tokenId);
          }
          
          // File: contracts/erc/erc721/IERC721TokenReceiver.sol
          
          /// @dev Note: the ERC-165 identifier for this interface is 0xf0b9e5ba
          interface IERC721TokenReceiver {
            /// @notice Handle the receipt of an NFT
            /// @dev The ERC721 smart contract calls this function on the recipient
            ///  after a `transfer`. 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)"))`
            ///  unless throwing
          	function onERC721Received(address _from, uint256 _tokenId, bytes _data) external returns (bytes4);
          }
          
          // File: contracts/core/dependency/AxieManager.sol
          
          interface AxieSpawningManager {
          	function isSpawningAllowed(uint256 _genes, address _owner) external returns (bool);
            function isRebirthAllowed(uint256 _axieId, uint256 _genes) external returns (bool);
          }
          
          interface AxieRetirementManager {
            function isRetirementAllowed(uint256 _axieId, bool _rip) external returns (bool);
          }
          
          interface AxieMarketplaceManager {
            function isTransferAllowed(address _from, address _to, uint256 _axieId) external returns (bool);
          }
          
          interface AxieGeneManager {
            function isEvolvementAllowed(uint256 _axieId, uint256 _newGenes) external returns (bool);
          }
          
          // File: contracts/core/dependency/AxieDependency.sol
          
          contract AxieDependency {
          
            address public whitelistSetterAddress;
          
            AxieSpawningManager public spawningManager;
            AxieRetirementManager public retirementManager;
            AxieMarketplaceManager public marketplaceManager;
            AxieGeneManager public geneManager;
          
            mapping (address => bool) public whitelistedSpawner;
            mapping (address => bool) public whitelistedByeSayer;
            mapping (address => bool) public whitelistedMarketplace;
            mapping (address => bool) public whitelistedGeneScientist;
          
            function AxieDependency() internal {
              whitelistSetterAddress = msg.sender;
            }
          
            modifier onlyWhitelistSetter() {
              require(msg.sender == whitelistSetterAddress);
              _;
            }
          
            modifier whenSpawningAllowed(uint256 _genes, address _owner) {
              require(
                spawningManager == address(0) ||
                  spawningManager.isSpawningAllowed(_genes, _owner)
              );
              _;
            }
          
            modifier whenRebirthAllowed(uint256 _axieId, uint256 _genes) {
              require(
                spawningManager == address(0) ||
                  spawningManager.isRebirthAllowed(_axieId, _genes)
              );
              _;
            }
          
            modifier whenRetirementAllowed(uint256 _axieId, bool _rip) {
              require(
                retirementManager == address(0) ||
                  retirementManager.isRetirementAllowed(_axieId, _rip)
              );
              _;
            }
          
            modifier whenTransferAllowed(address _from, address _to, uint256 _axieId) {
              require(
                marketplaceManager == address(0) ||
                  marketplaceManager.isTransferAllowed(_from, _to, _axieId)
              );
              _;
            }
          
            modifier whenEvolvementAllowed(uint256 _axieId, uint256 _newGenes) {
              require(
                geneManager == address(0) ||
                  geneManager.isEvolvementAllowed(_axieId, _newGenes)
              );
              _;
            }
          
            modifier onlySpawner() {
              require(whitelistedSpawner[msg.sender]);
              _;
            }
          
            modifier onlyByeSayer() {
              require(whitelistedByeSayer[msg.sender]);
              _;
            }
          
            modifier onlyMarketplace() {
              require(whitelistedMarketplace[msg.sender]);
              _;
            }
          
            modifier onlyGeneScientist() {
              require(whitelistedGeneScientist[msg.sender]);
              _;
            }
          
            /*
             * @dev Setting the whitelist setter address to `address(0)` would be a irreversible process.
             *  This is to lock changes to Axie's contracts after their development is done.
             */
            function setWhitelistSetter(address _newSetter) external onlyWhitelistSetter {
              whitelistSetterAddress = _newSetter;
            }
          
            function setSpawningManager(address _manager) external onlyWhitelistSetter {
              spawningManager = AxieSpawningManager(_manager);
            }
          
            function setRetirementManager(address _manager) external onlyWhitelistSetter {
              retirementManager = AxieRetirementManager(_manager);
            }
          
            function setMarketplaceManager(address _manager) external onlyWhitelistSetter {
              marketplaceManager = AxieMarketplaceManager(_manager);
            }
          
            function setGeneManager(address _manager) external onlyWhitelistSetter {
              geneManager = AxieGeneManager(_manager);
            }
          
            function setSpawner(address _spawner, bool _whitelisted) external onlyWhitelistSetter {
              require(whitelistedSpawner[_spawner] != _whitelisted);
              whitelistedSpawner[_spawner] = _whitelisted;
            }
          
            function setByeSayer(address _byeSayer, bool _whitelisted) external onlyWhitelistSetter {
              require(whitelistedByeSayer[_byeSayer] != _whitelisted);
              whitelistedByeSayer[_byeSayer] = _whitelisted;
            }
          
            function setMarketplace(address _marketplace, bool _whitelisted) external onlyWhitelistSetter {
              require(whitelistedMarketplace[_marketplace] != _whitelisted);
              whitelistedMarketplace[_marketplace] = _whitelisted;
            }
          
            function setGeneScientist(address _geneScientist, bool _whitelisted) external onlyWhitelistSetter {
              require(whitelistedGeneScientist[_geneScientist] != _whitelisted);
              whitelistedGeneScientist[_geneScientist] = _whitelisted;
            }
          }
          
          // File: contracts/core/AxieAccessControl.sol
          
          contract AxieAccessControl {
          
            address public ceoAddress;
            address public cfoAddress;
            address public cooAddress;
          
            function AxieAccessControl() internal {
              ceoAddress = msg.sender;
            }
          
            modifier onlyCEO() {
              require(msg.sender == ceoAddress);
              _;
            }
          
            modifier onlyCFO() {
              require(msg.sender == cfoAddress);
              _;
            }
          
            modifier onlyCOO() {
              require(msg.sender == cooAddress);
              _;
            }
          
            modifier onlyCLevel() {
              require(
                // solium-disable operator-whitespace
                msg.sender == ceoAddress ||
                  msg.sender == cfoAddress ||
                  msg.sender == cooAddress
                // solium-enable operator-whitespace
              );
              _;
            }
          
            function setCEO(address _newCEO) external onlyCEO {
              require(_newCEO != address(0));
              ceoAddress = _newCEO;
            }
          
            function setCFO(address _newCFO) external onlyCEO {
              cfoAddress = _newCFO;
            }
          
            function setCOO(address _newCOO) external onlyCEO {
              cooAddress = _newCOO;
            }
          
            function withdrawBalance() external onlyCFO {
              cfoAddress.transfer(this.balance);
            }
          }
          
          // File: contracts/core/lifecycle/AxiePausable.sol
          
          contract AxiePausable is AxieAccessControl {
          
            bool public paused = false;
          
            modifier whenNotPaused() {
              require(!paused);
              _;
            }
          
            modifier whenPaused {
              require(paused);
              _;
            }
          
            function pause() external onlyCLevel whenNotPaused {
              paused = true;
            }
          
            function unpause() public onlyCEO whenPaused {
              paused = false;
            }
          }
          
          // File: zeppelin/contracts/math/SafeMath.sol
          
          /**
           * @title SafeMath
           * @dev Math operations with safety checks that throw on error
           */
          library SafeMath {
            function mul(uint256 a, uint256 b) internal constant returns (uint256) {
              uint256 c = a * b;
              assert(a == 0 || c / a == b);
              return c;
            }
          
            function div(uint256 a, uint256 b) internal constant 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;
            }
          
            function sub(uint256 a, uint256 b) internal constant returns (uint256) {
              assert(b <= a);
              return a - b;
            }
          
            function add(uint256 a, uint256 b) internal constant returns (uint256) {
              uint256 c = a + b;
              assert(c >= a);
              return c;
            }
          }
          
          // File: contracts/core/erc721/AxieERC721BaseEnumerable.sol
          
          contract AxieERC721BaseEnumerable is ERC165, IERC721Base, IERC721Enumerable, AxieDependency, AxiePausable {
            using SafeMath for uint256;
          
            // @dev Total amount of tokens.
            uint256 private _totalTokens;
          
            // @dev Mapping from token index to ID.
            mapping (uint256 => uint256) private _overallTokenId;
          
            // @dev Mapping from token ID to index.
            mapping (uint256 => uint256) private _overallTokenIndex;
          
            // @dev Mapping from token ID to owner.
            mapping (uint256 => address) private _tokenOwner;
          
            // @dev For a given owner and a given operator, store whether
            //  the operator is allowed to manage tokens on behalf of the owner.
            mapping (address => mapping (address => bool)) private _tokenOperator;
          
            // @dev Mapping from token ID to approved address.
            mapping (uint256 => address) private _tokenApproval;
          
            // @dev Mapping from owner to list of owned token IDs.
            mapping (address => uint256[]) private _ownedTokens;
          
            // @dev Mapping from token ID to index in the owned token list.
            mapping (uint256 => uint256) private _ownedTokenIndex;
          
            function AxieERC721BaseEnumerable() internal {
              supportedInterfaces[0x6466353c] = true; // ERC-721 Base
              supportedInterfaces[0x780e9d63] = true; // ERC-721 Enumerable
            }
          
            // solium-disable function-order
          
            modifier mustBeValidToken(uint256 _tokenId) {
              require(_tokenOwner[_tokenId] != address(0));
              _;
            }
          
            function _isTokenOwner(address _ownerToCheck, uint256 _tokenId) private view returns (bool) {
              return _tokenOwner[_tokenId] == _ownerToCheck;
            }
          
            function _isTokenOperator(address _operatorToCheck, uint256 _tokenId) private view returns (bool) {
              return whitelistedMarketplace[_operatorToCheck] ||
                _tokenOperator[_tokenOwner[_tokenId]][_operatorToCheck];
            }
          
            function _isApproved(address _approvedToCheck, uint256 _tokenId) private view returns (bool) {
              return _tokenApproval[_tokenId] == _approvedToCheck;
            }
          
            modifier onlyTokenOwner(uint256 _tokenId) {
              require(_isTokenOwner(msg.sender, _tokenId));
              _;
            }
          
            modifier onlyTokenOwnerOrOperator(uint256 _tokenId) {
              require(_isTokenOwner(msg.sender, _tokenId) || _isTokenOperator(msg.sender, _tokenId));
              _;
            }
          
            modifier onlyTokenAuthorized(uint256 _tokenId) {
              require(
                // solium-disable operator-whitespace
                _isTokenOwner(msg.sender, _tokenId) ||
                  _isTokenOperator(msg.sender, _tokenId) ||
                  _isApproved(msg.sender, _tokenId)
                // solium-enable operator-whitespace
              );
              _;
            }
          
            // ERC-721 Base
          
            function balanceOf(address _owner) external view returns (uint256) {
              require(_owner != address(0));
              return _ownedTokens[_owner].length;
            }
          
            function ownerOf(uint256 _tokenId) external view mustBeValidToken(_tokenId) returns (address) {
              return _tokenOwner[_tokenId];
            }
          
            function _addTokenTo(address _to, uint256 _tokenId) private {
              require(_to != address(0));
          
              _tokenOwner[_tokenId] = _to;
          
              uint256 length = _ownedTokens[_to].length;
              _ownedTokens[_to].push(_tokenId);
              _ownedTokenIndex[_tokenId] = length;
            }
          
            function _mint(address _to, uint256 _tokenId) internal {
              require(_tokenOwner[_tokenId] == address(0));
          
              _addTokenTo(_to, _tokenId);
          
              _overallTokenId[_totalTokens] = _tokenId;
              _overallTokenIndex[_tokenId] = _totalTokens;
              _totalTokens = _totalTokens.add(1);
          
              Transfer(address(0), _to, _tokenId);
            }
          
            function _removeTokenFrom(address _from, uint256 _tokenId) private {
              require(_from != address(0));
          
              uint256 _tokenIndex = _ownedTokenIndex[_tokenId];
              uint256 _lastTokenIndex = _ownedTokens[_from].length.sub(1);
              uint256 _lastTokenId = _ownedTokens[_from][_lastTokenIndex];
          
              _tokenOwner[_tokenId] = address(0);
          
              // Insert the last token into the position previously occupied by the removed token.
              _ownedTokens[_from][_tokenIndex] = _lastTokenId;
              _ownedTokenIndex[_lastTokenId] = _tokenIndex;
          
              // Resize the array.
              delete _ownedTokens[_from][_lastTokenIndex];
              _ownedTokens[_from].length--;
          
              // Remove the array if no more tokens are owned to prevent pollution.
              if (_ownedTokens[_from].length == 0) {
                delete _ownedTokens[_from];
              }
          
              // Update the index of the removed token.
              delete _ownedTokenIndex[_tokenId];
            }
          
            function _burn(uint256 _tokenId) internal {
              address _from = _tokenOwner[_tokenId];
          
              require(_from != address(0));
          
              _removeTokenFrom(_from, _tokenId);
              _totalTokens = _totalTokens.sub(1);
          
              uint256 _tokenIndex = _overallTokenIndex[_tokenId];
              uint256 _lastTokenId = _overallTokenId[_totalTokens];
          
              delete _overallTokenIndex[_tokenId];
              delete _overallTokenId[_totalTokens];
              _overallTokenId[_tokenIndex] = _lastTokenId;
              _overallTokenIndex[_lastTokenId] = _tokenIndex;
          
              Transfer(_from, address(0), _tokenId);
            }
          
            function _isContract(address _address) private view returns (bool) {
              uint _size;
              // solium-disable-next-line security/no-inline-assembly
              assembly { _size := extcodesize(_address) }
              return _size > 0;
            }
          
            function _transferFrom(
              address _from,
              address _to,
              uint256 _tokenId,
              bytes _data,
              bool _check
            )
              internal
              mustBeValidToken(_tokenId)
              onlyTokenAuthorized(_tokenId)
              whenTransferAllowed(_from, _to, _tokenId)
            {
              require(_isTokenOwner(_from, _tokenId));
              require(_to != address(0));
              require(_to != _from);
          
              _removeTokenFrom(_from, _tokenId);
          
              delete _tokenApproval[_tokenId];
              Approval(_from, address(0), _tokenId);
          
              _addTokenTo(_to, _tokenId);
          
              if (_check && _isContract(_to)) {
                IERC721TokenReceiver(_to).onERC721Received.gas(50000)(_from, _tokenId, _data);
              }
          
              Transfer(_from, _to, _tokenId);
            }
          
            // solium-disable arg-overflow
          
            function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes _data) external payable {
              _transferFrom(_from, _to, _tokenId, _data, true);
            }
          
            function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable {
              _transferFrom(_from, _to, _tokenId, "", true);
            }
          
            function transferFrom(address _from, address _to, uint256 _tokenId) external payable {
              _transferFrom(_from, _to, _tokenId, "", false);
            }
          
            // solium-enable arg-overflow
          
            function approve(
              address _approved,
              uint256 _tokenId
            )
              external
              payable
              mustBeValidToken(_tokenId)
              onlyTokenOwnerOrOperator(_tokenId)
              whenNotPaused
            {
              address _owner = _tokenOwner[_tokenId];
          
              require(_owner != _approved);
              require(_tokenApproval[_tokenId] != _approved);
          
              _tokenApproval[_tokenId] = _approved;
          
              Approval(_owner, _approved, _tokenId);
            }
          
            function setApprovalForAll(address _operator, bool _approved) external whenNotPaused {
              require(_tokenOperator[msg.sender][_operator] != _approved);
              _tokenOperator[msg.sender][_operator] = _approved;
              ApprovalForAll(msg.sender, _operator, _approved);
            }
          
            function getApproved(uint256 _tokenId) external view mustBeValidToken(_tokenId) returns (address) {
              return _tokenApproval[_tokenId];
            }
          
            function isApprovedForAll(address _owner, address _operator) external view returns (bool) {
              return _tokenOperator[_owner][_operator];
            }
          
            // ERC-721 Enumerable
          
            function totalSupply() external view returns (uint256) {
              return _totalTokens;
            }
          
            function tokenByIndex(uint256 _index) external view returns (uint256) {
              require(_index < _totalTokens);
              return _overallTokenId[_index];
            }
          
            function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256 _tokenId) {
              require(_owner != address(0));
              require(_index < _ownedTokens[_owner].length);
              return _ownedTokens[_owner][_index];
            }
          }
          
          // File: contracts/erc/erc721/IERC721Metadata.sol
          
          /// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
          /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
          ///  Note: the ERC-165 identifier for this interface is 0x5b5e139f
          interface IERC721Metadata /* is IERC721Base */ {
            /// @notice A descriptive name for a collection of NFTs in this contract
            function name() external pure returns (string _name);
          
            /// @notice An abbreviated name for NFTs in this contract
            function symbol() external pure returns (string _symbol);
          
            /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
            /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
            ///  3986. The URI may point to a JSON file that conforms to the "ERC721
            ///  Metadata JSON Schema".
            function tokenURI(uint256 _tokenId) external view returns (string);
          }
          
          // File: contracts/core/erc721/AxieERC721Metadata.sol
          
          contract AxieERC721Metadata is AxieERC721BaseEnumerable, IERC721Metadata {
            string public tokenURIPrefix = "https://axieinfinity.com/erc/721/axies/";
            string public tokenURISuffix = ".json";
          
            function AxieERC721Metadata() internal {
              supportedInterfaces[0x5b5e139f] = true; // ERC-721 Metadata
            }
          
            function name() external pure returns (string) {
              return "Axie";
            }
          
            function symbol() external pure returns (string) {
              return "AXIE";
            }
          
            function setTokenURIAffixes(string _prefix, string _suffix) external onlyCEO {
              tokenURIPrefix = _prefix;
              tokenURISuffix = _suffix;
            }
          
            function tokenURI(
              uint256 _tokenId
            )
              external
              view
              mustBeValidToken(_tokenId)
              returns (string)
            {
              bytes memory _tokenURIPrefixBytes = bytes(tokenURIPrefix);
              bytes memory _tokenURISuffixBytes = bytes(tokenURISuffix);
              uint256 _tmpTokenId = _tokenId;
              uint256 _length;
          
              do {
                _length++;
                _tmpTokenId /= 10;
              } while (_tmpTokenId > 0);
          
              bytes memory _tokenURIBytes = new bytes(_tokenURIPrefixBytes.length + _length + 5);
              uint256 _i = _tokenURIBytes.length - 6;
          
              _tmpTokenId = _tokenId;
          
              do {
                _tokenURIBytes[_i--] = byte(48 + _tmpTokenId % 10);
                _tmpTokenId /= 10;
              } while (_tmpTokenId > 0);
          
              for (_i = 0; _i < _tokenURIPrefixBytes.length; _i++) {
                _tokenURIBytes[_i] = _tokenURIPrefixBytes[_i];
              }
          
              for (_i = 0; _i < _tokenURISuffixBytes.length; _i++) {
                _tokenURIBytes[_tokenURIBytes.length + _i - 5] = _tokenURISuffixBytes[_i];
              }
          
              return string(_tokenURIBytes);
            }
          }
          
          // File: contracts/core/erc721/AxieERC721.sol
          
          // solium-disable-next-line no-empty-blocks
          contract AxieERC721 is AxieERC721BaseEnumerable, AxieERC721Metadata {
          }
          
          // File: contracts/core/AxieCore.sol
          
          // solium-disable-next-line no-empty-blocks
          contract AxieCore is AxieERC721 {
            struct Axie {
              uint256 genes;
              uint256 bornAt;
            }
          
            Axie[] axies;
          
            event AxieSpawned(uint256 indexed _axieId, address indexed _owner, uint256 _genes);
            event AxieRebirthed(uint256 indexed _axieId, uint256 _genes);
            event AxieRetired(uint256 indexed _axieId);
            event AxieEvolved(uint256 indexed _axieId, uint256 _oldGenes, uint256 _newGenes);
          
            function AxieCore() public {
              axies.push(Axie(0, now)); // The void Axie
              _spawnAxie(0, msg.sender); // Will be Puff
              _spawnAxie(0, msg.sender); // Will be Kotaro
              _spawnAxie(0, msg.sender); // Will be Ginger
              _spawnAxie(0, msg.sender); // Will be Stella
            }
          
            function getAxie(
              uint256 _axieId
            )
              external
              view
              mustBeValidToken(_axieId)
              returns (uint256 /* _genes */, uint256 /* _bornAt */)
            {
              Axie storage _axie = axies[_axieId];
              return (_axie.genes, _axie.bornAt);
            }
          
            function spawnAxie(
              uint256 _genes,
              address _owner
            )
              external
              onlySpawner
              whenSpawningAllowed(_genes, _owner)
              returns (uint256)
            {
              return _spawnAxie(_genes, _owner);
            }
          
            function rebirthAxie(
              uint256 _axieId,
              uint256 _genes
            )
              external
              onlySpawner
              mustBeValidToken(_axieId)
              whenRebirthAllowed(_axieId, _genes)
            {
              Axie storage _axie = axies[_axieId];
              _axie.genes = _genes;
              _axie.bornAt = now;
              AxieRebirthed(_axieId, _genes);
            }
          
            function retireAxie(
              uint256 _axieId,
              bool _rip
            )
              external
              onlyByeSayer
              whenRetirementAllowed(_axieId, _rip)
            {
              _burn(_axieId);
          
              if (_rip) {
                delete axies[_axieId];
              }
          
              AxieRetired(_axieId);
            }
          
            function evolveAxie(
              uint256 _axieId,
              uint256 _newGenes
            )
              external
              onlyGeneScientist
              mustBeValidToken(_axieId)
              whenEvolvementAllowed(_axieId, _newGenes)
            {
              uint256 _oldGenes = axies[_axieId].genes;
              axies[_axieId].genes = _newGenes;
              AxieEvolved(_axieId, _oldGenes, _newGenes);
            }
          
            function _spawnAxie(uint256 _genes, address _owner) private returns (uint256 _axieId) {
              Axie memory _axie = Axie(_genes, now);
              _axieId = axies.push(_axie) - 1;
              _mint(_owner, _axieId);
              AxieSpawned(_axieId, _owner, _genes);
            }
          }