// File: AccessControl.sol



pragma solidity ^0.5.0;

contract AccessControl {
    // This facet controls access control for Cavalox. There are four roles managed here:
    //
    //     - The CEO: The CEO can reassign other roles and change the addresses of our dependent smart
    //         contracts. It is also the only role that can unpause the smart contract. It is initially
    //         set to the address that created the smart contract in the KittyCore constructor.
    //
    //     - The CFO: The CFO can withdraw funds from CVXBX.
    //
    //     - The COO: The COO can release gen0 kitties to auction, and mint promo cats.
    //
    // It should be noted that these roles are distinct without overlap in their access abilities, the
    // abilities listed for each role above are exhaustive. In particular, while the CEO can assign any
    // address to any role, the CEO address itself doesn't have the ability to act in those roles. This
    // restriction is intentional so that we aren't tempted to use the CEO address frequently out of
    // convenience. The less we use an address, the less likely it is that we somehow compromise the
    // account.

    // The addresses of the accounts (or contracts) that can execute actions within each roles.
    address public ceoAddress;
    address payable public cfoAddress;
    address public cooAddress;
    
    constructor () public {
       ceoAddress = msg.sender;
       cfoAddress = msg.sender;
       cooAddress = msg.sender;
    }
    
    
    /// @dev Access modifier for CEO-only functionality
    modifier onlyCEO() {
        require(msg.sender == ceoAddress);
        _;
    }

    /// @dev Access modifier for CFO-only functionality
    modifier onlyCFO() {
        require(msg.sender == cfoAddress);
        _;
    }

    /// @dev Access modifier for COO-only functionality
    modifier onlyCOO() {
        require(msg.sender == cooAddress);
        _;
    }

    modifier onlyCLevel() {
        require(
            msg.sender == cooAddress ||
            msg.sender == ceoAddress ||
            msg.sender == cfoAddress
        );
        _;
    }
    
     /// @dev Assigns a new address to act as the CEO. Only available to the current CEO.
    /// @param _newCEO The address of the new CEO
    function setCEO(address _newCEO) external onlyCEO {
        require(_newCEO != address(0));

        ceoAddress = _newCEO;
    }

    /// @dev Assigns a new address to act as the CFO. Only available to the current CEO.
    /// @param _newCFO The address of the new CFO
    function setCFO(address payable _newCFO) external onlyCEO {
        require(_newCFO != address(0));

        cfoAddress = _newCFO;
    }

    /// @dev Assigns a new address to act as the COO. Only available to the current CEO.
    /// @param _newCOO The address of the new COO
    function setCOO(address _newCOO) external onlyCEO {
        require(_newCOO != address(0));

        cooAddress = _newCOO;
    }
}

// File: BidCVXBX.sol



pragma solidity ^0.5.0;
import "./ERC721Full.sol";
import "./AccessControl.sol";

