ETH Price: $1,591.57 (-0.41%)

Transaction Decoder

Block:
11900973 at Feb-21-2021 03:03:11 PM +UTC
Transaction Fee:
0.010920820137357555 ETH $17.38
Gas Used:
94,145 Gas / 116.000001459 Gwei

Emitted Events:

126 AxieClockAuction.AuctionSuccessful( _nftAddress=AxieCore, _tokenId=35317, _totalPrice=65000000000000000, _winner=[Sender] 0x9ac20c4922fca379bb95083eb441c393ea88033e )
127 AxieCore.Approval( _owner=[Receiver] AxieClockAuction, _approved=0x00000000...000000000, _tokenId=35317 )
128 AxieCore.Transfer( _from=[Receiver] AxieClockAuction, _to=[Sender] 0x9ac20c4922fca379bb95083eb441c393ea88033e, _tokenId=35317 )

Account State Difference:

  Address   Before After State Difference Code
(F2Pool Old)
2,703.770732561392719996 Eth2,703.781653381530077551 Eth0.010920820137357555
0x9AC20C49...3ea88033E
1.178634776353029822 Eth
Nonce: 16
1.102713956215672267 Eth
Nonce: 17
0.075920820137357555
0xF4985070...c9a2dd9e2
(Axie Infinity: Axie Clock Auction)
619.15278107469293991 Eth619.15554357469293991 Eth0.0027625
0xF5b0A3eF...F3FFEcb8d
0xFe24CEA9...f94379401 0.003179745815726841 Eth0.065417245815726841 Eth0.0622375

Execution Trace