contract BidCVXBX is Ownable, AccessControl, ERC721Full {

    //Bidding Active Status
    bool public bidding = false;

    address constant nullAddress = address(0);

    //Bidding
    struct Offer {
        bool isForSale;
        uint tokenId;
        address seller;
        uint minValue;          // in ether
        address onlySellTo;     // specify to sell only to a specific person
    }

    struct Bid {
        bool hasBid;
        uint tokenId;
        address bidder;
        uint value;
    }


    // A record of horses that are offered for sale at a specific minimum value, and perhaps to a specific person
    mapping (uint => Offer) public horsesOfferedForSale;

    // A record of the highest horse bid
    mapping (uint => Bid) public horseBids;

    mapping (address => uint) public pendingWithdrawals;

    uint public bidSuccessFees = 0; //Fees

    //Bid specific events
    event BiddingPaused( uint64 date );
    event BiddingUnPaused( uint64 date );

    event HorseOffered(uint indexed tokenId, uint minValue, address toAddress, uint64 time );
    event HorseBidEntered(uint indexed tokenId, uint value, address indexed fromAddress, uint64 time);
    event HorseBidWithdrawn(uint indexed tokenId, uint value, address indexed fromAddress, uint64 time);
    event HorseBoughtWithBid(uint indexed tokenId, uint value, address indexed fromAddress, address indexed toAddress, uint64 time);
    event HorseBoughtWithOffer(uint indexed tokenId, uint value, address indexed fromAddress, address indexed toAddress, uint64 time);
    event HorseNoLongerForSale(uint indexed tokenId, uint64 time);

    modifier whenBiddingActive() {
        require(bidding, 'Bidding is currently not active!');
        _;
    }

    modifier whenBiddingNotActive() {
        require(!bidding, 'Bidding is currently active!');
        _;
    }

    modifier onlyTokenOwner( uint tokenId ) {
        require( ownerOf(tokenId) == msg.sender, 'Only owners of horse can call this!' );
        _;
    }

    modifier onlyNonTokenOwner( uint tokenId ) {
        require( ownerOf(tokenId) != msg.sender && ownerOf(tokenId) != nullAddress, 'Non owners of this horse can call this!' );
        _;
    }

    constructor () public { }

    //Bidding Utilities
    /**
    * @dev called by the owner to pause, triggers stopped state of bidding
    */
   function pauseBidding() public onlyCOO whenBiddingActive returns (bool) {
      bidding = false;
      emit BiddingPaused( uint64(now) );
      return true;
   }

   /**
   * @dev called by the owner to unpause, returns to normal state of bidding
   */
    function unpauseBidding() public onlyCOO whenBiddingNotActive returns (bool) {
      bidding = true;
      emit BiddingUnPaused( uint64(now) );
      return true;
    }

    function horseNoLongerForSale(uint tokenId) public whenNotPaused whenBiddingActive onlyTokenOwner(tokenId) {
        horsesOfferedForSale[tokenId] = Offer(false, tokenId, msg.sender, 0, nullAddress);
        emit HorseNoLongerForSale(tokenId, uint64(now));
    }

    function offerHorseForSale(uint tokenId, uint minSalePriceInWei) public whenNotPaused whenBiddingActive onlyTokenOwner(tokenId) {
        horsesOfferedForSale[tokenId] = Offer(true, tokenId, msg.sender, minSalePriceInWei, nullAddress);
        emit HorseOffered(tokenId, minSalePriceInWei, nullAddress, uint64(now) );
    }

    function offerHorseForSaleToAddress(uint tokenId, uint minSalePriceInWei, address toAddress) public whenNotPaused whenBiddingActive onlyTokenOwner(tokenId) {
        horsesOfferedForSale[tokenId] = Offer(true, tokenId, msg.sender, minSalePriceInWei, toAddress);
        emit HorseOffered(tokenId, minSalePriceInWei, toAddress, uint64(now));
    }

    function buyHorseFromOffer(uint tokenId) public whenNotPaused whenBiddingActive payable {
        Offer memory offer = horsesOfferedForSale[tokenId];
        require( offer.isForSale, 'This horse if not for sale!' );
        require( offer.onlySellTo == nullAddress || offer.onlySellTo == msg.sender, "Horse not supposed to be sold to this user!" );
        require( msg.value >= offer.minValue, "Didn't send enough ETH to buy Horse" );
        require( offer.seller == ownerOf(tokenId), "Seller no longer owner of horse" );

        address seller = offer.seller;

        //Transfer horse to new owner
        transferFromOffer( seller, msg.sender, tokenId );

        horseNoLongerForSale( tokenId );
        pendingWithdrawals[seller] += msg.value;

        emit HorseBoughtWithOffer(tokenId, msg.value, seller, msg.sender, uint64(now));

        // Check for the case where there is a bid from the new owner and refund it.
        // Any other bid can stay in place.
        Bid memory bid = horseBids[tokenId];
        if (bid.bidder == msg.sender) {
            // Kill bid and refund value
            pendingWithdrawals[msg.sender] += bid.value;
            horseBids[tokenId] = Bid(false, tokenId, nullAddress, 0);
        }

       deductFees( seller, msg.value ); //Transfer funds
    }

    function enterBidForHorse(uint tokenId) public whenNotPaused whenBiddingActive onlyNonTokenOwner(tokenId) payable {
        Bid memory existing = horseBids[tokenId];
        require (msg.value > existing.value, "Bid value cannot be less than or equal to existing value!");

        if (existing.value > 0) {
            // Refund the failing bid
            pendingWithdrawals[existing.bidder] += existing.value;
        }
        horseBids[tokenId] = Bid(true, tokenId, msg.sender, msg.value);
        emit HorseBidEntered(tokenId, msg.value, msg.sender, uint64(now));
    }

    function acceptBidForHorse(uint tokenId, uint minPrice) public whenNotPaused whenBiddingActive onlyTokenOwner( tokenId ) {
        address seller = msg.sender;
        Bid memory bid = horseBids[tokenId];
        require( bid.value > 0 && bid.value >= minPrice, "Bid value should be greater than or equal to minPrice!" );

        //Transfer horse to new owner
        transferFromOffer( seller, bid.bidder, tokenId );

        horsesOfferedForSale[tokenId] = Offer(false, tokenId, bid.bidder, 0, nullAddress);
        uint amount = bid.value;
        horseBids[tokenId] = Bid(false, tokenId, nullAddress, 0);
        pendingWithdrawals[seller] += amount;

        emit HorseBoughtWithBid(tokenId, bid.value, seller, bid.bidder, uint64(now));

        deductFees(seller, amount); //Transfer funds
    }

    function withdrawBidForHorse(uint tokenId) public whenNotPaused whenBiddingActive onlyNonTokenOwner(tokenId) {
        Bid memory bid = horseBids[tokenId];
        require( bid.bidder == msg.sender, 'Only Bidders can withdraw their bids!' );
        emit HorseBidWithdrawn(tokenId, bid.value, msg.sender, uint64(now));
        uint amount = bid.value;
        horseBids[tokenId] = Bid(false, tokenId, nullAddress, 0);

        // Refund the bid money
        msg.sender.transfer(amount);
    }


    function setSuccessFees( uint256 fees ) public onlyCFO {
      bidSuccessFees = fees;
    }

    function calcFees( uint _amount ) internal view returns(uint) {
        uint fees = (_amount * bidSuccessFees)/100;
        return fees;
    }
    
    function deductFees( address seller, uint amount ) private {
        uint fees = calcFees( amount );
        if( fees > 0 ) {
            cfoAddress.transfer(fees);
            pendingWithdrawals[ seller ] = pendingWithdrawals[ seller ] - fees;
        }
    }

    function withdrawFundsFromBid() public {
        uint amount = pendingWithdrawals[msg.sender];
        // Remember to zero the pending refund before
        // sending to prevent re-entrancy attacks
        pendingWithdrawals[msg.sender] = 0;
        msg.sender.transfer(amount);
    }

}

// File: Context.sol



pragma solidity ^0.5.0;

contract Context {
   constructor () internal { }

    function _msgSender() internal view returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view returns (bytes memory) {
        this;
        return msg.data;
    }
}

interface IERC165 {
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

contract IERC721 is IERC165 {
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
    function balanceOf(address owner) public view returns (uint256 balance);
    function ownerOf(uint256 tokenId) public view returns (address owner);
    function safeTransferFrom(address from, address to, uint256 tokenId) public;
    function transferFrom(address from, address to, uint256 tokenId) public;
    function approve(address to, uint256 tokenId) public;
    function getApproved(uint256 tokenId) public view returns (address operator);
    function setApprovalForAll(address operator, bool _approved) public;
    function isApprovedForAll(address owner, address operator) public view returns (bool);
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
}

contract IERC721Receiver {

    function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
    public returns (bytes4);
}

library SafeMath {

    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        return c;
    }
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

library Counters {
    using SafeMath for uint256;

    struct Counter {
        uint256 _value;
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        counter._value += 1;
    }

    function decrement(Counter storage counter) internal {
        counter._value = counter._value.sub(1);
    }
}

contract ERC165 is IERC165 {
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
    mapping(bytes4 => bool) private _supportedInterfaces;

    constructor () internal {
    }
    function supportsInterface(bytes4 interfaceId) external view returns (bool) {
        return _supportedInterfaces[interfaceId];
    }
    function _registerInterface(bytes4 interfaceId) internal {
        require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
        _supportedInterfaces[interfaceId] = true;
    }
}
// File: CVXBX.sol



pragma solidity ^0.5.0;
import "./BidCVXBX.sol";

contract CVXBX is BidCVXBX {
    string public cavaloxCdn = "https://www.cavalox.eu/erc721/";

    uint[] public r_stallions;
    uint[] public m_stallions;
    uint[] public l_stallions;
    uint[] public mares;

    //Only 39,000 stallions
    
    //3,000 rarest stallions
    uint constant r_TotalStallions = 3000;
    uint constant r_StallionPrice = 2000000000000000000; //Representing 2 eth as a starting price
    uint constant r_incRarestStallionPerFifty = 11; //Representing = 1.1% increase in price per 50 stallions
    
    //9,000 mid-rare stallions
    uint constant m_TotalStallions = 9000;
    uint constant m_StallionPrice = 1250000000000000000; //Representing 1.25 eth as a starting price
    uint constant m_incStallionPerFifty = 9; //Representing = 0.9% increase in price per 50 stallions
    
    //27,000 low-rare
    uint constant l_TotalStallions = 27000;
    uint constant l_stallionPrice = 500000000000000000; //Representing 0.5 eth as a starting price
    uint constant l_incStallionPerFifty = 7; //Representing = 0.7% increase in price per 50 stallions

    //Only 9,000 mares
    uint constant totalMares = 9000;
    uint constant marePrice = 1000000000000000000; //Representing 1eth eth as a starting price
    uint constant incMarePerFifty = 10; //Representing = 1% increase in price per 50 mares
    
    /// @dev The main Horse struct. Every horse in Cavalox is represented by a copy
    ///  of this structure, so great care was taken to ensure that it fits neatly into
    ///  exactly two 256-bit words. Note that the order of the members in this structure
    ///  is important because of the byte-packing rules used by Ethereum.
    ///  Ref: http://solidity.readthedocs.io/en/develop/miscellaneous.html
    struct Horse {
        //TokenUri of the Horse
        string tokenUri;

        // The timestamp from the block when this horse came into existence.
        uint64 birthTime;

        // Type of horse, stallion or mare
        string typeOfHorse;
        
        // SubType of horse, stallion or mare
        uint64 subType;
        
        // Gene of horse
        uint gene;
    }
    
    Horse[] public horses;
    
    constructor() ERC721Full("CVXBX", "ℂℽ") public {}
    
    modifier validRareIndex( uint64 rarityIndex ) {
        require( rarityIndex == 1 || rarityIndex == 2 || rarityIndex == 3 );
        _;
    } 
    
    modifier checkMareCount() {
        uint256 nextMare = getMintedMares().add(1);
        require( nextMare <= totalMares, "Cannot mint more than 9000 mares!");
        _;
    }
    
    modifier checkStallionCount( uint64 rarityIndex ) {
        uint256 nextStallion = getMintedStallions( rarityIndex ).add(1);
        uint256 totalStallions = getTotalStallions( rarityIndex );
        
        require( nextStallion <= totalStallions, "Cannot mint more than available stallions!");
        _;
    }

    /// @notice No tipping!
    /// @dev Reject all Ether from being sent here
    function() external payable {
    }
    
    function geneSequencer() private view returns(uint) {
        uint time = uint(now);
        uint sequence1 = block.difficulty.add(block.number);
        uint sequence2 = time;
        uint sequence = sequence1.add(sequence2);
        
        return sequence;
    }

    function mintHorse( string memory typeOfHorse, address owner, uint64 rarityIndex ) internal returns(uint256) {
        string memory tokenUri = '';
        
        if( keccak256(bytes( typeOfHorse )) == keccak256(bytes('stallion')) ) {
            if( rarityIndex == 1 ) {
                tokenUri =  strConcat( cavaloxCdn, 'horse/r_stallion.png' );
            } else if( rarityIndex == 2 ) {
                tokenUri =  strConcat( cavaloxCdn, 'horse/m_stallion.png' );
            } else if( rarityIndex == 3 ) {
                tokenUri =  strConcat( cavaloxCdn, 'horse/l_stallion.png' );
            }
        } else {
            tokenUri = tokenUri =  strConcat( cavaloxCdn, 'horse/mare.png' );
        }
        
        uint gene = geneSequencer();

        Horse memory _horse = Horse({
            tokenUri: tokenUri,
            birthTime: uint64(now),
            typeOfHorse: typeOfHorse,
            subType: rarityIndex,
            gene: gene
        });

        uint256 _id = horses.push(_horse);

       horseTypes[_id] = typeOfHorse;
       horseSubTypes[_id] = rarityIndex;
       tokenUriMapping[_id] = tokenUri;
        _mint(owner, _id);
        return _id;
    }
    
    function strConcat(string memory _a, string memory _b) internal pure returns (string memory){
        bytes memory _ba = bytes(_a);
        bytes memory _bb = bytes(_b);
        
        string memory abcde = new string(_ba.length + _bb.length);
        bytes memory babcde = bytes(abcde);
        uint k = 0;
        uint i = 0;
        for ( i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
        for (i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
        return string(babcde);
    }
    
    function mintStallionInternally( address owner, uint64 rarityIndex ) internal {
        uint256 _id = mintHorse( 'stallion', owner, rarityIndex );
        if( rarityIndex == 1 ) {
            r_stallions.push(_id);
        } else if( rarityIndex == 2 ) {
            m_stallions.push(_id);
        } else if( rarityIndex == 3 ) {
            l_stallions.push(_id);
        }
    }

    function mintStallion( uint64 rarityIndex ) public whenNotPaused validRareIndex( rarityIndex ) checkStallionCount( rarityIndex ) payable {
        uint256 currentStallionPrice = getStallionPrice( rarityIndex );
        require(msg.value == currentStallionPrice, "Price of stallion not correct!");

        mintStallionInternally( msg.sender, rarityIndex );
        uint256 balance = address(this).balance;
        cfoAddress.transfer(balance);
    }
    
    function getTotalStallions( uint64 rarityIndex ) public pure returns(uint256) {
        uint256 totalStallions = 0;
        
        if( rarityIndex == 1 ) {
            totalStallions = r_TotalStallions;
        } else if( rarityIndex == 2 ) {
            totalStallions = m_TotalStallions;
        } else if( rarityIndex == 3 ) {
            totalStallions = l_TotalStallions;
        }
        
        return totalStallions;
    }
    
    function mintMareInternally( address owner ) internal {
        uint256 _id = mintHorse('mare', owner, 0 );
        mares.push(_id);
    }

    function mintMare() public checkMareCount whenNotPaused payable {
        uint256 currentMarePrice = getMarePrice();
        require(msg.value == currentMarePrice, "Price of mare not correct!");

        mintMareInternally( msg.sender );
        uint256 balance = address(this).balance;
        cfoAddress.transfer(balance);
    }
    
    function getGene(uint n) public view returns ( uint ) {
        return ( horses[n].gene );
    }

    function getMintedStallions( uint64 rarityIndex ) public view validRareIndex( rarityIndex ) returns (uint256) {
        uint256 stallionsLength = 0;
        if( rarityIndex == 1 ) {
            stallionsLength = r_stallions.length;
        } else if( rarityIndex == 2 ) {
            stallionsLength = m_stallions.length;
        } else if( rarityIndex == 3 ) {
            stallionsLength = l_stallions.length;
        }
        return stallionsLength;
    }

    function getMintedMares() public view returns (uint256) {
        return mares.length;
    }
    
    function getIndividualStallionPrice( uint64 rarityIndex ) public pure returns(uint256) {
        uint256 priceStallions = 0;
        
        if( rarityIndex == 1 ) {
            priceStallions = r_StallionPrice;
        } else if( rarityIndex == 2 ) {
            priceStallions = m_StallionPrice;
        } else if( rarityIndex == 3 ) {
            priceStallions = l_stallionPrice;
        }
        
        require( priceStallions > 0, 'Invalid rarityIndex' );
        return priceStallions;
    }
    
    function getIncStallionPerFifty( uint64 rarityIndex ) public pure returns(uint256) {
        uint256 incStallionPerFifty = 0;
        
        if( rarityIndex == 1 ) {
            incStallionPerFifty = r_incRarestStallionPerFifty;
        } else if( rarityIndex == 2 ) {
            incStallionPerFifty = m_incStallionPerFifty;
        } else if( rarityIndex == 3 ) {
            incStallionPerFifty = l_incStallionPerFifty;
        }
        
        require( incStallionPerFifty > 0, 'Invalid rarityIndex' );
        return incStallionPerFifty;
    }

    function getStallionPrice( uint64 rarityIndex ) public view returns (uint256) {
        uint256 mintedStallions = getMintedStallions( rarityIndex ).add(1);
        uint256 stallionPrice = getIndividualStallionPrice( rarityIndex );
        uint256 incStallionPerFifty = getIncStallionPerFifty( rarityIndex );
        
        uint256 price = stallionPrice + ((stallionPrice * incStallionPerFifty)/1000) * (mintedStallions/50);
        return ( price );
    }

    function getMarePrice() public view returns (uint256) {
        uint256 mintedMares = getMintedMares().add(1);
        uint256 price = marePrice + ((marePrice * incMarePerFifty)/1000) * (mintedMares/50);
        return ( price );
    }

    function mFreeStallion(address owner, uint64 rarityIndex) public whenNotPaused onlyCLevel validRareIndex( rarityIndex ) checkStallionCount( rarityIndex ) {
        mintStallionInternally( owner, rarityIndex );
    }
    
    function mFreeMare(address owner) public onlyCLevel checkMareCount {
        mintMareInternally( owner );
    }

    function setCavaloxCdn(string memory cdn) public onlyCEO {
        cavaloxCdn = cdn;
    }
}

// File: ERC721Full.sol



pragma solidity ^0.5.0;
import "./Ownable.sol";
import "./Context.sol";
import "./Pausable.sol";

contract ERC721 is Context, ERC165, IERC721, Pausable {
    using SafeMath for uint256;
    using Counters for Counters.Counter;
    
    event HorseBought(address indexed owner, uint256 indexed tokenId, string horseType, uint64 horseSubType, uint64 birthTime, string tokenUri );
    event HorseTransferred(address indexed from, address indexed to, uint256 indexed tokenId, string horseType, uint64 horseSubType, uint64 birthTime, string tokenUri );
    
    bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
    mapping (uint256 => address) private _tokenOwner;
    mapping (uint256 => address) private _tokenApprovals;
    mapping (address => Counters.Counter) private _ownedTokensCount;
    mapping (address => mapping (address => bool)) private _operatorApprovals;

    mapping(address => Counters.Counter) public r_stallionsCount;
    mapping(address => Counters.Counter) public m_stallionsCount;
    mapping(address => Counters.Counter) public l_stallionsCount;
    mapping(address => Counters.Counter) public maresCount;
    mapping(uint256 => string) public tokenUriMapping;
   
    mapping(uint256 => string) public horseTypes;
    mapping(uint256 => uint64) public horseSubTypes;
    
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

    constructor () public {
        _registerInterface(_INTERFACE_ID_ERC721);
    }
    function balanceOf(address owner) public view returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");

        return _ownedTokensCount[owner].current();
    }
    function ownerOf(uint256 tokenId) public view returns (address) {
        address owner = _tokenOwner[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");

        return owner;
    }
    function approve(address to, uint256 tokenId) public whenNotPaused {
        address owner = ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _tokenApprovals[tokenId] = to;
        emit Approval(owner, to, tokenId);
    }
    function getApproved(uint256 tokenId) public view returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }
    function setApprovalForAll(address to, bool approved) public whenNotPaused {
        require(to != _msgSender(), "ERC721: approve to caller");

        _operatorApprovals[_msgSender()][to] = approved;
        emit ApprovalForAll(_msgSender(), to, approved);
    }
    function isApprovedForAll(address owner, address operator) public view returns (bool) {
        return _operatorApprovals[owner][operator];
    }
    function transferFrom(address from, address to, uint256 tokenId) public whenNotPaused {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

        _transferFrom(from, to, tokenId);
    }
    
    function transferFromOffer(address from, address to, uint256 tokenId) internal whenNotPaused {
        _transferFrom(from, to, tokenId);
    }
    
    function safeTransferFrom(address from, address to, uint256 tokenId) public whenNotPaused {
        safeTransferFrom(from, to, tokenId, "");
    }
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public whenNotPaused {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransferFrom(from, to, tokenId, _data);
    }
    function _safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) internal {
        _transferFrom(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }
    function _exists(uint256 tokenId) internal view returns (bool) {
        address owner = _tokenOwner[tokenId];
        return owner != address(0);
    }
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }
    function _safeMint(address to, uint256 tokenId) internal {
        _safeMint(to, tokenId, "");
    }
    function _safeMint(address to, uint256 tokenId, bytes memory _data) internal {
        _mint(to, tokenId);
        require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }
    function _mint(address to, uint256 tokenId) internal {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _tokenOwner[tokenId] = to;
        _ownedTokensCount[to].increment();

        if( keccak256(bytes(horseTypes[tokenId])) == keccak256(bytes('stallion')) ) {
            if( horseSubTypes[tokenId] == 1 ) {
                r_stallionsCount[to].increment();
            } else if( horseSubTypes[tokenId] == 2 ) {
                m_stallionsCount[to].increment();
            } else if( horseSubTypes[tokenId] == 3 ) {
                l_stallionsCount[to].increment();
            }
          emit HorseBought( to, tokenId, 'stallion', horseSubTypes[tokenId], uint64(now), tokenUriMapping[tokenId] );
        } else {
          maresCount[to].increment();
          emit HorseBought( to, tokenId, 'mare', 0, uint64(now), tokenUriMapping[tokenId] );
        }

        emit Transfer(address(0), to, tokenId);
    }

    function _transferFrom(address from, address to, uint256 tokenId) internal {
        require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _clearApproval(tokenId);

        _ownedTokensCount[from].decrement();
        _ownedTokensCount[to].increment();

        _tokenOwner[tokenId] = to;

        if( keccak256(bytes(horseTypes[tokenId])) == keccak256(bytes('stallion')) ) {
          if( horseSubTypes[tokenId] == 1 ) {
              r_stallionsCount[from].decrement();
              r_stallionsCount[to].increment();
           } else if( horseSubTypes[tokenId] == 2 ) {
              m_stallionsCount[from].decrement();
              m_stallionsCount[to].increment();
           } else if( horseSubTypes[tokenId] == 3 ) {
              l_stallionsCount[from].decrement();
              l_stallionsCount[to].increment();
           }
          
          emit HorseTransferred( from, to, tokenId, 'stallion', horseSubTypes[tokenId], uint64(now), tokenUriMapping[tokenId] );
          
        } else {
          maresCount[from].decrement();
          maresCount[to].increment();
          
          emit HorseTransferred( from, to, tokenId, 'mare', 0, uint64(now), tokenUriMapping[tokenId] );
        }

        emit Transfer(from, to, tokenId);
    }

    function isContract(address account) internal view returns (bool) {
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
        internal returns (bool) {
        if ( isContract(to) ) {
            return true;
        }
        (bool success, bytes memory returndata) = to.call(abi.encodeWithSelector(
            IERC721Receiver(to).onERC721Received.selector,
            _msgSender(),
            from,
            tokenId,
            _data
        ));
        if (!success) {
            if (returndata.length > 0) {
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert("ERC721: transfer to non ERC721Receiver implementer");
            }
        } else {
            bytes4 retval = abi.decode(returndata, (bytes4));
            return (retval == _ERC721_RECEIVED);
        }
    }
    function _clearApproval(uint256 tokenId) private {
        if (_tokenApprovals[tokenId] != address(0)) {
            _tokenApprovals[tokenId] = address(0);
        }
    }
}
contract IERC721Enumerable is IERC721 {
    function totalSupply() public view returns (uint256);
    function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256 tokenId);

    function tokenByIndex(uint256 index) public view returns (uint256);
}
contract ERC721Enumerable is Context, ERC165, ERC721, IERC721Enumerable {
    mapping(address => uint256[]) private _ownedTokens;
    mapping(uint256 => uint256) private _ownedTokensIndex;
    uint256[] private _allTokens;
    mapping(uint256 => uint256) private _allTokensIndex;
    bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;
    constructor () public {
        _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
    }
    function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) {
        require(index < balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
        return _ownedTokens[owner][index];
    }
    function totalSupply() public view returns (uint256) {
        return _allTokens.length;
    }
    function tokenByIndex(uint256 index) public view returns (uint256) {
        require(index < totalSupply(), "ERC721Enumerable: global index out of bounds");
        return _allTokens[index];
    }
    function _transferFrom(address from, address to, uint256 tokenId) internal {
        super._transferFrom(from, to, tokenId);

        _removeTokenFromOwnerEnumeration(from, tokenId);

        _addTokenToOwnerEnumeration(to, tokenId);
    }
    function _mint(address to, uint256 tokenId) internal {
        super._mint(to, tokenId);

        _addTokenToOwnerEnumeration(to, tokenId);

        _addTokenToAllTokensEnumeration(tokenId);
    }

    function _tokensOfOwner(address owner) internal view returns (uint256[] storage) {
        return _ownedTokens[owner];
    }
    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
        _ownedTokensIndex[tokenId] = _ownedTokens[to].length;
        _ownedTokens[to].push(tokenId);
    }
    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
        _allTokensIndex[tokenId] = _allTokens.length;
        _allTokens.push(tokenId);
    }
    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
        uint256 lastTokenIndex = _ownedTokens[from].length.sub(1);
        uint256 tokenIndex = _ownedTokensIndex[tokenId];
        if (tokenIndex != lastTokenIndex) {
            uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];

            _ownedTokens[from][tokenIndex] = lastTokenId;
            _ownedTokensIndex[lastTokenId] = tokenIndex;
        }
        _ownedTokens[from].length--;
    }
    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
        uint256 lastTokenIndex = _allTokens.length.sub(1);
        uint256 tokenIndex = _allTokensIndex[tokenId];
        uint256 lastTokenId = _allTokens[lastTokenIndex];

        _allTokens[tokenIndex] = lastTokenId;
        _allTokensIndex[lastTokenId] = tokenIndex;
        _allTokens.length--;
        _allTokensIndex[tokenId] = 0;
    }
}