ETH 0.065004960317460317 AxieClockAuction.bid( _nftAddress=0xF5b0A3eFB8e8E4c201e2A935F110eAaF3FFEcb8d, _tokenId=35317 )
  • ETH 0.0622375 0xfe24cea99cd00b20be072aeb5b79628f94379401.CALL( )
  • ETH 0.000004960317460317 0x9ac20c4922fca379bb95083eb441c393ea88033e.CALL( )
  • AxieCore.transferFrom( _from=0xF4985070Ce32b6B1994329DF787D1aCc9a2dd9e2, _to=0x9AC20C4922fcA379BB95083Eb441C393ea88033E, _tokenId=35317 )
    • 0xe8bd438d0383cf4d19641eaa4793eddc6cebeaf1.f7ebc39a( )
      • AxieCore.CALL( )
        File 1 of 2: AxieClockAuction
        pragma solidity ^0.4.19;
        
        // 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/HasNoEther.sol
        
        /**
         * @title Contracts that should not own Ether
         * @author Remco Bloemen <remco@2π.com>
         * @dev This tries to block incoming ether to prevent accidental loss of Ether. Should Ether end up
         * in the contract, it will allow the owner to reclaim this ether.
         * @notice Ether can still be send to this contract by:
         * calling functions labeled `payable`
         * `selfdestruct(contract_address)`
         * mining directly to the contract address
        */
        contract HasNoEther is Ownable {
        
          /**
          * @dev Constructor that rejects incoming Ether
          * @dev The `payable` flag is added so we can access `msg.value` without compiler warning. If we
          * leave out payable, then Solidity will allow inheriting contracts to implement a payable
          * constructor. By doing it this way we prevent a payable constructor from working. Alternatively
          * we could use assembly to access msg.value.
          */
          function HasNoEther() payable {
            require(msg.value == 0);
          }
        
          /**
           * @dev Disallows direct send by settings a default function without the `payable` flag.
           */
          function() external {
          }
        
          /**
           * @dev Transfer all Ether held by the contract to the owner.
           */
          function reclaimEther() external onlyOwner {
            assert(owner.send(this.balance));
          }
        }
        
        // File: contracts/marketplace/AxieClockAuction.sol
        
        /// @title Clock auction for non-fungible tokens.
        contract AxieClockAuction is HasNoEther, 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;
        
          // Map from token ID to their corresponding auction.
          mapping (address => mapping (uint256 => Auction)) public auctions;
        
          event AuctionCreated(
            address indexed _nftAddress,
            uint256 indexed _tokenId,
            uint256 _startingPrice,
            uint256 _endingPrice,
            uint256 _duration,
            address _seller
          );
        
          event AuctionSuccessful(
            address indexed _nftAddress,
            uint256 indexed _tokenId,
            uint256 _totalPrice,
            address _winner
          );
        
          event AuctionCancelled(
            address indexed _nftAddress,
            uint256 indexed _tokenId
          );
        
          /// @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.
          function AxieClockAuction(uint256 _ownerCut) public {
            require(_ownerCut <= 10000);
            ownerCut = _ownerCut;
          }
        
          /// @dev DON'T give me your money.
          function () external {}
        
          // 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);
            _;
          }
        
          /// @dev Returns auction info for an NFT on auction.
          /// @param _nftAddress - Address of the NFT.
          /// @param _tokenId - ID of NFT on auction.
          function getAuction(
            address _nftAddress,
            uint256 _tokenId
          )
            external
            view
            returns (
              address seller,
              uint256 startingPrice,
              uint256 endingPrice,
              uint256 duration,
              uint256 startedAt
            )
          {
            Auction storage _auction = auctions[_nftAddress][_tokenId];
            require(_isOnAuction(_auction));
            return (
              _auction.seller,
              _auction.startingPrice,
              _auction.endingPrice,
              _auction.duration,
              _auction.startedAt
            );
          }
        
          /// @dev Returns the current price of an auction.
          /// @param _nftAddress - Address of the NFT.
          /// @param _tokenId - ID of the token price we are checking.
          function getCurrentPrice(
            address _nftAddress,
            uint256 _tokenId
          )
            external
            view
            returns (uint256)
          {
            Auction storage _auction = auctions[_nftAddress][_tokenId];
            require(_isOnAuction(_auction));
            return _getCurrentPrice(_auction);
          }
        
          /// @dev Creates and begins a new auction.
          /// @param _nftAddress - address of a deployed contract implementing
          ///  the Nonfungible Interface.
          /// @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).
          function createAuction(
            address _nftAddress,
            uint256 _tokenId,
            uint256 _startingPrice,
            uint256 _endingPrice,
            uint256 _duration
          )
            external
            whenNotPaused
            canBeStoredWith128Bits(_startingPrice)
            canBeStoredWith128Bits(_endingPrice)
            canBeStoredWith64Bits(_duration)
          {
            address _seller = msg.sender;
            require(_owns(_nftAddress, _seller, _tokenId));
            _escrow(_nftAddress, _seller, _tokenId);
            Auction memory _auction = Auction(
              _seller,
              uint128(_startingPrice),
              uint128(_endingPrice),
              uint64(_duration),
              uint64(now)
            );
            _addAuction(_nftAddress, _tokenId, _auction, _seller);
          }
        
          /// @dev Bids on an open auction, completing the auction and transferring
          ///  ownership of the NFT if enough Ether is supplied.
          /// @param _nftAddress - address of a deployed contract implementing
          ///  the Nonfungible Interface.
          /// @param _tokenId - ID of token to bid on.
          function bid(
            address _nftAddress,
            uint256 _tokenId
          )
            external
            payable
            whenNotPaused
          {
            // _bid will throw if the bid or funds transfer fails
            _bid(_nftAddress, _tokenId, msg.value);
            _transfer(_nftAddress, 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 _nftAddress - Address of the NFT.
          /// @param _tokenId - ID of token on auction
          function cancelAuction(address _nftAddress, uint256 _tokenId) external {
            Auction storage _auction = auctions[_nftAddress][_tokenId];
            require(_isOnAuction(_auction));
            require(msg.sender == _auction.seller);
            _cancelAuction(_nftAddress, _tokenId, _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 _nftAddress - Address of the NFT.
          /// @param _tokenId - ID of the NFT on auction to cancel.
          function cancelAuctionWhenPaused(
            address _nftAddress,
            uint256 _tokenId
          )
            external
            whenPaused
            onlyOwner
          {
            Auction storage _auction = auctions[_nftAddress][_tokenId];
            require(_isOnAuction(_auction));
            _cancelAuction(_nftAddress, _tokenId, _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 Gets the NFT object from an address, validating that implementsERC721 is true.
          /// @param _nftAddress - Address of the NFT.
          function _getNftContract(address _nftAddress) internal pure returns (IERC721Base) {
            IERC721Base candidateContract = IERC721Base(_nftAddress);
            // require(candidateContract.implementsERC721());
            return candidateContract;
          }
        
          /// @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 Returns true if the claimant owns the token.
          /// @param _nftAddress - The address of the NFT.
          /// @param _claimant - Address claiming to own the token.
          /// @param _tokenId - ID of token whose ownership to verify.
          function _owns(address _nftAddress, address _claimant, uint256 _tokenId) private view returns (bool) {
            IERC721Base _nftContract = _getNftContract(_nftAddress);
            return (_nftContract.ownerOf(_tokenId) == _claimant);
          }
        
          /// @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 _nftAddress,
            uint256 _tokenId,
            Auction _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[_nftAddress][_tokenId] = _auction;
        
            AuctionCreated(
              _nftAddress,
              _tokenId,
              uint256(_auction.startingPrice),
              uint256(_auction.endingPrice),
              uint256(_auction.duration),
              _seller
            );
          }
        
          /// @dev Removes an auction from the list of open auctions.
          /// @param _tokenId - ID of NFT on auction.
          function _removeAuction(address _nftAddress, uint256 _tokenId) internal {
            delete auctions[_nftAddress][_tokenId];
          }
        
          /// @dev Cancels an auction unconditionally.
          function _cancelAuction(address _nftAddress, uint256 _tokenId, address _seller) internal {
            _removeAuction(_nftAddress, _tokenId);
            _transfer(_nftAddress, _seller, _tokenId);
            AuctionCancelled(_nftAddress, _tokenId);
          }
        
          /// @dev Escrows the NFT, assigning ownership to this contract.
          /// Throws if the escrow fails.
          /// @param _nftAddress - The address of the NFT.
          /// @param _owner - Current owner address of token to escrow.
          /// @param _tokenId - ID of token whose approval to verify.
          function _escrow(address _nftAddress, address _owner, uint256 _tokenId) private {
            IERC721Base _nftContract = _getNftContract(_nftAddress);
        
            // It will throw if transfer fails
            _nftContract.transferFrom(_owner, this, _tokenId);
          }
        
          /// @dev Transfers an NFT owned by this contract to another address.
          /// Returns true if the transfer succeeds.
          /// @param _nftAddress - The address of the NFT.
          /// @param _receiver - Address to transfer NFT to.
          /// @param _tokenId - ID of token to transfer.
          function _transfer(address _nftAddress, address _receiver, uint256 _tokenId) internal {
            IERC721Base _nftContract = _getNftContract(_nftAddress);
        
            // It will throw if transfer fails
            _nftContract.transferFrom(this, _receiver, _tokenId);
          }
        
          /// @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 token.
          function _bid(
            address _nftAddress,
            uint256 _tokenId,
            uint256 _bidAmount
          )
            internal
            returns (uint256)
          {
            // Get a reference to the auction struct
            Auction storage _auction = auctions[_nftAddress][_tokenId];
        
            // 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 incoming bid is higher than the current
            // price
            uint256 _price = _getCurrentPrice(_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(_nftAddress, _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 = _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 > _price) {
              // 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!
            AuctionSuccessful(_nftAddress, _tokenId, _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);
          }
        }