contract IERC721Metadata is IERC721 {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata {
    string private _name;
    string private _symbol;
    string private _baseURI;
    bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
    
    constructor (string memory name, string memory symbol) public {
        _name = name;
        _symbol = symbol;

        _registerInterface(_INTERFACE_ID_ERC721_METADATA);
    }

    function name() external view returns (string memory) {
        return _name;
    }
    function symbol() external view returns (string memory) {
        return _symbol;
    }
    function tokenURI(uint256 tokenId) external view returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory _tokenURI = tokenUriMapping[tokenId];
        if (bytes(_tokenURI).length == 0) {
            return "";
        } else {
            return string(abi.encodePacked(_baseURI, _tokenURI));
        }
    }
    function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal {
        require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
        tokenUriMapping[tokenId] = _tokenURI;
    }
    function _setBaseURI(string memory baseURI) internal {
        _baseURI = baseURI;
    }
    function baseURI() external view returns (string memory) {
        return _baseURI;
    }
}
contract ERC721Full is ERC721, ERC721Enumerable, ERC721Metadata {
    constructor (string memory name, string memory symbol) public ERC721Metadata(name, symbol) {
        // solhint-disable-previous-line no-empty-blocks
    }
}

// File: Migrations.sol



// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

contract Migrations {
  address public owner = msg.sender;
  uint public last_completed_migration;

  modifier restricted() {
    require(
      msg.sender == owner,
      "This function is restricted to the contract's owner"
    );
    _;
  }

  function setCompleted(uint completed) public restricted {
    last_completed_migration = completed;
  }
}

// File: Ownable.sol



pragma solidity ^0.5.0;

/**
 * @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 private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () public {
        address msgSender = msg.sender;
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _owner, "Ownable: caller is not the owner");
        _;
    }
}

// File: Pausable.sol



import "./Ownable.sol";

pragma solidity ^0.5.0;

/**
 * @title Pausable
 * @dev Base contract which allows children to implement an emergency stop mechanism.
 */
contract Pausable is Ownable {
  event Pause( uint64 timestamp );
  event Unpause( uint64 timestamp );

  bool public paused = false;


  /**
   * @dev modifier to allow actions only when the contract IS paused
   */
  modifier whenNotPaused() {
    require(!paused, 'CVXBX is currently paused!');
    _;
  }

  /**
   * @dev modifier to allow actions only when the contract IS NOT paused
   */
  modifier whenPaused {
    require(paused, 'CVXBX is not paused!');
    _;
  }

  /**
   * @dev called by the owner to pause, triggers stopped state
   */
  function pause() public onlyOwner whenNotPaused returns (bool) {
    paused = true;
    emit Pause( uint64(now) );
    return true;
  }

  /**
   * @dev called by the owner to unpause, returns to normal state
   */
  function unpause() public onlyOwner whenPaused returns (bool) {
    paused = false;
    emit Unpause( uint64(now) );
    return true;
  }
}