ETH Price: $1,951.49 (-1.68%)

Transaction Decoder

Block:
14072885 at Jan-25-2022 05:27:06 AM +UTC
Transaction Fee:
0.05647023215749935 ETH $110.20
Gas Used:
491,682 Gas / 114.851127675 Gwei

Emitted Events:

189 MoonCatAccessories.AccessoryPurchased( accessoryId=1109, rescueOrder=3470, price=200000000000000000 )
190 MoonCatAccessories.AccessoryApplied( accessoryId=1109, rescueOrder=3470, paletteIndex=0, zIndex=32768 )
191 MoonCatAccessories.AccessoryPurchased( accessoryId=1109, rescueOrder=6083, price=200000000000000000 )
192 MoonCatAccessories.AccessoryApplied( accessoryId=1109, rescueOrder=6083, paletteIndex=0, zIndex=32768 )

Account State Difference:

  Address   Before After State Difference Code
0x0aF6Ce7E...C6FAaf735 3.54242971476508373 Eth3.62242971476508373 Eth0.08
(AntPool 2)
2,429.227218070923216235 Eth2,429.227955593923216235 Eth0.000737523
0x8d333030...90e747C63
(Acclimated Moon Cat: Accessories)
0xb6B4979B...3EeB078EB
1.252152190351557114 Eth
Nonce: 832
0.795681958194057764 Eth
Nonce: 833
0.45647023215749935
0xb8d646F0...49f61d8a8 0.52808544920209778 Eth0.84808544920209778 Eth0.32

Execution Trace

ETH 0.4 MoonCatAccessories.buyAccessories( orders= )
  • MoonCatRescue.rescueOrder( 3470 ) => ( System.Byte[] )
  • MoonCatRescue.catOwners( System.Byte[] ) => ( 0xc3f733ca98E0daD0386979Eb96fb1722A1A05E69 )
  • MoonCatAcclimator.ownerOf( _tokenId=3470 ) => ( 0xb6B4979Bc057742b61320A061a09A743EeB078EB )
  • ETH 0.04 0x0af6ce7e6c65cca42f651a3b6752642c6faaf735.CALL( )
  • 0x0af6ce7e6c65cca42f651a3b6752642c6faaf735.CALL( )
  • ETH 0.16 0xb8d646f094ed6c6b6a790d9ec3acf0e49f61d8a8.CALL( )
  • MoonCatRescue.rescueOrder( 6083 ) => ( System.Byte[] )
  • MoonCatRescue.catOwners( System.Byte[] ) => ( 0xc3f733ca98E0daD0386979Eb96fb1722A1A05E69 )
  • MoonCatAcclimator.ownerOf( _tokenId=6083 ) => ( 0xb6B4979Bc057742b61320A061a09A743EeB078EB )
  • ETH 0.04 0x0af6ce7e6c65cca42f651a3b6752642c6faaf735.CALL( )
  • 0x0af6ce7e6c65cca42f651a3b6752642c6faaf735.CALL( )
  • ETH 0.16 0xb8d646f094ed6c6b6a790d9ec3acf0e49f61d8a8.CALL( )
    File 1 of 3: MoonCatAccessories
    // SPDX-License-Identifier: AGPL-3.0
    
    pragma solidity 0.8.1;
    
    interface IMoonCatAcclimator {
        function getApproved(uint256 tokenId) external view returns (address);
        function isApprovedForAll(address owner, address operator) external view returns (bool);
        function ownerOf(uint256 tokenId) external view returns (address);
    }
    
    interface IMoonCatRescue {
        function rescueOrder(uint256 tokenId) external view returns (bytes5);
        function catOwners(bytes5 catId) external view returns (address);
    }
    
    interface IReverseResolver {
        function claim(address owner) external returns (bytes32);
    }
    
    interface IERC20 {
        function balanceOf(address account) external view returns (uint256);
        function transfer(address recipient, uint256 amount) external returns (bool);
    }
    interface IERC721 {
        function safeTransferFrom(address from, address to, uint256 tokenId) external;
    }
    
    /**
     * @dev Derived from OpenZeppelin standard template
     * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/EnumerableSet.sol
     * b0cf6fbb7a70f31527f36579ad644e1cf12fdf4e
     */
    library EnumerableSet {
        struct Set {
            uint256[] _values;
            mapping (uint256 => uint256) _indexes;
        }
    
        function at(Set storage set, uint256 index) internal view returns (uint256) {
            return set._values[index];
        }
    
        function contains(Set storage set, uint256 value) internal view returns (bool) {
            return set._indexes[value] != 0;
        }
    
        function length(Set storage set) internal view returns (uint256) {
            return set._values.length;
        }
    
        function add(Set storage set, uint256 value) internal returns (bool) {
            if (!contains(set, value)) {
                set._values.push(value);
                // The value is stored at length-1, but we add 1 to all indexes
                // and use 0 as a sentinel value
                set._indexes[value] = set._values.length;
                return true;
            } else {
                return false;
            }
        }
    
        function remove(Set storage set, uint256 value) internal returns (bool) {
            // We read and store the value's index to prevent multiple reads from the same storage slot
            uint256 valueIndex = set._indexes[value];
            if (valueIndex != 0) { // Equivalent to contains(set, value)
                // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                // the array, and then remove the last element (sometimes called as 'swap and pop').
                // This modifies the order of the array, as noted in {at}.
                uint256 toDeleteIndex = valueIndex - 1;
                uint256 lastIndex = set._values.length - 1;
                if (lastIndex != toDeleteIndex) {
                    uint256 lastvalue = set._values[lastIndex];
                    // Move the last value to the index where the value to delete is
                    set._values[toDeleteIndex] = lastvalue;
                    // Update the index for the moved value
                    set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex
                }
    
                // Delete the slot where the moved value was stored
                set._values.pop();
                // Delete the index for the deleted slot
                delete set._indexes[value];
                return true;
            } else {
                return false;
            }
        }
    }
    
    library MoonCatBitSet {
    
        bytes32 constant Mask =  0x0000000000000000000000000000000000000000000000000000000000000001;
    
        function activate(bytes32[100] storage set)
            internal
        {
            set[99] |= Mask;
        }
    
        function deactivate(bytes32[100] storage set)
            internal
        {
            set[99] &= ~Mask;
        }
    
        function setBit(bytes32[100] storage set, uint16 index)
            internal
        {
            uint16 wordIndex = index / 256;
            uint16 bitIndex = index % 256;
            bytes32 mask = Mask << (255 - bitIndex);
            set[wordIndex] |= mask;
        }
    
        function clearBit(bytes32[100] storage set, uint16 index)
            internal
        {
            uint16 wordIndex = index / 256;
            uint16 bitIndex = index % 256;
            bytes32 mask = ~(Mask << (255 - bitIndex));
            set[wordIndex] &= mask;
        }
    
        function checkBit(bytes32[100] memory set, uint256 index)
            internal
            pure
            returns (bool)
        {
            uint256 wordIndex = index / 256;
            uint256 bitIndex = index % 256;
            bytes32 mask = Mask << (255 - bitIndex);
            return (mask & set[wordIndex]) != 0;
        }
    
        function isActive(bytes32[100] memory set)
            internal
            pure
            returns (bool)
        {
            return (Mask & set[99]) == Mask;
        }
    }
    
    
    /**
     * @title MoonCat​Accessories
     * @notice Public MoonCat Wearables infrastructure/protocols
     * @dev Allows wearable-designers to create accessories for sale and gifting.
     */
    contract MoonCatAccessories {
    
        /* External Contracts */
    
        IMoonCatAcclimator MCA = IMoonCatAcclimator(0xc3f733ca98E0daD0386979Eb96fb1722A1A05E69);
        IMoonCatRescue MCR = IMoonCatRescue(0x60cd862c9C687A9dE49aecdC3A99b74A4fc54aB6);
    
        /* Events */
    
        event AccessoryCreated(uint256 accessoryId, address creator, uint256 price, uint16 totalSupply, bytes30 name);
        event AccessoryManagementTransferred(uint256 accessoryId, address newManager);
        event AccessoryPriceChanged(uint256 accessoryId, uint256 price);
        event AccessoryPurchased(uint256 accessoryId, uint256 rescueOrder, uint256 price);
        event AccessoryApplied(uint256 accessoryId, uint256 rescueOrder, uint8 paletteIndex, uint16 zIndex);
        event AccessoryDiscontinued(uint256 accessoryId);
    
        event EligibleListSet(uint256 accessoryId);
        event EligibleListCleared(uint256 accessoryId);
    
        /* Structs */
    
        struct Accessory {            // Accessory Definition
            address payable manager;  // initially creator; payee for sales
            uint8 width;              // image width
            uint8 height;             // image height
            uint8 meta;               // metadata flags [Reserved 3b, Audience 2b, MirrorPlacement 1b, MirrorAccessory 1b, Background 1b]
            uint72 price;             // price at which accessory can be purchased (MAX ~4,722 ETH)
                                      // if set to max value, the accessory is not for sale
    
            uint16 totalSupply;      // total number of a given accessory that will ever exist; can only be changed by discontinuing the accessory
            uint16 availableSupply;  // number of given accessory still available for sale; decremented on each sale
            bytes28 name;            // unicode name of accessory, can only be set on creation
    
            bytes8[7] palettes;     // color palettes, each palette is an array of uint8 offsets into the global palette
            bytes2[4] positions;    // offsets for all 4 MoonCat poses, an offset pair of 0xffff indicates the pose is not supported
                                    // position order is [standing, sleeping, pouncing, stalking]
    
            bytes IDAT;            // PNG IDAT chunk data for image reconstruction
        }
    
        struct OwnedAccessory {   // Accessory owned by an AcclimatedMoonCat
            uint232 accessoryId;  // index into AllAccessories Array
            uint8 paletteIndex;   // index into Accessory.palettes Array
            uint16 zIndex;        // drawing order indicator (lower numbers are closer to MoonCat)
                                  // zIndex == 0 indicates the MoonCat is not wearing the accessory
                                  // if the accessory meta `Background` bit is 1 the zIndex is interpreted as negative
        }
    
        struct AccessoryBatchData {   // Used for batch accessory alterations and purchases
            uint256 rescueOrder;
            uint232 ownedIndexOrAccessoryId;
            uint8 paletteIndex;
            uint16 zIndex;
        }
    
        using EnumerableSet for EnumerableSet.Set;
    
        /* State */
    
        bool public frozen = true;
    
        Accessory[] internal AllAccessories; //  Array of all Accessories that have been created
        mapping (uint256 => bytes32[100]) internal AllEligibleLists; // Accessory ID => BitSet
                                                                     // Each bit represents the eligbility of an AcclimatedMoonCat
                                                                     // An eligibleList is active when the final bit == 1
    
        mapping (address => EnumerableSet.Set) internal AccessoriesByManager; // Manager address => accessoryId Set
    
        mapping (uint256 => mapping(uint256 => bool)) internal OwnedAccessoriesByMoonCat; // AcclimatedMoonCat rescueOrder => Accessory ID => isOwned?
        mapping (uint256 => OwnedAccessory[]) public AccessoriesByMoonCat; // AcclimatedMoonCat rescueOrder => Array of AppliedAccessory structs
    
        mapping (bytes32 => bool) public accessoryHashes; // used to check if the image data for an accessory has already been submitted
    
        address payable public owner;
    
        uint72 constant NOT_FOR_SALE = 0xffffffffffffffffff;
    
        uint256 public feeDenominator = 5;
        uint256 public referralDenominator = 0;
    
        /* Modifiers */
    
        modifier onlyOwner () {
            require(msg.sender == owner, "Only Owner");
            _;
        }
    
        modifier accessoryExists (uint256 accessoryId){
            require(accessoryId < AllAccessories.length, "Accessory Not Found");
            _;
        }
    
        modifier onlyAccessoryManager (uint256 accessoryId) {
            require(msg.sender == AllAccessories[accessoryId].manager, "Not Accessory Manager");
            _;
        }
    
        modifier onlyAMCOwner (uint256 rescueOrder) {
            require(MCR.catOwners(MCR.rescueOrder(rescueOrder)) == 0xc3f733ca98E0daD0386979Eb96fb1722A1A05E69,
                    "Not Acclimated");
            address moonCatOwner = MCA.ownerOf(rescueOrder);
            require((msg.sender == moonCatOwner)
                || (msg.sender == MCA.getApproved(rescueOrder))
                || (MCA.isApprovedForAll(moonCatOwner, msg.sender)),
                "Not AMC Owner or Approved"
            );
            _;
        }
    
        modifier notZeroAddress (address a){
            require(a != address(0), "Zero Address");
            _;
        }
    
        modifier notFrozen () {
            require(!frozen, "Frozen");
            _;
        }
    
        modifier validPrice(uint256 price) {
            require(price <= NOT_FOR_SALE, "Invalid Price");
            _;
        }
    
        /* Admin */
    
        constructor(){
            owner = payable(msg.sender);
    
            // https://docs.ens.domains/contract-api-reference/reverseregistrar#claim-address
            IReverseResolver(0x084b1c3C81545d370f3634392De611CaaBFf8148)
                .claim(msg.sender);
        }
    
        /**
         * @dev Transfer funds from the contract's wallet to an external wallet, minus a fee
         */
        function sendPayment (address payable target, uint256 amount, address payable referrer)
            internal
        {
            uint256 fee = (feeDenominator > 0) ? (amount / feeDenominator) : 0;
            uint256 referral = (referralDenominator > 0) ? (fee / referralDenominator) : 0;
            fee = fee - referral;
            uint256 payment = amount - fee - referral;
            owner.transfer(fee);
            referrer.transfer(referral);
            target.transfer(payment);
        }
    
        /**
         * @dev Update the amount of fee taken from each sale
         */
        function setFee (uint256 denominator)
            public
            onlyOwner
        {
            feeDenominator = denominator;
        }
    
        /**
         * @dev Update the amount of referral fee taken from each sale
         */
        function setReferralFee (uint256 denominator)
            public
            onlyOwner
        {
            referralDenominator = denominator;
        }
    
        /**
         * @dev Allow current `owner` to transfer ownership to another address
         */
        function transferOwnership (address payable newOwner)
            public
            onlyOwner
        {
            owner = newOwner;
        }
    
        /**
         * @dev Prevent creating and applying accessories
         */
        function freeze ()
            public
            onlyOwner
            notFrozen
        {
            frozen = true;
        }
    
        /**
         * @dev Enable creating and applying accessories
         */
        function unfreeze ()
            public
            onlyOwner
        {
            frozen = false;
        }
    
        /**
         * @dev Update the metadata flags for an accessory
         */
        function setMetaByte (uint256 accessoryId, uint8 metabyte)
            public
            onlyOwner
            accessoryExists(accessoryId)
        {
            Accessory storage accessory = AllAccessories[accessoryId];
            accessory.meta = metabyte;
        }
    
        /**
         * @dev Batch-update metabytes for accessories, by ensuring given bits are on
         */
        function batchOrMetaByte (uint8 value, uint256[] calldata accessoryIds)
            public
            onlyOwner
        {
            uint256 id;
            Accessory storage accessory;
            for(uint256 i = 0; i < accessoryIds.length; i++){
                id = accessoryIds[i];
                if(i < AllAccessories.length){
                    accessory = AllAccessories[id];
                    accessory.meta = accessory.meta | value;
                }
            }
        }
    
        /**
         * @dev Batch-update metabytes for accessories, by ensuring given bits are off
         */
        function batchAndMetaByte (uint8 value, uint256[] calldata accessoryIds)
            public
            onlyOwner
        {
            uint256 id;
            Accessory storage accessory;
            for(uint256 i = 0; i < accessoryIds.length; i++){
                id = accessoryIds[i];
                if(i < AllAccessories.length){
                    accessory = AllAccessories[id];
                    accessory.meta = accessory.meta & value;
                }
            }
        }
    
        /**
         * @dev Rescue ERC20 assets sent directly to this contract.
         */
        function withdrawForeignERC20(address tokenContract)
            public
            onlyOwner
        {
            IERC20 token = IERC20(tokenContract);
            token.transfer(owner, token.balanceOf(address(this)));
        }
    
        /**
         * @dev Rescue ERC721 assets sent directly to this contract.
         */
        function withdrawForeignERC721(address tokenContract, uint256 tokenId)
            public
            onlyOwner
        {
            IERC721(tokenContract).safeTransferFrom(address(this), owner, tokenId);
        }
    
        /**
         * @dev Check if a MoonCat is eligible to purchase an accessory
         */
        function isEligible(uint256 rescueOrder, uint256 accessoryId)
            public
            view
            returns (bool)
        {
            if(MoonCatBitSet.isActive(AllEligibleLists[accessoryId])) {
                return MoonCatBitSet.checkBit(AllEligibleLists[accessoryId], rescueOrder);
            }
            return true;
        }
    
        /* Helpers */
    
        /**
         * @dev Mark an accessory as owned by a specific MoonCat, and put it on
         *
         * This is an internal function that only does sanity-checking (prevent double-buying an accessory, and prevent picking an invalid palette).
         * All methods that use this function check permissions before calling this function.
         */
        function applyAccessory (uint256 rescueOrder, uint256 accessoryId, uint8 paletteIndex, uint16 zIndex)
            private
            accessoryExists(accessoryId)
            notFrozen
            returns (uint256)
        {
            require(OwnedAccessoriesByMoonCat[rescueOrder][accessoryId] == false, "Already Owned");
            require(uint64(AllAccessories[accessoryId].palettes[paletteIndex]) != 0, "Invalid Palette");
            OwnedAccessory[] storage ownedAccessories = AccessoriesByMoonCat[rescueOrder];
            uint256 ownedAccessoryIndex = ownedAccessories.length;
            ownedAccessories.push(OwnedAccessory(uint232(accessoryId), paletteIndex, zIndex));
            OwnedAccessoriesByMoonCat[rescueOrder][accessoryId] = true;
            emit AccessoryApplied(accessoryId, rescueOrder, paletteIndex, zIndex);
            return ownedAccessoryIndex;
        }
    
        /**
         * @dev Ensure an accessory's image data has not been submitted before
         */
        function verifyAccessoryUniqueness(bytes calldata IDAT)
            internal
        {
            bytes32 accessoryHash = keccak256(IDAT);
            require(!accessoryHashes[accessoryHash], "Duplicate");
            accessoryHashes[accessoryHash] = true;
        }
    
        /* Creator */
    
        /**
         * @dev Create an accessory, as the contract owner
         *
         * This method allows the contract owner to deploy accessories on behalf of others. It also allows deploying
         * accessories that break some of the rules:
         *
         * This method can be called when frozen, so the owner can add to the store even when others cannot.
         * This method does not check for duplicates, so if an accessory creator wants to make a literal duplicate, that can be facilitated.
         */
        function ownerCreateAccessory(address payable manager, uint8[3] calldata WHM, uint256 priceWei, uint16 totalSupply, bytes28 name, bytes2[4] calldata positions, bytes8[7] calldata initialPalettes, bytes calldata IDAT)
            public
            onlyOwner
            returns (uint256)
        {
            uint256 accessoryId = AllAccessories.length;
            AllAccessories.push(Accessory(manager, WHM[0], WHM[1], WHM[2], uint72(priceWei), totalSupply, totalSupply, name, initialPalettes, positions, IDAT));
    
            bytes32 accessoryHash = keccak256(IDAT);
            accessoryHashes[accessoryHash] = true;
    
            emit AccessoryCreated(accessoryId, manager, priceWei, totalSupply, name);
            AccessoriesByManager[manager].add(accessoryId);
            return accessoryId;
        }
    
        /**
         * @dev Create an accessory with an eligible list, as the contract owner
         */
        function ownerCreateAccessory(address payable manager, uint8[3] calldata WHM, uint256 priceWei, uint16 totalSupply, bytes28 name, bytes2[4] calldata positions, bytes8[7] calldata initialPalettes, bytes calldata IDAT, bytes32[100] calldata eligibleList)
            public
            onlyOwner
            returns (uint256)
        {
            uint256 accessoryId = ownerCreateAccessory(manager, WHM, priceWei, totalSupply, name, positions, initialPalettes, IDAT);
            AllEligibleLists[accessoryId] = eligibleList;
            MoonCatBitSet.activate(AllEligibleLists[accessoryId]);
            return accessoryId;
        }
    
        /**
         * @dev Create an accessory
         */
        function createAccessory (uint8[3] calldata WHM, uint256 priceWei, uint16 totalSupply, bytes28 name, bytes2[4] calldata positions, bytes8[] calldata palettes, bytes calldata IDAT)
            public
            notFrozen
            validPrice(priceWei)
            returns (uint256)
        {
            require(palettes.length <= 7 && palettes.length > 0, "Invalid Palette Count");
            require(totalSupply > 0 && totalSupply <= 25440, "Invalid Supply");
            require(WHM[0] > 0 && WHM[1] > 0, "Invalid Dimensions");
            verifyAccessoryUniqueness(IDAT);
            uint256 accessoryId = AllAccessories.length;
            bytes8[7] memory initialPalettes;
            for(uint i = 0; i < palettes.length; i++){
                require(uint64(palettes[i]) != 0, "Invalid Palette");
                initialPalettes[i] = palettes[i];
            }
            AllAccessories.push(Accessory(payable(msg.sender), WHM[0], WHM[1], WHM[2] & 0x1f, uint72(priceWei), totalSupply, totalSupply, name, initialPalettes, positions, IDAT));
            //                                                                        ^ Clear reserved bits
            emit AccessoryCreated(accessoryId, msg.sender, priceWei, totalSupply, name);
            AccessoriesByManager[msg.sender].add(accessoryId);
            return accessoryId;
        }
    
        /**
         * @dev Create an accessory with an eligible list
         */
        function createAccessory (uint8[3] calldata WHM, uint256 priceWei, uint16 totalSupply, bytes28 name, bytes2[4] calldata positions, bytes8[] calldata palettes, bytes calldata IDAT, bytes32[100] calldata eligibleList)
            public
            returns (uint256)
        {
            uint256 accessoryId = createAccessory(WHM, priceWei, totalSupply, name, positions, palettes, IDAT);
            AllEligibleLists[accessoryId] = eligibleList;
            MoonCatBitSet.activate(AllEligibleLists[accessoryId]);
            return accessoryId;
        }
    
        /**
         * @dev Add a color palette variant to an existing accessory
         */
        function addAccessoryPalette (uint256 accessoryId, bytes8 newPalette)
            public
            onlyAccessoryManager(accessoryId)
        {
            require(uint64(newPalette) != 0, "Invalid Palette");
            Accessory storage accessory = AllAccessories[accessoryId];
            bytes8[7] storage accessoryPalettes = accessory.palettes;
    
            require(uint64(accessoryPalettes[6]) == 0, "Palette Limit Exceeded");
            uint paletteIndex = 1;
            while(uint64(accessoryPalettes[paletteIndex]) > 0){
                paletteIndex++;
            }
            accessoryPalettes[paletteIndex] = newPalette;
        }
    
        /**
         * @dev Give ownership of an accessory to someone else
         */
        function transferAccessoryManagement (uint256 accessoryId, address payable newManager)
            public
            onlyAccessoryManager(accessoryId)
            notZeroAddress(newManager)
        {
            Accessory storage accessory = AllAccessories[accessoryId];
            AccessoriesByManager[accessory.manager].remove(accessoryId);
            AccessoriesByManager[newManager].add(accessoryId);
            accessory.manager = newManager;
            emit AccessoryManagementTransferred(accessoryId, newManager);
        }
    
        /**
         * @dev Set accessory to have a new price
         */
        function setAccessoryPrice (uint256 accessoryId, uint256 newPriceWei)
            public
            onlyAccessoryManager(accessoryId)
            validPrice(newPriceWei)
        {
            Accessory storage accessory = AllAccessories[accessoryId];
    
            if(accessory.price != newPriceWei){
                accessory.price = uint72(newPriceWei);
                emit AccessoryPriceChanged(accessoryId, newPriceWei);
            }
        }
    
        /**
         * @dev Set accessory eligible list
         */
        function setEligibleList (uint256 accessoryId, bytes32[100] calldata eligibleList)
            public
            onlyAccessoryManager(accessoryId)
        {
            AllEligibleLists[accessoryId] = eligibleList;
            MoonCatBitSet.activate(AllEligibleLists[accessoryId]);
            emit EligibleListSet(accessoryId);
        }
    
        /**
         * @dev Clear accessory eligible list
         */
        function clearEligibleList (uint256 accessoryId)
            public
            onlyAccessoryManager(accessoryId)
        {
            delete AllEligibleLists[accessoryId];
            emit EligibleListCleared(accessoryId);
        }
    
        /**
         * @dev Turns eligible list on or off without setting/clearing
         */
        function toggleEligibleList (uint256 accessoryId, bool active)
            public
            onlyAccessoryManager(accessoryId)
        {
            bool isActive = MoonCatBitSet.isActive(AllEligibleLists[accessoryId]);
            if(isActive && !active) {
                MoonCatBitSet.deactivate(AllEligibleLists[accessoryId]);
                emit EligibleListCleared(accessoryId);
            } else if (!isActive && active){
                MoonCatBitSet.activate(AllEligibleLists[accessoryId]);
                emit EligibleListSet(accessoryId);
            }
        }
    
        /**
         * @dev Add/Remove individual rescueOrders from an eligibleSet
         */
        function editEligibleMoonCats(uint256 accessoryId, bool targetState, uint16[] calldata rescueOrders)
            public
            onlyAccessoryManager(accessoryId)
        {
            bytes32[100] storage eligibleList = AllEligibleLists[accessoryId];
            for(uint i = 0; i < rescueOrders.length; i++){
                require(rescueOrders[i] < 25440, "Out of bounds");
                if(targetState) {
                    MoonCatBitSet.setBit(eligibleList, rescueOrders[i]);
                } else {
                    MoonCatBitSet.clearBit(eligibleList, rescueOrders[i]);
                }
            }
            if(MoonCatBitSet.isActive(eligibleList)){
                emit EligibleListSet(accessoryId);
            }
        }
    
        /**
         * @dev Buy an accessory as the manager of that accessory
         *
         * Accessory managers always get charged zero cost for buying/applying their own accessories,
         * and always bypass the EligibleList (if there is any).
         *
         * A purchase by the accessory manager still reduces the available supply of an accessory, and
         * the Manager must be the owner of or be granted access to the MoonCat to which the accessory
         * is being applied.
         */
        function managerApplyAccessory (uint256 rescueOrder, uint256 accessoryId, uint8 paletteIndex, uint16 zIndex)
            public
            onlyAccessoryManager(accessoryId)
            onlyAMCOwner(rescueOrder)
            returns (uint256)
        {
            require(AllAccessories[accessoryId].availableSupply > 0, "Supply Exhausted");
            AllAccessories[accessoryId].availableSupply--;
            return applyAccessory(rescueOrder, accessoryId, paletteIndex, zIndex);
        }
    
        /**
         * @dev Remove accessory from the market forever by transferring
         * management to the zero address, setting it as not for sale, and
         * setting the total supply to the current existing quantity.
         */
        function discontinueAccessory (uint256 accessoryId)
            public
            onlyAccessoryManager(accessoryId)
        {
            Accessory storage accessory = AllAccessories[accessoryId];
            accessory.price = NOT_FOR_SALE;
            AccessoriesByManager[accessory.manager].remove(accessoryId);
            AccessoriesByManager[address(0)].add(accessoryId);
            accessory.manager = payable(address(0));
            accessory.totalSupply = accessory.totalSupply - accessory.availableSupply;
            accessory.availableSupply = 0;
            emit AccessoryDiscontinued(accessoryId);
        }
    
        /* User */
    
        /**
         * @dev Purchase and apply an accessory in a standard manner.
         *
         * This method is an internal method for doing standard permission checks before calling the applyAccessory function.
         * This method checks that an accessory is set to be allowed for sale (not set to the max price), that there's enough supply left,
         * and that the buyer has supplied enough ETH to satisfy the price of the accessory.
         *
         * In addition, it checks to ensure that the MoonCat receiving the accessory is owned by the address making this purchase,
         * and that the MoonCat purchasing the accessory is on the Eligible List for that accessory.
         */
        function buyAndApplyAccessory (uint256 rescueOrder, uint256 accessoryId, uint8 paletteIndex, uint16 zIndex, address payable referrer)
            private
            onlyAMCOwner(rescueOrder)
            notZeroAddress(referrer)
            accessoryExists(accessoryId)
            returns (uint256)
        {
            require(isEligible(rescueOrder, accessoryId), "Ineligible");
            Accessory storage accessory = AllAccessories[accessoryId];
            require(accessory.price != NOT_FOR_SALE, "Not For Sale");
            require(accessory.availableSupply > 0, "Supply Exhausted");
            accessory.availableSupply--;
            require(address(this).balance >= accessory.price, "Insufficient Value");
            emit AccessoryPurchased(accessoryId, rescueOrder, accessory.price);
            uint256 ownedAccessoryId = applyAccessory(rescueOrder, accessoryId, paletteIndex, zIndex);
            if(accessory.price > 0) {
                sendPayment(accessory.manager, accessory.price, referrer);
            }
            return ownedAccessoryId;
        }
    
        /**
         * @dev Buy an accessory that is up for sale by its owner
         *
         * This method is the typical purchase method used by storefronts;
         * it allows the storefront to claim a referral fee for the purchase.
         *
         * Passing a z-index value of zero to this method just purchases the accessory,
         * but does not make it an active part of the MoonCat's appearance.
         */
        function buyAccessory (uint256 rescueOrder, uint256 accessoryId, uint8 paletteIndex, uint16 zIndex, address payable referrer)
            public
            payable
            returns (uint256)
        {
            uint256 ownedAccessoryId = buyAndApplyAccessory(rescueOrder, accessoryId, paletteIndex, zIndex, referrer);
            if(address(this).balance > 0){
                // The buyer over-paid; transfer their funds back to them
                payable(msg.sender).transfer(address(this).balance);
            }
            return ownedAccessoryId;
        }
    
        /**
         * @dev Buy an accessory that is up for sale by its owner
         *
         * This method is a generic fallback method if no referrer address is given for a purchase.
         * Defaults to the owner of the contract to receive the referral fee in this case.
         */
        function buyAccessory (uint256 rescueOrder, uint256 accessoryId, uint8 paletteIndex, uint16 zIndex)
            public
            payable
            returns (uint256)
        {
            return buyAccessory(rescueOrder, accessoryId, paletteIndex, zIndex, owner);
        }
    
        /**
         * @dev Buy multiple accessories at once; setting a palette and z-index for each one
         */
        function buyAccessories (AccessoryBatchData[] calldata orders, address payable referrer)
            public
            payable
        {
            for (uint256 i = 0; i < orders.length; i++) {
                AccessoryBatchData memory order = orders[i];
                buyAndApplyAccessory(order.rescueOrder, order.ownedIndexOrAccessoryId, order.paletteIndex, order.zIndex, referrer);
            }
            if(address(this).balance > 0){
                // The buyer over-paid; transfer their funds back to them
                payable(msg.sender).transfer(address(this).balance);
            }
        }
    
        /**
         * @dev Buy multiple accessories at once; setting a palette and z-index for each one (setting the contract owner as the referrer)
         */
        function buyAccessories (AccessoryBatchData[] calldata orders)
            public
            payable
        {
            buyAccessories(orders, owner);
        }
    
        /**
         * @dev Change the status of an owned accessory (worn or not, z-index ordering, color palette variant)
         */
        function alterAccessory (uint256 rescueOrder, uint256 ownedAccessoryIndex, uint8 paletteIndex, uint16 zIndex)
            public
            onlyAMCOwner(rescueOrder)
        {
            OwnedAccessory[] storage ownedAccessories = AccessoriesByMoonCat[rescueOrder];
            require(ownedAccessoryIndex < ownedAccessories.length, "Owned Accessory Not Found");
            OwnedAccessory storage ownedAccessory = ownedAccessories[ownedAccessoryIndex];
            require((paletteIndex <= 7) && (uint64(AllAccessories[ownedAccessory.accessoryId].palettes[paletteIndex]) != 0), "Palette Not Found");
            ownedAccessory.paletteIndex = paletteIndex;
            ownedAccessory.zIndex = zIndex;
            emit AccessoryApplied(ownedAccessory.accessoryId, rescueOrder, paletteIndex, zIndex);
        }
    
        /**
        * @dev Change the status of multiple accessories at once
        */
        function alterAccessories (AccessoryBatchData[] calldata alterations)
            public
        {
            for(uint i = 0; i < alterations.length; i++ ){
                AccessoryBatchData memory alteration = alterations[i];
                alterAccessory(alteration.rescueOrder, alteration.ownedIndexOrAccessoryId, alteration.paletteIndex, alteration.zIndex);
            }
        }
    
        /* View - Accessories */
    
        /**
         * @dev How many accessories exist in this contract?
         */
        function totalAccessories ()
            public
            view
            returns (uint256)
        {
            return AllAccessories.length;
        }
    
        /**
         * @dev Checks if there is an accessory with same IDAT data
         */
        function isAccessoryUnique(bytes calldata IDAT)
            public
            view
            returns (bool)
        {
            bytes32 accessoryHash = keccak256(IDAT);
            return (!accessoryHashes[accessoryHash]);
        }
    
        /**
         * @dev How many palettes are defined for an accessory?
         */
        function accessoryPaletteCount (uint256 accessoryId)
            public
            view
            accessoryExists(accessoryId)
            returns (uint8)
        {
            bytes8[7] memory accessoryPalettes = AllAccessories[accessoryId].palettes;
            for(uint8 i = 0; i < accessoryPalettes.length; i++) {
                if (uint64(accessoryPalettes[i]) == 0) {
                    return i;
                }
            }
            return uint8(accessoryPalettes.length);
        }
    
        /**
         * @dev Fetch a specific palette for a given accessory
         */
        function accessoryPalette (uint256 accessoryId, uint256 paletteIndex)
            public
            view
            returns (bytes8)
        {
            return AllAccessories[accessoryId].palettes[paletteIndex];
        }
    
        /**
         * @dev Fetch data about a given accessory
         */
        function accessoryInfo (uint256 accessoryId)
            public
            view
            accessoryExists(accessoryId)
            returns (uint16 totalSupply, uint16 availableSupply, bytes28 name, address manager, uint8 metabyte, uint8 availablePalettes, bytes2[4] memory positions, bool availableForPurchase, uint256 price)
        {
            Accessory memory accessory = AllAccessories[accessoryId];
            availablePalettes = accessoryPaletteCount(accessoryId);
            bool available = accessory.price != NOT_FOR_SALE && accessory.availableSupply > 0;
            return (accessory.totalSupply, accessory.availableSupply, accessory.name, accessory.manager, accessory.meta, availablePalettes, accessory.positions, available, accessory.price);
        }
    
        /**
         * @dev Fetch image data about a given accessory
         */
        function accessoryImageData (uint256 accessoryId)
            public
            view
            accessoryExists(accessoryId)
            returns (bytes2[4] memory positions, bytes8[7] memory palettes, uint8 width, uint8 height, uint8 meta, bytes memory IDAT)
        {
            Accessory memory accessory = AllAccessories[accessoryId];
            return (accessory.positions, accessory.palettes, accessory.width, accessory.height, accessory.meta, accessory.IDAT);
        }
    
        /**
         * @dev Fetch EligibleList for a given accessory
         */
        function accessoryEligibleList(uint256 accessoryId)
            public
            view
            accessoryExists(accessoryId)
            returns (bytes32[100] memory)
        {
            return AllEligibleLists[accessoryId];
        }
    
        /*  View - Manager */
    
        /**
         * @dev Which address manages a specific accessory?
         */
        function managerOf (uint256 accessoryId)
            public
            view
            accessoryExists(accessoryId)
            returns (address)
        {
            return AllAccessories[accessoryId].manager;
        }
    
        /**
         * @dev How many accessories does a given address manage?
         */
        function balanceOf (address manager)
            public
            view
            returns (uint256)
        {
            return AccessoriesByManager[manager].length();
        }
    
        /**
         * @dev Iterate through a given address's managed accessories
         */
        function managedAccessoryByIndex (address manager, uint256 managedAccessoryIndex)
            public
            view
            returns (uint256)
        {
            return AccessoriesByManager[manager].at(managedAccessoryIndex);
        }
    
        /*  View - AcclimatedMoonCat */
    
        /**
         * @dev How many accessories does a given MoonCat own?
         */
        function balanceOf (uint256 rescueOrder)
            public
            view
            returns (uint256)
        {
            return AccessoriesByMoonCat[rescueOrder].length;
        }
    
        /**
         * @dev Iterate through a given MoonCat's accessories
         */
        function ownedAccessoryByIndex (uint256 rescueOrder, uint256 ownedAccessoryIndex)
            public
            view
            returns (OwnedAccessory memory)
        {
            require(ownedAccessoryIndex < AccessoriesByMoonCat[rescueOrder].length, "Index out of bounds");
            return AccessoriesByMoonCat[rescueOrder][ownedAccessoryIndex];
        }
    
        /**
         * @dev Lookup function to see if this MoonCat has already purchased a given accessory
         */
        function doesMoonCatOwnAccessory (uint256 rescueOrder, uint256 accessoryId)
            public
            view
            returns (bool)
        {
            return OwnedAccessoriesByMoonCat[rescueOrder][accessoryId];
        }
    
    }

    File 2 of 3: MoonCatRescue
    pragma solidity ^0.4.13;
    
    contract MoonCatRescue {
      enum Modes { Inactive, Disabled, Test, Live }
    
      Modes public mode = Modes.Inactive;
    
      address owner;
    
      bytes16 public imageGenerationCodeMD5 = 0xdbad5c08ec98bec48490e3c196eec683; // use this to verify mooncatparser.js the cat image data generation javascript file.
    
      string public name = "MoonCats";
      string public symbol = "?"; // unicode cat symbol
      uint8 public decimals = 0;
    
      uint256 public totalSupply = 25600;
      uint16 public remainingCats = 25600 - 256; // there will only ever be 25,000 cats
      uint16 public remainingGenesisCats = 256; // there can only be a maximum of 256 genesis cats
      uint16 public rescueIndex = 0;
    
      bytes5[25600] public rescueOrder;
    
      bytes32 public searchSeed = 0x0; // gets set with the immediately preceding blockhash when the contract is activated to prevent "premining"
    
      struct AdoptionOffer {
        bool exists;
        bytes5 catId;
        address seller;
        uint price;
        address onlyOfferTo;
      }
    
      struct AdoptionRequest{
        bool exists;
        bytes5 catId;
        address requester;
        uint price;
      }
    
      mapping (bytes5 => AdoptionOffer) public adoptionOffers;
      mapping (bytes5 => AdoptionRequest) public adoptionRequests;
    
      mapping (bytes5 => bytes32) public catNames;
      mapping (bytes5 => address) public catOwners;
      mapping (address => uint256) public balanceOf; //number of cats owned by a given address
      mapping (address => uint) public pendingWithdrawals;
    
      /* events */
    
      event CatRescued(address indexed to, bytes5 indexed catId);
      event CatNamed(bytes5 indexed catId, bytes32 catName);
      event Transfer(address indexed from, address indexed to, uint256 value);
      event CatAdopted(bytes5 indexed catId, uint price, address indexed from, address indexed to);
      event AdoptionOffered(bytes5 indexed catId, uint price, address indexed toAddress);
      event AdoptionOfferCancelled(bytes5 indexed catId);
      event AdoptionRequested(bytes5 indexed catId, uint price, address indexed from);
      event AdoptionRequestCancelled(bytes5 indexed catId);
      event GenesisCatsAdded(bytes5[16] catIds);
    
      function MoonCatRescue() payable {
        owner = msg.sender;
        assert((remainingCats + remainingGenesisCats) == totalSupply);
        assert(rescueOrder.length == totalSupply);
        assert(rescueIndex == 0);
      }
    
      /* registers and validates cats that are found */
      function rescueCat(bytes32 seed) activeMode returns (bytes5) {
        require(remainingCats > 0); // cannot register any cats once supply limit is reached
        bytes32 catIdHash = keccak256(seed, searchSeed); // generate the prospective catIdHash
        require(catIdHash[0] | catIdHash[1] | catIdHash[2] == 0x0); // ensures the validity of the catIdHash
        bytes5 catId = bytes5((catIdHash & 0xffffffff) << 216); // one byte to indicate genesis, and the last 4 bytes of the catIdHash
        require(catOwners[catId] == 0x0); // if the cat is already registered, throw an error. All cats are unique.
    
        rescueOrder[rescueIndex] = catId;
        rescueIndex++;
    
        catOwners[catId] = msg.sender;
        balanceOf[msg.sender]++;
        remainingCats--;
    
        CatRescued(msg.sender, catId);
    
        return catId;
      }
    
      /* assigns a name to a cat, once a name is assigned it cannot be changed */
      function nameCat(bytes5 catId, bytes32 catName) onlyCatOwner(catId) {
        require(catNames[catId] == 0x0); // ensure the current name is empty; cats can only be named once
        require(!adoptionOffers[catId].exists); // cats cannot be named while they are up for adoption
        catNames[catId] = catName;
        CatNamed(catId, catName);
      }
    
      /* puts a cat up for anyone to adopt */
      function makeAdoptionOffer(bytes5 catId, uint price) onlyCatOwner(catId) {
        require(price > 0);
        adoptionOffers[catId] = AdoptionOffer(true, catId, msg.sender, price, 0x0);
        AdoptionOffered(catId, price, 0x0);
      }
    
      /* puts a cat up for a specific address to adopt */
      function makeAdoptionOfferToAddress(bytes5 catId, uint price, address to) onlyCatOwner(catId) isNotSender(to){
        adoptionOffers[catId] = AdoptionOffer(true, catId, msg.sender, price, to);
        AdoptionOffered(catId, price, to);
      }
    
      /* cancel an adoption offer */
      function cancelAdoptionOffer(bytes5 catId) onlyCatOwner(catId) {
        adoptionOffers[catId] = AdoptionOffer(false, catId, 0x0, 0, 0x0);
        AdoptionOfferCancelled(catId);
      }
    
      /* accepts an adoption offer  */
      function acceptAdoptionOffer(bytes5 catId) payable {
        AdoptionOffer storage offer = adoptionOffers[catId];
        require(offer.exists);
        require(offer.onlyOfferTo == 0x0 || offer.onlyOfferTo == msg.sender);
        require(msg.value >= offer.price);
        if(msg.value > offer.price) {
          pendingWithdrawals[msg.sender] += (msg.value - offer.price); // if the submitted amount exceeds the price allow the buyer to withdraw the difference
        }
        transferCat(catId, catOwners[catId], msg.sender, offer.price);
      }
    
      /* transfer a cat directly without payment */
      function giveCat(bytes5 catId, address to) onlyCatOwner(catId) {
        transferCat(catId, msg.sender, to, 0);
      }
    
      /* requests adoption of a cat with an ETH offer */
      function makeAdoptionRequest(bytes5 catId) payable isNotSender(catOwners[catId]) {
        require(catOwners[catId] != 0x0); // the cat must be owned
        AdoptionRequest storage existingRequest = adoptionRequests[catId];
        require(msg.value > 0);
        require(msg.value > existingRequest.price);
    
    
        if(existingRequest.price > 0) {
          pendingWithdrawals[existingRequest.requester] += existingRequest.price;
        }
    
        adoptionRequests[catId] = AdoptionRequest(true, catId, msg.sender, msg.value);
        AdoptionRequested(catId, msg.value, msg.sender);
    
      }
    
      /* allows the owner of the cat to accept an adoption request */
      function acceptAdoptionRequest(bytes5 catId) onlyCatOwner(catId) {
        AdoptionRequest storage existingRequest = adoptionRequests[catId];
        require(existingRequest.exists);
        address existingRequester = existingRequest.requester;
        uint existingPrice = existingRequest.price;
        adoptionRequests[catId] = AdoptionRequest(false, catId, 0x0, 0); // the adoption request must be cancelled before calling transferCat to prevent refunding the requester.
        transferCat(catId, msg.sender, existingRequester, existingPrice);
      }
    
      /* allows the requester to cancel their adoption request */
      function cancelAdoptionRequest(bytes5 catId) {
        AdoptionRequest storage existingRequest = adoptionRequests[catId];
        require(existingRequest.exists);
        require(existingRequest.requester == msg.sender);
    
        uint price = existingRequest.price;
    
        adoptionRequests[catId] = AdoptionRequest(false, catId, 0x0, 0);
    
        msg.sender.transfer(price);
    
        AdoptionRequestCancelled(catId);
      }
    
    
      function withdraw() {
        uint amount = pendingWithdrawals[msg.sender];
        pendingWithdrawals[msg.sender] = 0;
        msg.sender.transfer(amount);
      }
    
      /* owner only functions */
    
      /* disable contract before activation. A safeguard if a bug is found before the contract is activated */
      function disableBeforeActivation() onlyOwner inactiveMode {
        mode = Modes.Disabled;  // once the contract is disabled it's mode cannot be changed
      }
    
      /* activates the contract in *Live* mode which sets the searchSeed and enables rescuing */
      function activate() onlyOwner inactiveMode {
        searchSeed = block.blockhash(block.number - 1); // once the searchSeed is set it cannot be changed;
        mode = Modes.Live; // once the contract is activated it's mode cannot be changed
      }
    
      /* activates the contract in *Test* mode which sets the searchSeed and enables rescuing */
      function activateInTestMode() onlyOwner inactiveMode { //
        searchSeed = 0x5713bdf5d1c3398a8f12f881f0f03b5025b6f9c17a97441a694d5752beb92a3d; // once the searchSeed is set it cannot be changed;
        mode = Modes.Test; // once the contract is activated it's mode cannot be changed
      }
    
      /* add genesis cats in groups of 16 */
      function addGenesisCatGroup() onlyOwner activeMode {
        require(remainingGenesisCats > 0);
        bytes5[16] memory newCatIds;
        uint256 price = (17 - (remainingGenesisCats / 16)) * 300000000000000000;
        for(uint8 i = 0; i < 16; i++) {
    
          uint16 genesisCatIndex = 256 - remainingGenesisCats;
          bytes5 genesisCatId = (bytes5(genesisCatIndex) << 24) | 0xff00000ca7;
    
          newCatIds[i] = genesisCatId;
    
          rescueOrder[rescueIndex] = genesisCatId;
          rescueIndex++;
          balanceOf[0x0]++;
          remainingGenesisCats--;
    
          adoptionOffers[genesisCatId] = AdoptionOffer(true, genesisCatId, owner, price, 0x0);
        }
        GenesisCatsAdded(newCatIds);
      }
    
    
      /* aggregate getters */
    
      function getCatIds() constant returns (bytes5[]) {
        bytes5[] memory catIds = new bytes5[](rescueIndex);
        for (uint i = 0; i < rescueIndex; i++) {
          catIds[i] = rescueOrder[i];
        }
        return catIds;
      }
    
    
      function getCatNames() constant returns (bytes32[]) {
        bytes32[] memory names = new bytes32[](rescueIndex);
        for (uint i = 0; i < rescueIndex; i++) {
          names[i] = catNames[rescueOrder[i]];
        }
        return names;
      }
    
      function getCatOwners() constant returns (address[]) {
        address[] memory owners = new address[](rescueIndex);
        for (uint i = 0; i < rescueIndex; i++) {
          owners[i] = catOwners[rescueOrder[i]];
        }
        return owners;
      }
    
      function getCatOfferPrices() constant returns (uint[]) {
        uint[] memory catOffers = new uint[](rescueIndex);
        for (uint i = 0; i < rescueIndex; i++) {
          bytes5 catId = rescueOrder[i];
          if(adoptionOffers[catId].exists && adoptionOffers[catId].onlyOfferTo == 0x0) {
            catOffers[i] = adoptionOffers[catId].price;
          }
        }
        return catOffers;
      }
    
      function getCatRequestPrices() constant returns (uint[]) {
        uint[] memory catRequests = new uint[](rescueIndex);
        for (uint i = 0; i < rescueIndex; i++) {
          bytes5 catId = rescueOrder[i];
          catRequests[i] = adoptionRequests[catId].price;
        }
        return catRequests;
      }
    
      function getCatDetails(bytes5 catId) constant returns (bytes5 id,
                                                             address owner,
                                                             bytes32 name,
                                                             address onlyOfferTo,
                                                             uint offerPrice,
                                                             address requester,
                                                             uint requestPrice) {
    
        return (catId,
                catOwners[catId],
                catNames[catId],
                adoptionOffers[catId].onlyOfferTo,
                adoptionOffers[catId].price,
                adoptionRequests[catId].requester,
                adoptionRequests[catId].price);
      }
    
      /* modifiers */
      modifier onlyOwner() {
        require(msg.sender == owner);
        _;
      }
    
      modifier inactiveMode() {
        require(mode == Modes.Inactive);
        _;
      }
    
      modifier activeMode() {
        require(mode == Modes.Live || mode == Modes.Test);
        _;
      }
    
      modifier onlyCatOwner(bytes5 catId) {
        require(catOwners[catId] == msg.sender);
        _;
      }
    
      modifier isNotSender(address a) {
        require(msg.sender != a);
        _;
      }
    
      /* transfer helper */
      function transferCat(bytes5 catId, address from, address to, uint price) private {
        catOwners[catId] = to;
        balanceOf[from]--;
        balanceOf[to]++;
        adoptionOffers[catId] = AdoptionOffer(false, catId, 0x0, 0, 0x0); // cancel any existing adoption offer when cat is transferred
    
        AdoptionRequest storage request = adoptionRequests[catId]; //if the recipient has a pending adoption request, cancel it
        if(request.requester == to) {
          pendingWithdrawals[to] += request.price;
          adoptionRequests[catId] = AdoptionRequest(false, catId, 0x0, 0);
        }
    
        pendingWithdrawals[from] += price;
    
        Transfer(from, to, 1);
        CatAdopted(catId, price, from, to);
      }
    
    }

    File 3 of 3: MoonCatAcclimator
    // SPDX-License-Identifier: GPL-3.0-only
    pragma solidity ^0.7.3;
    import "./openzeppelin/contracts/token/ERC721/ERC721.sol";
    import "@openzeppelin/contracts/token/ERC721/ERC721Holder.sol";
    import "@openzeppelin/contracts/access/Ownable.sol";
    import "@openzeppelin/contracts/utils/Pausable.sol";
    import "./IERC998.sol";
    import "./MoonCatOrderLookup.sol";
    //        ##          ##
    //      ##  ##      ##  ##
    //      ##..  ######  ..##
    //    ####              ####
    //    ##                  ##
    //    ##    ()      ()    ##
    //    ##                  ##
    //    ##     \\  ##  /     ##
    //    ##      \\/  \\/      ##
    //      ##              ##
    //        ##############
    //
    //    #AcclimatedMoonCatsGlow
    //  https://mooncat.community/
    /**
     * @title MoonCat​Acclimator
     * @notice Accepts an original MoonCat and wraps it to present an ERC721- and ERC998-compliant asset
     * @notice Accepts a MoonCat wrapped with the older wrapping contract (at 0x7C40c3...) and re-wraps them
     * @notice Ownable by an admin address. Rights of the Owner are to pause and unpause the contract, and update metadata URL
     */
    contract MoonCatAcclimator is
        ERC721,
        ERC721Holder,
        Ownable,
        Pausable,
        IERC998ERC721TopDown,
        IERC998ERC721TopDownEnumerable
    {
        bytes32 private constant ERC998_MAGIC_VALUE = 0x00000000000000000000000000000000000000000000000000000000cd740db5;
        bytes4 private constant _INTERFACE_ID_ERC998ERC721TopDown = 0x1efdf36a;
        MoonCatOrderLookup public rescueOrderLookup;
        MoonCatRescue MCR = MoonCatRescue(0x60cd862c9C687A9dE49aecdC3A99b74A4fc54aB6);
        MoonCatsWrapped OLD_MCRW = MoonCatsWrapped(0x7C40c393DC0f283F318791d746d894DdD3693572);
        constructor(string memory baseURI)
            ERC721(unicode"Acclimated​MoonCats", unicode"😺")
            Ownable()
        {
            _registerInterface(_INTERFACE_ID_ERC998ERC721TopDown);
            rescueOrderLookup = new MoonCatOrderLookup();
            setBaseURI(baseURI);
            _pause(); // Start in a paused state
        }
        function pause() public whenNotPaused onlyOwner {
            _pause();
        }
        function unpause() public whenPaused onlyOwner {
            _unpause();
        }
        /**
         * @dev Emitted when `catId` token is wrapped into `tokenId`, owned by `owner`.
         */
        event MoonCatAcclimated(
            uint256 tokenId,
            address indexed owner
        );
        /**
         * @dev Emitted when `catId` token is unwrapped from `tokenId`, owned by `owner`.
         */
        event MoonCatDeacclimated(
            uint256 tokenId,
            address indexed owner
        );
        /**
         * @dev returns tokenId of newly minted wrapped MoonCat
         *
         * Requirements:
         *
         * - Do not need to check if _msgSender() is MoonCat owner as the wrapped token is assigned to owner (even if that's not _msgSender())
         * - Owner needs to call makeAdoptionOfferToAddress() in moonCatRescue first.
         * Emits a {Transfer} ERC721 event.
         * @param _rescueOrder the minting order of the MoonCat to wrap
         * @return the ID (rescue order) of the minted token
         */
        function wrap(uint256 _rescueOrder) public returns (uint256) {
            bytes5 catId = MCR.rescueOrder(_rescueOrder);
            address _owner = MCR.catOwners(catId);
            MCR.acceptAdoptionOffer(catId);
            return _wrap(_owner, _rescueOrder);
        }
        /**
         * @dev returns tokenId of newly minted wrapped MoonCat
         *
         * This method must not allow an adoption offer specifically to the new Wrapper address to be buy-able by anyone,
         * because that is how the real owner sets up a manual wrapping of the MoonCat (where they don't really intend to sell).
         *
         * Requirements:
         *
         * - MoonCat at `_rescueOrder` must be offered for sale to any address.
         * - Must have active makeAdoptionOffer() in moonCatRescue contract.
         * Emits a {Transfer} and {MoonCatAcclimated} event.
         * @param _rescueOrder the minting order of the MoonCat to wrap
         * @return the ID (rescue order) of the minted token
         */
        function buyAndWrap(uint256 _rescueOrder) public payable returns (uint256) {
            bytes5 catId = MCR.rescueOrder(_rescueOrder);
            (bool exists, , , , address onlyOfferTo) = MCR.adoptionOffers(catId);
            require(
                onlyOfferTo == address(0) && exists,
                "That MoonCat is not for sale"
            );
            MCR.acceptAdoptionOffer{value: msg.value}(catId);
            return _wrap(_msgSender(), _rescueOrder);
        }
        /**
         * @dev returns tokenId of burned unwrapped MoonCat
         *
         * Requirements:
         *
         * - msgSender() must be owner.
         * Emits a {Transfer} and {MoonCatDeacclimated} event.
         * @param _tokenId the minting order of the MoonCat to unwrap
         * @return the ID (rescue order) of the burned token
         */
        function unwrap(uint256 _tokenId) public returns (uint256) {
            require(ownerOf(_tokenId) == _msgSender(), "Not your MoonCat!");
            require(
                super._exists(_tokenId),
                "That MoonCat is not wrapped in this contract"
            );
            bytes5 catId = MCR.rescueOrder(_tokenId);
            MCR.giveCat(catId, ownerOf(_tokenId));
            _burn(_tokenId);
            emit MoonCatDeacclimated(_tokenId, _msgSender());
            return _tokenId;
        }
        /**
         * @dev wraps MoonCat that was safeTransferFrom() the old MoonCat wrapper directly in one transaction
         *
         * Requirements:
         * - Owner of old wrapped MoonCat must include the rescueOrder in the calldata as a bytes32
         * Emits a {Transfer} and {MoonCatAcclimated} event.
         * @param _to the address that is to be the owner of the newly-wrapped token
         * @param _oldTokenID the ID of the token in the other wrapping contract
         * @param _rescueOrder the minting order of the MoonCat being wrapped
         * @return the ID (rescue order) of the minted token
         */
        function _wrapOnSafeTransferFromReceipt(
            address _to,
            uint256 _oldTokenID,
            uint256 _rescueOrder
        ) internal returns (uint256) {
            if (
                MCR.rescueOrder(_rescueOrder) !=
                OLD_MCRW._tokenIDToCatID(_oldTokenID)
            ) {
                // Look up rescue order in Lookup contract
                require(
                    rescueOrderLookup.oldTokenIdExists(_oldTokenID),
                    "Unable to determine proper rescueOrder for this old token ID"
                );
                _rescueOrder = rescueOrderLookup.oldTokenIdToRescueOrder(
                    _oldTokenID
                );
                require(
                    MCR.rescueOrder(_rescueOrder) ==
                        OLD_MCRW._tokenIDToCatID(_oldTokenID),
                    "_oldTokenID and _rescueOrder do not match same catID"
                );
            }
            OLD_MCRW.unwrap(_oldTokenID);
            return _wrap(_to, _rescueOrder);
        }
        /**
         * @dev wraps an unwrapped MoonCat
         *
         * notes:
         * Emits a {Transfer} and {MoonCatAcclimated} event.
         * @param _owner the address that should be the new owner of the newly-created token
         * @param _tokenId the ID of the token to create (rescue order of the MoonCat)
         * @return the ID (rescue order) of the minted token
         */
        function _wrap(address _owner, uint256 _tokenId)
            internal
            returns (uint256)
        {
            require(!paused(), "Attempted wrap while paused");
            _mint(_owner, _tokenId);
            emit MoonCatAcclimated(_tokenId, _msgSender());
            return _tokenId;
        }
        /**
         * @dev Always returns `IERC721Receiver.onERC721Received.selector`
         *
         * This function handles both automatic rewrapping of old-wrapped MoonCats, and assigning ERC721 tokens as "child assets"
         * of MoonCats already wrapped with this contract.
         *
         * If the incoming token is an old-wrapped Mooncat, the `_data` variable is structured as
         * the first 32 bytes are the rescue order of the transferred MoonCat, subsequent 20 bytes
         * are the new owner's address. If the rescue order is not supplied, the `_oldTokenId` is
         * looked up in the {MoonCatOrderLookup} contract. If a new owner's address is not
         * supplied, the new owner will be assigned as the `_from` sender.
         * Emits a {Transfer} and {MoonCatAcclimated} event.
         *
         * If the incoming token is any other type of ERC721, the `_data` variable is structured as
         * the first 32 bytes are the token ID (rescue order) of the MoonCat that is to receive that assest.
         * Emits a {ReceivedChild} event.
         *
         * @param _operator the _msgSender of the transaction
         * @param _from the address of the former owner of the incoming token
         * @param _oldTokenId the ID of the incoming token
         * @param _data additional metdata
         */
        function onERC721Received(
            address _operator,
            address _from,
            uint256 _oldTokenId,
            bytes calldata _data
        ) public override(ERC721Holder, IERC998ERC721TopDown) returns (bytes4) {
            // Using msg.sender here instead of _operator because we want to know the most recent transaction source,
            // not the start of the chain
            if (msg.sender == address(0x7C40c393DC0f283F318791d746d894DdD3693572)) {
                // This is a Wrapped MoonCat incoming. Don't make it a child, instead unwrap and re-wrap it
                // Who should own this MoonCat after wrapping?
                address _to =
                    (_data.length >= 32 + 20 && bytesToAddress(_data, 32) != address(0))
                        ? bytesToAddress(_data, 32)
                        : _from;
                require(
                    _to != address(0) && _to != address(this),
                    "Invalid destination owner specified"
                );
                _wrapOnSafeTransferFromReceipt(
                    _to,
                    _oldTokenId,
                    (_data.length >= 32) ? toUint256(_data, 0) : 0
                );
                return ERC721Holder.onERC721Received(_operator, _from, _oldTokenId, _data);
            }
            // Otherwise, handle as ERC998 Child incoming
            require(_data.length > 0, "_data must contain the uint256 tokenId to transfer the child token to");
            // convert up to 32 bytes of_data to uint256, owner NFT tokenId passed as uint in bytes
            uint256 tokenId;
            assembly {tokenId := calldataload(164)}
            if (_data.length < 32) {
                tokenId = tokenId >> 256 - _data.length * 8;
            }
            _receiveChild(_from, tokenId, msg.sender, _oldTokenId);
            require(ERC721(msg.sender).ownerOf(_oldTokenId) != address(0), "Child token not owned");
            return ERC721Holder.onERC721Received(_operator, _from, _oldTokenId, _data);
        }
        /**
         * @dev sets the base URI
         *
         * notes:
         * - only callable by the contract owner
         */
        function setBaseURI(string memory _newBaseURI) public onlyOwner {
            _setBaseURI(_newBaseURI);
        }
        /**
         * @dev See {IERC721-balanceOf}.
         * This contract returns the locally-wrapped token count as well as old-wrapped MoonCats
         * that are mapped in the {MoonCatOrderLookup} contract.
         */
        function balanceOf(address _owner) public view override returns (uint256) {
            return
                super.balanceOf(_owner) +
                rescueOrderLookup.entriesPerAddress(_owner);
        }
        /**
        * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
         * This contract enumerates the locally-wrapped token count as well as old-wrapped MoonCats
         * that are mapped in the {MoonCatOrderLookup} contract.
        */
        function tokenOfOwnerByIndex(address _owner, uint256 _index)
            public
            view
            override
            returns (uint256)
        {
            uint256 localBalance = super.balanceOf(_owner);
            if (_index < localBalance) {
                // This index is in the range of tokens owned by that address here in this contract
                return super.tokenOfOwnerByIndex(_owner, _index);
            }
            // Looking to enumerate a token that's mapped to the old wrapping contract
            uint16 countFound = 0;
            for (uint256 i = 0; i < OLD_MCRW.balanceOf(_owner); i++) {
                uint256 oldTokenId = OLD_MCRW.tokenOfOwnerByIndex(_owner, i);
                if (rescueOrderLookup.oldTokenIdExists(oldTokenId)) {
                    countFound++;
                    if (countFound == _index - localBalance + 1) {
                        return
                            rescueOrderLookup.oldTokenIdToRescueOrder(oldTokenId);
                    }
                }
            }
            revert("Cannot find token ID for that index");
        }
        /**
        * @dev See {IERC721-ownerOf}.
        */
        function ownerOf(uint256 _tokenId) public view override returns (address) {
            if (super._exists(_tokenId)) {
                return super.ownerOf(_tokenId);
            }
            // Check other wrapper
            // First see if we're dealing with the MoonCat that was the zeroth-wrapped MoonCat in other wrapper
            bytes5 thisMoonCatID = MCR.rescueOrder(_tokenId);
            if (thisMoonCatID == OLD_MCRW._tokenIDToCatID(0)) {
                return OLD_MCRW.ownerOf(0);
            }
            uint256 otherID = OLD_MCRW._catIDToTokenID(thisMoonCatID);
            // We're not dealing with the zeroth-wrapped MoonCat, so a zero here is an indication they don't exist
            require(otherID > 0, "That MoonCat is not wrapped");
            return OLD_MCRW.ownerOf(otherID);
        }
        /**
         * @dev See {IERC721-isApprovedForAll}.
         */
        function isApprovedForAll(address _owner, address _operator)
            public
            view
            virtual
            override
            returns (bool)
        {
            return
                rescueOrderLookup.entriesPerAddress(_owner) == 0
                    ? super.isApprovedForAll(_owner, _operator)
                    : super.isApprovedForAll(_owner, _operator) &&
                        OLD_MCRW.isApprovedForAll(_owner, address(this));
        }
        /**
         * @dev See {ERC721-_isApprovedOrOwner}.
         */
        function _isApprovedOrOwner(address _spender, uint256 _tokenId)
            internal
            view
            override
            returns (bool)
        {
            require(
                _exists(_tokenId),
                "ERC721: operator query for nonexistent token"
            );
            // Differs here from OpenZeppelin standard:
            // Calls `ownerOf` instead of `ERC721.ownerOf`
            address _owner = ownerOf(_tokenId);
            return (_spender == _owner ||
                getApproved(_tokenId) == _spender ||
                ERC721.isApprovedForAll(_owner, _spender));
        }
        /**
         * @dev See {ERC721-approve}.
         */
        function approve(address _to, uint256 _tokenId) public override {
            address _owner = ownerOf(_tokenId);
            require(_to != _owner, "ERC721: approval to current owner");
            // Differs here from OpenZeppelin standard:
            // Calls `isApprovedForAll` instead of `ERC721.isApprovedForAll`
            require(
                _msgSender() == _owner || isApprovedForAll(_owner, _msgSender()),
                "ERC721: approve caller is not owner nor approved for all"
            );
            _approve(_to, _tokenId);
        }
        /**
         * @dev rewrap several MoonCats from the old wrapper at once
         * Owner needs to call setApprovalForAll in old wrapper first.
         * @param _rescueOrders an array of MoonCats, identified by rescue order, to rewrap
         * @param _oldTokenIds an array holding the corresponding token ID
         *        in the old wrapper for each MoonCat to be rewrapped
         */
        function batchReWrap(
            uint256[] memory _rescueOrders,
            uint256[] memory _oldTokenIds
        ) public {
            for (uint16 i = 0; i < _rescueOrders.length; i++) {
                address _owner = OLD_MCRW.ownerOf(_oldTokenIds[i]);
                OLD_MCRW.safeTransferFrom(
                    _owner,
                    address(this),
                    _oldTokenIds[i],
                    abi.encodePacked(
                        uintToBytes(_rescueOrders[i]),
                        addressToBytes(_owner)
                    )
                );
            }
        }
        /**
         * @dev Take a list of unwrapped MoonCat rescue orders and wrap them.
         * @param _rescueOrders an array of MoonCats, identified by rescue order, to rewrap
         */
        function batchWrap(uint256[] memory _rescueOrders) public {
            for (uint16 i = 0; i < _rescueOrders.length; i++) {
                wrap(_rescueOrders[i]);
            }
        }
        /**
         * @dev Take a list of MoonCats wrapped in this contract and unwrap them.
         * @param _rescueOrders an array of MoonCats, identified by rescue order, to unwrap
         */
        function batchUnwrap(uint256[] memory _rescueOrders) public {
            for (uint16 i = 0; i < _rescueOrders.length; i++) {
                unwrap(_rescueOrders[i]);
            }
        }
        /**
         * @dev See {ERC721-_transfer}.
         * If the token being transferred exists in this contract, the standard ERC721 logic is used.
         * If the token does not exist in this contract, look it up in the old wrapping contract,
         * and attempt to wrap-then-transfer it.
         */
        function _transfer(
            address _from,
            address _to,
            uint256 _tokenId
        ) internal override {
            if (super._exists(_tokenId)) {
                return super._transfer(_from, _to, _tokenId);
            }
            require(_to != address(0), "ERC721: transfer to the zero address");
            if (_to == address(this)) {
                // Sending the token to be owned by this contract? That's not what they meant; make it owned by the original owner after re-wrapping
                _to = _from;
            }
            uint256 oldTokenId =
                OLD_MCRW._catIDToTokenID(MCR.rescueOrder(_tokenId));
            OLD_MCRW.safeTransferFrom(
                _from,
                address(this),
                oldTokenId,
                abi.encodePacked(uintToBytes(_tokenId), addressToBytes(_to))
            );
            rescueOrderLookup.removeEntry(oldTokenId);
        }
        /**
         * @dev See {ERC721-_exists}.
         * If the token being queried exists in this contract, the standard ERC721 logic is used.
         * If the token does not exist in this contract, look it up in the old wrapping contract,
         * and see if it exists there.
         */
        function _exists(uint256 _tokenId) internal view override returns (bool) {
            if (super._exists(_tokenId)) {
                return true;
            }
            // Check if exists in old wrapping contract
            bytes5 realMoonCatZero = OLD_MCRW._tokenIDToCatID(0);
            bytes5 thisMoonCatID = MCR.rescueOrder(_tokenId);
            if (thisMoonCatID == realMoonCatZero) {
                return true;
            }
            return OLD_MCRW._catIDToTokenID(thisMoonCatID) != 0;
        }
        ///// ERC998 /////
        using EnumerableSet for EnumerableSet.UintSet;
        using EnumerableSet for EnumerableSet.AddressSet;
        /// @dev mapping of local token IDs, and which addresses they own children at.
        /// tokenId => child contract
        mapping(uint256 => EnumerableSet.AddressSet) private childContracts;
        /// @dev mapping of local token IDs, addresses they own children at, and IDs of the specific child tokens
        /// tokenId => (child address => array of child tokens)
        mapping(uint256 => mapping(address => EnumerableSet.UintSet)) private childTokens;
        /// @dev mapping of addresses of child tokens, the specific child token IDs, and which local token owns them
        /// child address => childId => tokenId
        mapping(address => mapping(uint256 => uint256)) internal childTokenOwner;
        uint8 constant TOKEN_OWNER_OFFSET = 10;
        /**
         * @dev a token has been transferred to this contract mark which local token is to now own it
         * Emits a {ReceivedChild} event.
         *
         * @param _from the address who sent the token to this contract
         * @param _tokenId the local token ID that is to be the parent
         * @param _childContract the address of the child token's contract
         * @param _childTokenId the ID value of teh incoming child token
         */
        function _receiveChild(address _from, uint256 _tokenId, address _childContract, uint256 _childTokenId) private {
            require(!paused(), "Child received while paused");
            require(super._exists(_tokenId), "That MoonCat is not wrapped in this contract");
            require(childTokens[_tokenId][_childContract].contains(_childTokenId) == false, "Cannot receive child token because it has already been received");
            childContracts[_tokenId].add(_childContract);
            childTokens[_tokenId][_childContract].add(_childTokenId);
            childTokenOwner[_childContract][_childTokenId] = _tokenId + TOKEN_OWNER_OFFSET;
            emit ReceivedChild(_from, _tokenId, _childContract, _childTokenId);
        }
        /**
         * @dev See {IERC998ERC721TopDown-getChild}.
         */
        function getChild(
            address _from,
            uint256 _tokenId,
            address _childContract,
            uint256 _childTokenId
        ) public override {
            _receiveChild(_from, _tokenId, _childContract, _childTokenId);
            IERC721(_childContract).transferFrom(_from, address(this), _childTokenId);
        }
        /**
         * @dev Given a child address/ID that is owned by some token in this contract, return that owning token's owner
         * @param _childContract the address of the child asset being queried
         * @param _childTokenId the specific ID of the child asset being queried
         * @return parentTokenOwner the address of the owner of that child's parent asset
         * @return parentTokenId the local token ID that is the parent of that child asset
         */
        function _ownerOfChild(address _childContract, uint256 _childTokenId) internal view returns (address parentTokenOwner, uint256 parentTokenId) {
            parentTokenId = childTokenOwner[_childContract][_childTokenId];
            require(parentTokenId > 0, "That child is not owned by a token in this contract");
            return (ownerOf(parentTokenId - TOKEN_OWNER_OFFSET), parentTokenId - TOKEN_OWNER_OFFSET);
        }
        /**
         * @dev See {IERC998ERC721TopDown-ownerOfChild}.
         */
        function ownerOfChild(address _childContract, uint256 _childTokenId)
            public
            override
            view
            returns (bytes32 parentTokenOwner, uint256 parentTokenId)
        {
            parentTokenId = childTokenOwner[_childContract][_childTokenId];
            require(parentTokenId > 0, "That child is not owned by a token in this contract");
            return (ERC998_MAGIC_VALUE << 224 | bytes32(uint256(ownerOf(parentTokenId - TOKEN_OWNER_OFFSET))), parentTokenId - TOKEN_OWNER_OFFSET);
        }
        /**
         * @dev See {IERC998ERC721TopDown-rootOwnerOf}.
         */
        function rootOwnerOf(uint256 _tokenId)
            public
            override
            view
            returns (bytes32 rootOwner)
        {
            return rootOwnerOfChild(address(0), _tokenId);
        }
        /**
         * @dev See {IERC998ERC721TopDown-rootOwnerOfChild}.
         */
        function rootOwnerOfChild(address _childContract, uint256 _childTokenId)
            public
            override
            view
            returns (bytes32 rootOwner)
        {
            address rootOwnerAddress;
            if (_childContract != address(0)) {
                (rootOwnerAddress, _childTokenId) = _ownerOfChild(_childContract, _childTokenId);
            } else {
                rootOwnerAddress = ownerOf(_childTokenId);
            }
            // Case 1: Token owner is this contract and token.
            while (rootOwnerAddress == address(this)) {
                (rootOwnerAddress, _childTokenId) = _ownerOfChild(rootOwnerAddress, _childTokenId);
            }
            (bool callSuccess, bytes memory data) = rootOwnerAddress.staticcall(abi.encodeWithSelector(0xed81cdda, address(this), _childTokenId));
            if (data.length != 0) {
                rootOwner = abi.decode(data, (bytes32));
            }
            if(callSuccess == true && rootOwner >> 224 == ERC998_MAGIC_VALUE) {
                // Case 2: Token owner is other top-down composable
                return rootOwner;
            }
            else {
                // Case 3: Token owner is other contract
                // Or
                // Case 4: Token owner is user
                return ERC998_MAGIC_VALUE << 224 | bytes32(uint256(rootOwnerAddress));
            }
        }
        /**
         * @dev remove internal records linking a given child to a given parent
         * @param _tokenId the local token ID that is the parent of the child asset
         * @param _childContract the address of the child asset to remove
         * @param _childTokenId the specific ID representing the child asset to be removed
         */
        function _removeChild(uint256 _tokenId, address _childContract, uint256 _childTokenId) private {
            require(
                childTokens[_tokenId][_childContract].contains(_childTokenId),
                "Child token not owned by token"
            );
            // remove child token
            childTokens[_tokenId][_childContract].remove(_childTokenId);
            delete childTokenOwner[_childContract][_childTokenId];
            // remove contract
            if (childTokens[_tokenId][_childContract].length() == 0) {
                childContracts[_tokenId].remove(_childContract);
            }
        }
        /**
         * @dev check permissions are correct for a transfer of a child asset
         * @param _fromTokenId the local ID of the token that is the parent
         * @param _to the address this child token is being transferred to
         * @param _childContract the address of the child asset's contract
         * @param _childTokenId the specific ID for the child asset being transferred
         */
        function _checkTransferChild(
            uint256 _fromTokenId,
            address _to,
            address _childContract,
            uint256 _childTokenId
        ) private view {
            require(!paused(), "Child transfer while paused");
            uint256 tokenId = childTokenOwner[_childContract][_childTokenId];
            require(tokenId > 0, "Child asset is not owned by a token in this contract");
            tokenId -= TOKEN_OWNER_OFFSET;
            require(tokenId == _fromTokenId, "That MoonCat does not own that asset");
            require(_to != address(0), "Transfer to zero address");
            address rootOwner = address(uint160(uint256(rootOwnerOf(_fromTokenId))));
            require(
                _msgSender() == rootOwner || getApproved(_fromTokenId) == _msgSender() || ERC721.isApprovedForAll(rootOwner, _msgSender()),
                "Not allowed to transfer child assets of that MoonCat"
            );
        }
        /**
         * @dev See {IERC998ERC721TopDown-safeTransferChild}.
         */
        function safeTransferChild(
            uint256 _fromTokenId,
            address _to,
            address _childContract,
            uint256 _childTokenId
        ) public override {
            _checkTransferChild(_fromTokenId, _to, _childContract, _childTokenId);
            _removeChild(_fromTokenId, _childContract, _childTokenId);
            ERC721(_childContract).safeTransferFrom(address(this), _to, _childTokenId);
            emit TransferChild(_fromTokenId, _to, _childContract, _childTokenId);
        }
        /**
         * @dev See {IERC998ERC721TopDown-safeTransferChild}.
         */
        function safeTransferChild(
            uint256 _fromTokenId,
            address _to,
            address _childContract,
            uint256 _childTokenId,
            bytes calldata _data
        ) public override {
            _checkTransferChild(_fromTokenId, _to, _childContract, _childTokenId);
            _removeChild(_fromTokenId, _childContract, _childTokenId);
            ERC721(_childContract).safeTransferFrom(address(this), _to, _childTokenId, _data);
            emit TransferChild(_fromTokenId, _to, _childContract, _childTokenId);
        }
        /**
         * @dev See {IERC998ERC721TopDown-transferChild}.
         */
        function transferChild(
            uint256 _fromTokenId,
            address _to,
            address _childContract,
            uint256 _childTokenId
        ) public override {
            _checkTransferChild(_fromTokenId, _to, _childContract, _childTokenId);
            _removeChild(_fromTokenId, _childContract, _childTokenId);
            //this is here to be compatible with cryptokitties and other old contracts that require being owner and approved
            // before transferring.
            //does not work with current standard which does not allow approving self, so we must let it fail in that case.
            //0x095ea7b3 == "approve(address,uint256)"
            (bool success, bytes memory data) = _childContract.call(abi.encodeWithSelector(0x095ea7b3, this, _childTokenId));
            require(
                success && (data.length == 0 || abi.decode(data, (bool))),
                'Failed to Approve'
            );
            ERC721(_childContract).transferFrom(address(this), _to, _childTokenId);
            emit TransferChild(_fromTokenId, _to, _childContract, _childTokenId);
        }
        /**
         * @dev See {IERC998ERC721TopDown-transferChildToParent}.
         */
        function transferChildToParent(
            uint256 _fromTokenId,
            address _toContract,
            uint256 _toTokenId,
            address _childContract,
            uint256 _childTokenId,
            bytes calldata _data
        ) public override {
            _checkTransferChild(_fromTokenId, _toContract, _childContract, _childTokenId);
            _removeChild(_fromTokenId, _childContract, _childTokenId);
            IERC998ERC721BottomUp(_childContract).transferToParent(address(this), _toContract, _toTokenId, _childTokenId, _data);
            emit TransferChild(_fromTokenId, _toContract, _childContract, _childTokenId);
        }
        ///// ERC998 Enumerable
        /**
         * @dev See {IERC998ERC721TopDownEnumerable-totalChildContracts}.
         */
        function totalChildContracts(uint256 _tokenId)
            external
            override
            view
            returns (uint256)
        {
            return childContracts[_tokenId].length();
        }
        /**
         * @dev See {IERC998ERC721TopDownEnumerable-childContractByIndex}.
         */
        function childContractByIndex(uint256 _tokenId, uint256 _index)
            external
            override
            view
            returns (address childContract)
        {
            return childContracts[_tokenId].at(_index);
        }
        /**
         * @dev See {IERC998ERC721TopDownEnumerable-totalChildTokens}.
         */
        function totalChildTokens(uint256 _tokenId, address _childContract) external override view returns (uint256) {
            return childTokens[_tokenId][_childContract].length();
        }
        /**
         * @dev See {IERC998ERC721TopDownEnumerable-childTokenByIndex}.
         */
        function childTokenByIndex(uint256 _tokenId, address _childContract, uint256 _index) external override view returns (uint256 childTokenId) {
            return childTokens[_tokenId][_childContract].at(_index);
        }
    }
    // UTILITIES
    /**
     * @dev converts bytes (which is at least 32 bytes long) to uint256
     */
    function toUint256(bytes memory _bytes, uint256 _start) pure returns (uint256) {
        require(_start + 32 >= _start, "toUint256_overflow");
        require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
        uint256 tempUint;
        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }
        return tempUint;
    }
    /**
     * @dev converts uint256 to a bytes(32) object
     */
    function uintToBytes(uint256 x) pure returns (bytes memory b) {
        b = new bytes(32);
        assembly {
            mstore(add(b, 32), x)
        }
    }
    /**
     * @dev converts bytes (which is at least 20 bytes long) to address
     */
    function bytesToAddress(bytes memory bys, uint256 _start)
        pure
        returns (address addr)
    {
        assembly {
            addr := mload(add(add(bys, 20), _start))
        }
    }
    /**
     * @dev converts address to a bytes(32) object
     */
    function addressToBytes(address a) pure returns (bytes memory) {
        return abi.encodePacked(a);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    import "@openzeppelin/contracts/utils/Context.sol";
    import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
    import "@openzeppelin/contracts/token/ERC721/IERC721Metadata.sol";
    import "@openzeppelin/contracts/token/ERC721/IERC721Enumerable.sol";
    import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
    import "@openzeppelin/contracts/introspection/ERC165.sol";
    import "@openzeppelin/contracts/math/SafeMath.sol";
    import "@openzeppelin/contracts/utils/Address.sol";
    import "@openzeppelin/contracts/utils/EnumerableSet.sol";
    import "@openzeppelin/contracts/utils/EnumerableMap.sol";
    import "@openzeppelin/contracts/utils/Strings.sol";
    /**
     * @title ERC721 Non-Fungible Token Standard basic implementation
     * @dev see https://eips.ethereum.org/EIPS/eip-721
     */
    contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable {
        using SafeMath for uint256;
        using Address for address;
        using EnumerableSet for EnumerableSet.UintSet;
        using EnumerableMap for EnumerableMap.UintToAddressMap;
        using Strings for uint256;
        // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
        // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
        bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
        // Mapping from holder address to their (enumerable) set of owned tokens
        mapping (address => EnumerableSet.UintSet) private _holderTokens;
        // Enumerable mapping from token ids to their owners
        EnumerableMap.UintToAddressMap private _tokenOwners;
        // Mapping from token ID to approved address
        mapping (uint256 => address) private _tokenApprovals;
        // Mapping from owner to operator approvals
        mapping (address => mapping (address => bool)) private _operatorApprovals;
        // Token name
        string private _name;
        // Token symbol
        string private _symbol;
        // Optional mapping for token URIs
        mapping (uint256 => string) private _tokenURIs;
        // Base URI
        string private _baseURI;
        /*
         *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
         *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
         *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
         *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
         *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
         *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
         *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
         *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
         *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
         *
         *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
         *        0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
         */
        bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
        /*
         *     bytes4(keccak256('name()')) == 0x06fdde03
         *     bytes4(keccak256('symbol()')) == 0x95d89b41
         *     bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
         *
         *     => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
         */
        bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
        /*
         *     bytes4(keccak256('totalSupply()')) == 0x18160ddd
         *     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
         *     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
         *
         *     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
         */
        bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;
        /**
         * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
         */
        constructor (string memory name_, string memory symbol_) public {
            _name = name_;
            _symbol = symbol_;
            // register the supported interfaces to conform to ERC721 via ERC165
            _registerInterface(_INTERFACE_ID_ERC721);
            _registerInterface(_INTERFACE_ID_ERC721_METADATA);
            _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
        }
        /**
         * @dev See {IERC721-balanceOf}.
         */
        function balanceOf(address owner) public view virtual override returns (uint256) {
            require(owner != address(0), "ERC721: balance query for the zero address");
            return _holderTokens[owner].length();
        }
        /**
         * @dev See {IERC721-ownerOf}.
         */
        function ownerOf(uint256 tokenId) public view virtual override returns (address) {
            return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token");
        }
        /**
         * @dev See {IERC721Metadata-name}.
         */
        function name() public view virtual override returns (string memory) {
            return _name;
        }
        /**
         * @dev See {IERC721Metadata-symbol}.
         */
        function symbol() public view virtual override returns (string memory) {
            return _symbol;
        }
        /**
         * @dev See {IERC721Metadata-tokenURI}.
         */
        function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
            require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
            string memory _tokenURI = _tokenURIs[tokenId];
            string memory base = baseURI();
            // If there is no base URI, return the token URI.
            if (bytes(base).length == 0) {
                return _tokenURI;
            }
            // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
            if (bytes(_tokenURI).length > 0) {
                return string(abi.encodePacked(base, _tokenURI));
            }
            // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
            return string(abi.encodePacked(base, tokenId.toString()));
        }
        /**
        * @dev Returns the base URI set via {_setBaseURI}. This will be
        * automatically added as a prefix in {tokenURI} to each token's URI, or
        * to the token ID if no specific URI is set for that token ID.
        */
        function baseURI() public view virtual returns (string memory) {
            return _baseURI;
        }
        /**
         * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
         */
        function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
            return _holderTokens[owner].at(index);
        }
        /**
        * @dev Return an array of all tokens this
        * CUSTOM FUNCTION, NOT IN OPENZEPPELIN TEMPLATE
        */
        function tokensIdsByOwner(address owner) public view returns (uint256[] memory) {
            uint256[] memory tokens = new uint256[](_holderTokens[owner].length());
            for (uint i = 0; i < _holderTokens[owner].length(); i++) {
                tokens[i] = _holderTokens[owner].at(i);
            }
            return tokens;
        }
        /**
         * @dev See {IERC721Enumerable-totalSupply}.
         */
        function totalSupply() public view virtual override returns (uint256) {
            // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds
            return _tokenOwners.length();
        }
        /**
         * @dev See {IERC721Enumerable-tokenByIndex}.
         */
        function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
            (uint256 tokenId, ) = _tokenOwners.at(index);
            return tokenId;
        }
        /**
         * @dev See {IERC721-approve}.
         */
        function approve(address to, uint256 tokenId) public virtual override {
            address owner = ERC721.ownerOf(tokenId);
            require(to != owner, "ERC721: approval to current owner");
            require(_msgSender() == owner || ERC721.isApprovedForAll(owner, _msgSender()),
                "ERC721: approve caller is not owner nor approved for all"
            );
            _approve(to, tokenId);
        }
        /**
         * @dev See {IERC721-getApproved}.
         */
        function getApproved(uint256 tokenId) public view virtual override returns (address) {
            require(_exists(tokenId), "ERC721: approved query for nonexistent token");
            return _tokenApprovals[tokenId];
        }
        /**
         * @dev See {IERC721-setApprovalForAll}.
         */
        function setApprovalForAll(address operator, bool approved) public virtual override {
            require(operator != _msgSender(), "ERC721: approve to caller");
            _operatorApprovals[_msgSender()][operator] = approved;
            emit ApprovalForAll(_msgSender(), operator, approved);
        }
        /**
         * @dev See {IERC721-isApprovedForAll}.
         */
        function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
            return _operatorApprovals[owner][operator];
        }
        /**
         * @dev See {IERC721-transferFrom}.
         */
        function transferFrom(address from, address to, uint256 tokenId) public virtual override {
            //solhint-disable-next-line max-line-length
            require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
            _transfer(from, to, tokenId);
        }
        /**
         * @dev See {IERC721-safeTransferFrom}.
         */
        function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
            safeTransferFrom(from, to, tokenId, "");
        }
        /**
         * @dev See {IERC721-safeTransferFrom}.
         */
        function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override {
            require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
            _safeTransfer(from, to, tokenId, _data);
        }
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
         * are aware of the ERC721 protocol to prevent tokens from being forever locked.
         *
         * `_data` is additional data, it has no specified format and it is sent in call to `to`.
         *
         * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
         * implement alternative mechanisms to perform token transfer, such as signature-based.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {
            _transfer(from, to, tokenId);
            require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
        }
        /**
         * @dev Returns whether `tokenId` exists.
         *
         * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
         *
         * Tokens start existing when they are minted (`_mint`),
         * and stop existing when they are burned (`_burn`).
         */
        function _exists(uint256 tokenId) internal view virtual returns (bool) {
            return _tokenOwners.contains(tokenId);
        }
        /**
         * @dev Returns whether `spender` is allowed to manage `tokenId`.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
            require(_exists(tokenId), "ERC721: operator query for nonexistent token");
            address owner = ERC721.ownerOf(tokenId);
            return (spender == owner || getApproved(tokenId) == spender || ERC721.isApprovedForAll(owner, spender));
        }
        /**
         * @dev Safely mints `tokenId` and transfers it to `to`.
         *
         * Requirements:
         d*
         * - `tokenId` must not exist.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function _safeMint(address to, uint256 tokenId) internal virtual {
            _safeMint(to, tokenId, "");
        }
        /**
         * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
         * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
         */
        function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
            _mint(to, tokenId);
            require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
        }
        /**
         * @dev Mints `tokenId` and transfers it to `to`.
         *
         * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
         *
         * Requirements:
         *
         * - `tokenId` must not exist.
         * - `to` cannot be the zero address.
         *
         * Emits a {Transfer} event.
         */
        function _mint(address to, uint256 tokenId) internal virtual {
            require(to != address(0), "ERC721: mint to the zero address");
            // DIFFERENT FROM OPENZEPPELIN STANDARD
            // Calls `ERC721._exists` rather than `_exists`
            require(!ERC721._exists(tokenId), "ERC721: token already minted");
            _beforeTokenTransfer(address(0), to, tokenId);
            _holderTokens[to].add(tokenId);
            _tokenOwners.set(tokenId, to);
            emit Transfer(address(0), to, tokenId);
        }
        /**
         * @dev Destroys `tokenId`.
         * The approval is cleared when the token is burned.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         *
         * Emits a {Transfer} event.
         */
        function _burn(uint256 tokenId) internal virtual {
            address owner = ERC721.ownerOf(tokenId); // internal owner
            _beforeTokenTransfer(owner, address(0), tokenId);
            // Clear approvals
            _approve(address(0), tokenId);
            // Clear metadata (if any)
            if (bytes(_tokenURIs[tokenId]).length != 0) {
                delete _tokenURIs[tokenId];
            }
            _holderTokens[owner].remove(tokenId);
            _tokenOwners.remove(tokenId);
            emit Transfer(owner, address(0), tokenId);
        }
        /**
         * @dev Transfers `tokenId` from `from` to `to`.
         *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
         *
         * Requirements:
         *
         * - `to` cannot be the zero address.
         * - `tokenId` token must be owned by `from`.
         *
         * Emits a {Transfer} event.
         */
        function _transfer(address from, address to, uint256 tokenId) internal virtual {
            require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); // internal owner
            require(to != address(0), "ERC721: transfer to the zero address");
            _beforeTokenTransfer(from, to, tokenId);
            // Clear approvals from the previous owner
            _approve(address(0), tokenId);
            _holderTokens[from].remove(tokenId);
            _holderTokens[to].add(tokenId);
            _tokenOwners.set(tokenId, to);
            emit Transfer(from, to, tokenId);
        }
        /**
         * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
            require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
            _tokenURIs[tokenId] = _tokenURI;
        }
        /**
         * @dev Internal function to set the base URI for all token IDs. It is
         * automatically added as a prefix to the value returned in {tokenURI},
         * or to the token ID if {tokenURI} is empty.
         */
        function _setBaseURI(string memory baseURI_) internal virtual {
            _baseURI = baseURI_;
        }
        /**
         * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
         * The call is not executed if the target address is not a contract.
         *
         * @param from address representing the previous owner of the given token ID
         * @param to target address that will receive the tokens
         * @param tokenId uint256 ID of the token to be transferred
         * @param _data bytes optional data to send along with the call
         * @return bool whether the call correctly returned the expected magic value
         */
        function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
            private returns (bool)
        {
            if (!to.isContract()) {
                return true;
            }
            bytes memory returndata = to.functionCall(abi.encodeWithSelector(
                IERC721Receiver(to).onERC721Received.selector,
                _msgSender(),
                from,
                tokenId,
                _data
            ), "ERC721: transfer to non ERC721Receiver implementer");
            bytes4 retval = abi.decode(returndata, (bytes4));
            return (retval == _ERC721_RECEIVED);
        }
        /**
         * @dev Approve `to` to operate on `tokenId`
         *
         * Emits an {Approval} event.
         */
        function _approve(address to, uint256 tokenId) internal virtual {
            _tokenApprovals[tokenId] = to;
            // DIFFERENT FROM OPENZEPPELIN STANDARD
            // Calls `ownerOf` rather than `ERC721.ownerOf`
            emit Approval(ownerOf(tokenId), to, tokenId);
        }
        /**
         * @dev Hook that is called before any token transfer. This includes minting
         * and burning.
         *
         * Calling conditions:
         *
         * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
         * transferred to `to`.
         * - When `from` is zero, `tokenId` will be minted for `to`.
         * - When `to` is zero, ``from``'s `tokenId` will be burned.
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         *
         * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
         */
        function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { }
    }
    // SPDX-License-Identifier: GPL-3.0-only
    pragma solidity ^0.7.3;
    import "@openzeppelin/contracts/access/Ownable.sol";
    import "./IMoonCatRescue.sol";
    import "./IMoonCatsWrapped.sol";
    /**
     * @title MoonCat Order Lookup
     * @notice A space to have an on-chain record mapping token IDs for OLD_MCRW to their original "rescue order" IDs
     * @dev This contract exists because there is no MoonCat ID => Rescue ID function
     * on the original MoonCatRescue contract. The only way to tell a given MoonCat's
     * rescue order if you don't know it is to iterate through the whole `rescueOrder`
     * array. Looping through that whole array in a smart contract would be
     * prohibitively high gas-usage, and so this alternative is needed.
     */
    contract MoonCatOrderLookup is Ownable {
        MoonCatRescue MCR = MoonCatRescue(0x60cd862c9C687A9dE49aecdC3A99b74A4fc54aB6);
        MoonCatsWrapped OLD_MCRW = MoonCatsWrapped(0x7C40c393DC0f283F318791d746d894DdD3693572);
        uint256[25600] private _oldTokenIdToRescueOrder;
        uint8 constant VALUE_OFFSET = 10;
        constructor() Ownable() {}
        /**
          * @dev Submit a batch of token IDs, and their associated rescue orders
          * This is the primary method for the utility of the contract. Anyone
          * can submit this pairing information (not just the owners of the token)
          * and the information can be submitted in batches.
          *
          * Submitting pairs of token IDs with their rescue orders is verified with
          * the original MoonCatRescue contract before recording.
          *
          * Within the private array holding this information, a VALUE_OFFSET is used
          * to differentiate between "not set" and "set to zero" (because Solidity
          * has no concept of "null" or "undefined"). Because the maximum value of the
          * rescue ordering can only be 25,600, we can safely shift the stored values
          * up, and not hit the uint256 limit.
          */
        function submitRescueOrder(
            uint256[] memory oldTokenIds,
            uint16[] memory rescueOrders
        ) public {
            for (uint256 i = 0; i < oldTokenIds.length; i++) {
                require(
                    MCR.rescueOrder(rescueOrders[i]) == OLD_MCRW._tokenIDToCatID(oldTokenIds[i]),
                    "Pair does not match!"
                );
                _oldTokenIdToRescueOrder[oldTokenIds[i]] = rescueOrders[i] + VALUE_OFFSET;
            }
        }
        /**
          * @dev verify a given old token ID is mapped yet or not
          *
          * This function can use just a zero-check because internally all values are
          * stored with a VALUE_OFFSET added onto them (e.g. storing an actual zero
          * is saved as 0 + VALUE_OFFSET = 10, internally), so anything set to an
          * actual zero means "unset".
          */
        function _exists(uint256 oldTokenId) internal view returns (bool) {
            return _oldTokenIdToRescueOrder[oldTokenId] != 0;
        }
        /**
         * @dev public function to verify whether a given old token ID is mapped or not
         */
        function oldTokenIdExists(uint256 oldTokenId) public view returns(bool) {
            return _exists(oldTokenId);
        }
        /**
         * @dev given an old token ID, return the rescue order of that MoonCat
         *
         * Throws an error if that particular token ID does not have a recorded
         * mapping to a rescue order.
         */
        function oldTokenIdToRescueOrder(uint256 oldTokenId) public view returns(uint256) {
            require(_exists(oldTokenId), "That token ID is not mapped yet");
            return _oldTokenIdToRescueOrder[oldTokenId] - VALUE_OFFSET;
        }
        /**
         * @dev remove a mapping from the data structure
         *
         * This allows reclaiming some gas, so as part of the re-wrapping process,
         * this gets called by the Acclimator contract, to recoup some gas for the
         * MoonCat owner.
         */
        function removeEntry(uint256 _oldTokenId) public onlyOwner {
            delete _oldTokenIdToRescueOrder[_oldTokenId];
        }
        /**
         * @dev for a given address, iterate through all the tokens they own in the
         * old wrapping contract, and for each of them, determine how many are mapped
         * in this lookup contract.
         *
         * This method is used by the Acclimator `balanceOf` and `tokenOfOwnerByIndex`
         * to be able to enumerate old-wrapped MoonCats as if they were already
         * re-wrapped in the Acclimator contract.
         */
        function entriesPerAddress(address _owner) public view returns (uint256) {
            uint256 countMapped = 0;
            for (uint256 i = 0; i < OLD_MCRW.balanceOf(_owner); i++) {
                uint256 oldTokenId = OLD_MCRW.tokenOfOwnerByIndex(_owner, i);
                if (_exists(oldTokenId)) {
                    countMapped++;
                }
            }
            return countMapped;
        }
    }
    pragma solidity ^0.7.3;
    /**
     * @title ERC998ERC721 Top-Down Composable Non-Fungible Token
     * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-998.md
     * Note: the ERC-165 identifier for this interface is 0x1efdf36a
     */
    interface IERC998ERC721TopDown {
        /**
         * @dev This emits when a token receives a child token.
         * @param _from The prior owner of the token.
         * @param _toTokenId The token that receives the child token.
         */
        event ReceivedChild(
            address indexed _from,
            uint256 indexed _toTokenId,
            address indexed _childContract,
            uint256 _childTokenId
        );
        /**
         * @dev This emits when a child token is transferred from a token to an address.
         * @param _fromTokenId The parent token that the child token is being transferred from.
         * @param _to The new owner address of the child token.
         */
        event TransferChild(
            uint256 indexed _fromTokenId,
            address indexed _to,
            address indexed _childContract,
            uint256 _childTokenId
        );
        /**
         * @notice Get the root owner of tokenId.
         * @param _tokenId The token to query for a root owner address
         * @return rootOwner The root owner at the top of tree of tokens and ERC998 magic value.
         */
        function rootOwnerOf(uint256 _tokenId)
            external
            view
            returns (bytes32 rootOwner);
        /**
         * @notice Get the root owner of a child token.
         * @param _childContract The contract address of the child token.
         * @param _childTokenId The tokenId of the child.
         * @return rootOwner The root owner at the top of tree of tokens and ERC998 magic value.
         */
        function rootOwnerOfChild(address _childContract, uint256 _childTokenId)
            external
            view
            returns (bytes32 rootOwner);
        /**
         * @notice Get the parent tokenId of a child token.
         * @param _childContract The contract address of the child token.
         * @param _childTokenId The tokenId of the child.
         * @return parentTokenOwner The parent address of the parent token and ERC998 magic value
         * @return parentTokenId The parent tokenId of _tokenId
         */
        function ownerOfChild(address _childContract, uint256 _childTokenId)
            external
            view
            returns (bytes32 parentTokenOwner, uint256 parentTokenId);
        /**
         * @notice A token receives a child token
         * @param _operator The address that caused the transfer.
         * @param _from The owner of the child token.
         * @param _childTokenId The token that is being transferred to the parent.
         * @param _data Up to the first 32 bytes contains an integer which is the receiving parent tokenId.
         */
        function onERC721Received(
            address _operator,
            address _from,
            uint256 _childTokenId,
            bytes calldata _data
        ) external returns (bytes4);
        /**
         * @notice Transfer child token from top-down composable to address.
         * @param _fromTokenId The owning token to transfer from.
         * @param _to The address that receives the child token
         * @param _childContract The ERC721 contract of the child token.
         * @param _childTokenId The tokenId of the token that is being transferred.
         */
        function transferChild(
            uint256 _fromTokenId,
            address _to,
            address _childContract,
            uint256 _childTokenId
        ) external;
        /**
         * @notice Transfer child token from top-down composable to address.
         * @param _fromTokenId The owning token to transfer from.
         * @param _to The address that receives the child token
         * @param _childContract The ERC721 contract of the child token.
         * @param _childTokenId The tokenId of the token that is being transferred.
         */
        function safeTransferChild(
            uint256 _fromTokenId,
            address _to,
            address _childContract,
            uint256 _childTokenId
        ) external;
        /**
         * @notice Transfer child token from top-down composable to address.
         * @param _fromTokenId The owning token to transfer from.
         * @param _to The address that receives the child token
         * @param _childContract The ERC721 contract of the child token.
         * @param _childTokenId The tokenId of the token that is being transferred.
         * @param _data Additional data with no specified format
         */
        function safeTransferChild(
            uint256 _fromTokenId,
            address _to,
            address _childContract,
            uint256 _childTokenId,
            bytes calldata _data
        ) external;
        /**
         * @notice Transfer bottom-up composable child token from top-down composable to other ERC721 token.
         * @param _fromTokenId The owning token to transfer from.
         * @param _toContract The ERC721 contract of the receiving token
         * @param _toTokenId The receiving token
         * @param _childContract The bottom-up composable contract of the child token.
         * @param _childTokenId The token that is being transferred.
         * @param _data Additional data with no specified format
         */
        function transferChildToParent(
            uint256 _fromTokenId,
            address _toContract,
            uint256 _toTokenId,
            address _childContract,
            uint256 _childTokenId,
            bytes calldata _data
        ) external;
        /**
         * @notice Get a child token from an ERC721 contract.
         * @param _from The address that owns the child token.
         * @param _tokenId The token that becomes the parent owner
         * @param _childContract The ERC721 contract of the child token
         * @param _childTokenId The tokenId of the child token
         */
        function getChild(
            address _from,
            uint256 _tokenId,
            address _childContract,
            uint256 _childTokenId
        ) external;
    }
    /**
     * @dev The ERC-165 identifier for this interface is 0xa344afe4
     */
    interface IERC998ERC721TopDownEnumerable {
        /**
         * @notice Get the total number of child contracts with tokens that are owned by tokenId.
         * @param _tokenId The parent token of child tokens in child contracts
         * @return uint256 The total number of child contracts with tokens owned by tokenId.
         */
        function totalChildContracts(uint256 _tokenId)
            external
            view
            returns (uint256);
        /**
         * @notice Get child contract by tokenId and index
         * @param _tokenId The parent token of child tokens in child contract
         * @param _index The index position of the child contract
         * @return childContract The contract found at the tokenId and index.
         */
        function childContractByIndex(uint256 _tokenId, uint256 _index)
            external
            view
            returns (address childContract);
        /**
         * @notice Get the total number of child tokens owned by tokenId that exist in a child contract.
         * @param _tokenId The parent token of child tokens
         * @param _childContract The child contract containing the child tokens
         * @return uint256 The total number of child tokens found in child contract that are owned by tokenId.
         */
        function totalChildTokens(uint256 _tokenId, address _childContract)
            external
            view
            returns (uint256);
        /**
         * @notice Get child token owned by tokenId, in child contract, at index position
         * @param _tokenId The parent token of the child token
         * @param _childContract The child contract of the child token
         * @param _index The index position of the child token.
         * @return childTokenId The child tokenId for the parent token, child token and index
         */
        function childTokenByIndex(
            uint256 _tokenId,
            address _childContract,
            uint256 _index
        ) external view returns (uint256 childTokenId);
    }
    interface IERC998ERC721BottomUp {
        /**
         * @notice Transfer token from owner address to a token
         * @param _from The owner address
         * @param _toContract The ERC721 contract of the receiving token
         * @param _toTokenId The receiving token
         * @param _data Additional data with no specified format
         */
        function transferToParent(
            address _from,
            address _toContract,
            uint256 _toTokenId,
            uint256 _tokenId,
            bytes calldata _data
        ) external;
    }pragma solidity ^0.7.3;
    interface MoonCatRescue {
        function getCatDetails(bytes5 catId)
            external
            view
            returns (
                bytes5 id,
                address owner,
                bytes32 name,
                address onlyOfferTo,
                uint256 offerPrice,
                address requester,
                uint256 requestPrice
            );
        function rescueOrder(uint256 _rescueOrder)
            external
            view
            returns (bytes5 catId);
        function acceptAdoptionOffer(bytes5 catId) external payable;
        function acceptAdoptionRequest(bytes5 catId) external;
        function adoptionRequests(bytes5 _catId)
            external
            view
            returns (
                bool exists,
                bytes5 catId,
                address requester,
                uint256 price
            );
        function adoptionOffers(bytes5 _catId)
            external
            view
            returns (
                bool exists,
                bytes5 catId,
                address seller,
                uint256 price,
                address offerOnlyTo
            );
        function giveCat(bytes5 catId, address to) external;
        function catOwners(bytes5) external view returns (address);
        function makeAdoptionOfferToAddress(bytes5 catId, uint256 price, address to) external;
        function makeAdoptionOffer(bytes5 catId, uint256 price) external;
        function withdraw() external;
    }
    pragma solidity ^0.7.3;
    interface MoonCatsWrapped {
        /**
         * @dev in the original contract, this is a public map property, so is
         * using the default getter action, which does NOT check for "exists";
         * if this returns a zero, it might be referencing token ID #0, or it might
         * be meaning "that MoonCat ID is not wrapped in this contract".
         */
        function _catIDToTokenID(bytes5 catId) external pure
            returns (uint256);
        /**
         * @dev in the original contract, this is a public map property, so is
         * using the default getter action, which does NOT check for "exists".
         * However, no MoonCat has an ID of `0x0000000000`, so if this returns
         * all zeroes, it means "that token ID does not exist in this contract".
         */
        function _tokenIDToCatID(uint256 _tokenID) external pure
            returns (bytes5 catId);
        function safeTransferFrom(address from, address to, uint256 tokenId) external;
        function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) external;
        function balanceOf(address owner) external view returns (uint256 balance);
        function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
        function wrap(bytes5 catId) external;
        function unwrap(uint256 tokenID) external;
        function ownerOf(uint256 tokenID) external view returns(address);
        function setApprovalForAll(address operator, bool _approved) external;
        function isApprovedForAll(address owner, address operator) external view returns (bool);
        function approve(address to, uint256 tokenId) external;
    }// SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    /*
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with GSN meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address payable) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    import "../utils/Context.sol";
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * By default, the owner account will be the one that deploys the contract. This
     * can later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    abstract contract Ownable is Context {
        address private _owner;
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor () internal {
            address msgSender = _msgSender();
            _owner = msgSender;
            emit OwnershipTransferred(address(0), msgSender);
        }
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view virtual returns (address) {
            return _owner;
        }
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(owner() == _msgSender(), "Ownable: caller is not the owner");
            _;
        }
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            emit OwnershipTransferred(_owner, address(0));
            _owner = address(0);
        }
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Can only be called by the current owner.
         */
        function transferOwnership(address newOwner) public virtual onlyOwner {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            emit OwnershipTransferred(_owner, newOwner);
            _owner = newOwner;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    import "./Context.sol";
    /**
     * @dev Contract module which allows children to implement an emergency stop
     * mechanism that can be triggered by an authorized account.
     *
     * This module is used through inheritance. It will make available the
     * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
     * the functions of your contract. Note that they will not be pausable by
     * simply including this module, only once the modifiers are put in place.
     */
    abstract contract Pausable is Context {
        /**
         * @dev Emitted when the pause is triggered by `account`.
         */
        event Paused(address account);
        /**
         * @dev Emitted when the pause is lifted by `account`.
         */
        event Unpaused(address account);
        bool private _paused;
        /**
         * @dev Initializes the contract in unpaused state.
         */
        constructor () internal {
            _paused = false;
        }
        /**
         * @dev Returns true if the contract is paused, and false otherwise.
         */
        function paused() public view virtual returns (bool) {
            return _paused;
        }
        /**
         * @dev Modifier to make a function callable only when the contract is not paused.
         *
         * Requirements:
         *
         * - The contract must not be paused.
         */
        modifier whenNotPaused() {
            require(!paused(), "Pausable: paused");
            _;
        }
        /**
         * @dev Modifier to make a function callable only when the contract is paused.
         *
         * Requirements:
         *
         * - The contract must be paused.
         */
        modifier whenPaused() {
            require(paused(), "Pausable: not paused");
            _;
        }
        /**
         * @dev Triggers stopped state.
         *
         * Requirements:
         *
         * - The contract must not be paused.
         */
        function _pause() internal virtual whenNotPaused {
            _paused = true;
            emit Paused(_msgSender());
        }
        /**
         * @dev Returns to normal state.
         *
         * Requirements:
         *
         * - The contract must be paused.
         */
        function _unpause() internal virtual whenPaused {
            _paused = false;
            emit Unpaused(_msgSender());
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.8.0;
    import "../../introspection/IERC165.sol";
    /**
     * @dev Required interface of an ERC721 compliant contract.
     */
    interface IERC721 is IERC165 {
        /**
         * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
         */
        event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
        /**
         * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
         */
        event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
        /**
         * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
         */
        event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
        /**
         * @dev Returns the number of tokens in ``owner``'s account.
         */
        function balanceOf(address owner) external view returns (uint256 balance);
        /**
         * @dev Returns the owner of the `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function ownerOf(uint256 tokenId) external view returns (address owner);
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
         * are aware of the ERC721 protocol to prevent tokens from being forever locked.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function safeTransferFrom(address from, address to, uint256 tokenId) external;
        /**
         * @dev Transfers `tokenId` token from `from` to `to`.
         *
         * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must be owned by `from`.
         * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(address from, address to, uint256 tokenId) external;
        /**
         * @dev Gives permission to `to` to transfer `tokenId` token to another account.
         * The approval is cleared when the token is transferred.
         *
         * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
         *
         * Requirements:
         *
         * - The caller must own the token or be an approved operator.
         * - `tokenId` must exist.
         *
         * Emits an {Approval} event.
         */
        function approve(address to, uint256 tokenId) external;
        /**
         * @dev Returns the account approved for `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function getApproved(uint256 tokenId) external view returns (address operator);
        /**
         * @dev Approve or remove `operator` as an operator for the caller.
         * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
         *
         * Requirements:
         *
         * - The `operator` cannot be the caller.
         *
         * Emits an {ApprovalForAll} event.
         */
        function setApprovalForAll(address operator, bool _approved) external;
        /**
         * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
         *
         * See {setApprovalForAll}
         */
        function isApprovedForAll(address owner, address operator) external view returns (bool);
        /**
          * @dev Safely transfers `tokenId` token from `from` to `to`.
          *
          * Requirements:
          *
          * - `from` cannot be the zero address.
          * - `to` cannot be the zero address.
          * - `tokenId` token must exist and be owned by `from`.
          * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
          * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
          *
          * Emits a {Transfer} event.
          */
        function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.8.0;
    import "./IERC721.sol";
    /**
     * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
     * @dev See https://eips.ethereum.org/EIPS/eip-721
     */
    interface IERC721Metadata is IERC721 {
        /**
         * @dev Returns the token collection name.
         */
        function name() external view returns (string memory);
        /**
         * @dev Returns the token collection symbol.
         */
        function symbol() external view returns (string memory);
        /**
         * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
         */
        function tokenURI(uint256 tokenId) external view returns (string memory);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.8.0;
    import "./IERC721.sol";
    /**
     * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
     * @dev See https://eips.ethereum.org/EIPS/eip-721
     */
    interface IERC721Enumerable is IERC721 {
        /**
         * @dev Returns the total amount of tokens stored by the contract.
         */
        function totalSupply() external view returns (uint256);
        /**
         * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
         * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
         */
        function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
        /**
         * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
         * Use along with {totalSupply} to enumerate all tokens.
         */
        function tokenByIndex(uint256 index) external view returns (uint256);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    /**
     * @title ERC721 token receiver interface
     * @dev Interface for any contract that wants to support safeTransfers
     * from ERC721 asset contracts.
     */
    interface IERC721Receiver {
        /**
         * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
         * by `operator` from `from`, this function is called.
         *
         * It must return its Solidity selector to confirm the token transfer.
         * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
         *
         * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
         */
        function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    import "./IERC721Receiver.sol";
      /**
       * @dev Implementation of the {IERC721Receiver} interface.
       *
       * Accepts all token transfers. 
       * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}.
       */
    contract ERC721Holder is IERC721Receiver {
        /**
         * @dev See {IERC721Receiver-onERC721Received}.
         *
         * Always returns `IERC721Receiver.onERC721Received.selector`.
         */
        function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) {
            return this.onERC721Received.selector;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    import "./IERC165.sol";
    /**
     * @dev Implementation of the {IERC165} interface.
     *
     * Contracts may inherit from this and call {_registerInterface} to declare
     * their support of an interface.
     */
    abstract contract ERC165 is IERC165 {
        /*
         * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
         */
        bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
        /**
         * @dev Mapping of interface ids to whether or not it's supported.
         */
        mapping(bytes4 => bool) private _supportedInterfaces;
        constructor () internal {
            // Derived contracts need only register support for their own interfaces,
            // we register support for ERC165 itself here
            _registerInterface(_INTERFACE_ID_ERC165);
        }
        /**
         * @dev See {IERC165-supportsInterface}.
         *
         * Time complexity O(1), guaranteed to always use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
            return _supportedInterfaces[interfaceId];
        }
        /**
         * @dev Registers the contract as an implementer of the interface defined by
         * `interfaceId`. Support of the actual ERC165 interface is automatic and
         * registering its interface id is not required.
         *
         * See {IERC165-supportsInterface}.
         *
         * Requirements:
         *
         * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
         */
        function _registerInterface(bytes4 interfaceId) internal virtual {
            require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
            _supportedInterfaces[interfaceId] = true;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    /**
     * @dev Interface of the ERC165 standard, as defined in the
     * https://eips.ethereum.org/EIPS/eip-165[EIP].
     *
     * Implementers can declare support of contract interfaces, which can then be
     * queried by others ({ERC165Checker}).
     *
     * For an implementation, see {ERC165}.
     */
    interface IERC165 {
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    /**
     * @dev Wrappers over Solidity's arithmetic operations with added overflow
     * checks.
     *
     * Arithmetic operations in Solidity wrap on overflow. This can easily result
     * in bugs, because programmers usually assume that an overflow raises an
     * error, which is the standard behavior in high level programming languages.
     * `SafeMath` restores this intuition by reverting the transaction when an
     * operation overflows.
     *
     * Using this library instead of the unchecked operations eliminates an entire
     * class of bugs, so it's recommended to use it always.
     */
    library SafeMath {
        /**
         * @dev Returns the addition of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
        /**
         * @dev Returns the substraction of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
        /**
         * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
        /**
         * @dev Returns the division of two unsigned integers, with a division by zero flag.
         *
         * _Available since v3.4._
         */
        function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
        /**
         * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
         *
         * _Available since v3.4._
         */
        function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
        /**
         * @dev Returns the addition of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `+` operator.
         *
         * Requirements:
         *
         * - Addition cannot overflow.
         */
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
            return c;
        }
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            require(b <= a, "SafeMath: subtraction overflow");
            return a - b;
        }
        /**
         * @dev Returns the multiplication of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `*` operator.
         *
         * Requirements:
         *
         * - Multiplication cannot overflow.
         */
        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;
        }
        /**
         * @dev Returns the integer division of two unsigned integers, reverting on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            require(b > 0, "SafeMath: division by zero");
            return a / b;
        }
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * reverting when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            require(b > 0, "SafeMath: modulo by zero");
            return a % b;
        }
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
         * overflow (when the result is negative).
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {trySub}.
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            return a - b;
        }
        /**
         * @dev Returns the integer division of two unsigned integers, reverting with custom message on
         * division by zero. The result is rounded towards zero.
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {tryDiv}.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b > 0, errorMessage);
            return a / b;
        }
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * reverting with custom message when dividing by zero.
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {tryMod}.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.8.0;
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * [IMPORTANT]
         * ====
         * It is unsafe to assume that an address for which this function returns
         * false is an externally-owned account (EOA) and not a contract.
         *
         * Among others, `isContract` will return false for the following
         * types of addresses:
         *
         *  - an externally-owned account
         *  - a contract in construction
         *  - an address where a contract will be created
         *  - an address where a contract lived, but was destroyed
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // This method relies on extcodesize, which returns 0 for contracts in
            // construction, since the code is only stored at the end of the
            // constructor execution.
            uint256 size;
            // solhint-disable-next-line no-inline-assembly
            assembly { size := extcodesize(account) }
            return size > 0;
        }
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{ value: amount }("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain`call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
          return functionCall(target, data, "Address: low-level call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            require(isContract(target), "Address: call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.call{ value: value }(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
            return functionStaticCall(target, data, "Address: low-level static call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
            require(isContract(target), "Address: static call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.staticcall(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.4._
         */
        function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionDelegateCall(target, data, "Address: low-level delegate call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.4._
         */
        function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
            require(isContract(target), "Address: delegate call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    /**
     * @dev Library for managing
     * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
     * types.
     *
     * Sets have the following properties:
     *
     * - Elements are added, removed, and checked for existence in constant time
     * (O(1)).
     * - Elements are enumerated in O(n). No guarantees are made on the ordering.
     *
     * ```
     * contract Example {
     *     // Add the library methods
     *     using EnumerableSet for EnumerableSet.AddressSet;
     *
     *     // Declare a set state variable
     *     EnumerableSet.AddressSet private mySet;
     * }
     * ```
     *
     * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
     * and `uint256` (`UintSet`) are supported.
     */
    library EnumerableSet {
        // To implement this library for multiple types with as little code
        // repetition as possible, we write it in terms of a generic Set type with
        // bytes32 values.
        // The Set implementation uses private functions, and user-facing
        // implementations (such as AddressSet) are just wrappers around the
        // underlying Set.
        // This means that we can only create new EnumerableSets for types that fit
        // in bytes32.
        struct Set {
            // Storage of set values
            bytes32[] _values;
            // Position of the value in the `values` array, plus 1 because index 0
            // means a value is not in the set.
            mapping (bytes32 => uint256) _indexes;
        }
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function _add(Set storage set, bytes32 value) private returns (bool) {
            if (!_contains(set, value)) {
                set._values.push(value);
                // The value is stored at length-1, but we add 1 to all indexes
                // and use 0 as a sentinel value
                set._indexes[value] = set._values.length;
                return true;
            } else {
                return false;
            }
        }
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function _remove(Set storage set, bytes32 value) private returns (bool) {
            // We read and store the value's index to prevent multiple reads from the same storage slot
            uint256 valueIndex = set._indexes[value];
            if (valueIndex != 0) { // Equivalent to contains(set, value)
                // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                // the array, and then remove the last element (sometimes called as 'swap and pop').
                // This modifies the order of the array, as noted in {at}.
                uint256 toDeleteIndex = valueIndex - 1;
                uint256 lastIndex = set._values.length - 1;
                // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
                // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
                bytes32 lastvalue = set._values[lastIndex];
                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastvalue;
                // Update the index for the moved value
                set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based
                // Delete the slot where the moved value was stored
                set._values.pop();
                // Delete the index for the deleted slot
                delete set._indexes[value];
                return true;
            } else {
                return false;
            }
        }
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function _contains(Set storage set, bytes32 value) private view returns (bool) {
            return set._indexes[value] != 0;
        }
        /**
         * @dev Returns the number of values on the set. O(1).
         */
        function _length(Set storage set) private view returns (uint256) {
            return set._values.length;
        }
       /**
        * @dev Returns the value stored at position `index` in the set. O(1).
        *
        * Note that there are no guarantees on the ordering of values inside the
        * array, and it may change when more values are added or removed.
        *
        * Requirements:
        *
        * - `index` must be strictly less than {length}.
        */
        function _at(Set storage set, uint256 index) private view returns (bytes32) {
            require(set._values.length > index, "EnumerableSet: index out of bounds");
            return set._values[index];
        }
        // Bytes32Set
        struct Bytes32Set {
            Set _inner;
        }
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
            return _add(set._inner, value);
        }
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
            return _remove(set._inner, value);
        }
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
            return _contains(set._inner, value);
        }
        /**
         * @dev Returns the number of values in the set. O(1).
         */
        function length(Bytes32Set storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
       /**
        * @dev Returns the value stored at position `index` in the set. O(1).
        *
        * Note that there are no guarantees on the ordering of values inside the
        * array, and it may change when more values are added or removed.
        *
        * Requirements:
        *
        * - `index` must be strictly less than {length}.
        */
        function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
            return _at(set._inner, index);
        }
        // AddressSet
        struct AddressSet {
            Set _inner;
        }
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(AddressSet storage set, address value) internal returns (bool) {
            return _add(set._inner, bytes32(uint256(uint160(value))));
        }
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(AddressSet storage set, address value) internal returns (bool) {
            return _remove(set._inner, bytes32(uint256(uint160(value))));
        }
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(AddressSet storage set, address value) internal view returns (bool) {
            return _contains(set._inner, bytes32(uint256(uint160(value))));
        }
        /**
         * @dev Returns the number of values in the set. O(1).
         */
        function length(AddressSet storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
       /**
        * @dev Returns the value stored at position `index` in the set. O(1).
        *
        * Note that there are no guarantees on the ordering of values inside the
        * array, and it may change when more values are added or removed.
        *
        * Requirements:
        *
        * - `index` must be strictly less than {length}.
        */
        function at(AddressSet storage set, uint256 index) internal view returns (address) {
            return address(uint160(uint256(_at(set._inner, index))));
        }
        // UintSet
        struct UintSet {
            Set _inner;
        }
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(UintSet storage set, uint256 value) internal returns (bool) {
            return _add(set._inner, bytes32(value));
        }
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(UintSet storage set, uint256 value) internal returns (bool) {
            return _remove(set._inner, bytes32(value));
        }
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(UintSet storage set, uint256 value) internal view returns (bool) {
            return _contains(set._inner, bytes32(value));
        }
        /**
         * @dev Returns the number of values on the set. O(1).
         */
        function length(UintSet storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
       /**
        * @dev Returns the value stored at position `index` in the set. O(1).
        *
        * Note that there are no guarantees on the ordering of values inside the
        * array, and it may change when more values are added or removed.
        *
        * Requirements:
        *
        * - `index` must be strictly less than {length}.
        */
        function at(UintSet storage set, uint256 index) internal view returns (uint256) {
            return uint256(_at(set._inner, index));
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    /**
     * @dev Library for managing an enumerable variant of Solidity's
     * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
     * type.
     *
     * Maps have the following properties:
     *
     * - Entries are added, removed, and checked for existence in constant time
     * (O(1)).
     * - Entries are enumerated in O(n). No guarantees are made on the ordering.
     *
     * ```
     * contract Example {
     *     // Add the library methods
     *     using EnumerableMap for EnumerableMap.UintToAddressMap;
     *
     *     // Declare a set state variable
     *     EnumerableMap.UintToAddressMap private myMap;
     * }
     * ```
     *
     * As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are
     * supported.
     */
    library EnumerableMap {
        // To implement this library for multiple types with as little code
        // repetition as possible, we write it in terms of a generic Map type with
        // bytes32 keys and values.
        // The Map implementation uses private functions, and user-facing
        // implementations (such as Uint256ToAddressMap) are just wrappers around
        // the underlying Map.
        // This means that we can only create new EnumerableMaps for types that fit
        // in bytes32.
        struct MapEntry {
            bytes32 _key;
            bytes32 _value;
        }
        struct Map {
            // Storage of map keys and values
            MapEntry[] _entries;
            // Position of the entry defined by a key in the `entries` array, plus 1
            // because index 0 means a key is not in the map.
            mapping (bytes32 => uint256) _indexes;
        }
        /**
         * @dev Adds a key-value pair to a map, or updates the value for an existing
         * key. O(1).
         *
         * Returns true if the key was added to the map, that is if it was not
         * already present.
         */
        function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) {
            // We read and store the key's index to prevent multiple reads from the same storage slot
            uint256 keyIndex = map._indexes[key];
            if (keyIndex == 0) { // Equivalent to !contains(map, key)
                map._entries.push(MapEntry({ _key: key, _value: value }));
                // The entry is stored at length-1, but we add 1 to all indexes
                // and use 0 as a sentinel value
                map._indexes[key] = map._entries.length;
                return true;
            } else {
                map._entries[keyIndex - 1]._value = value;
                return false;
            }
        }
        /**
         * @dev Removes a key-value pair from a map. O(1).
         *
         * Returns true if the key was removed from the map, that is if it was present.
         */
        function _remove(Map storage map, bytes32 key) private returns (bool) {
            // We read and store the key's index to prevent multiple reads from the same storage slot
            uint256 keyIndex = map._indexes[key];
            if (keyIndex != 0) { // Equivalent to contains(map, key)
                // To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one
                // in the array, and then remove the last entry (sometimes called as 'swap and pop').
                // This modifies the order of the array, as noted in {at}.
                uint256 toDeleteIndex = keyIndex - 1;
                uint256 lastIndex = map._entries.length - 1;
                // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs
                // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
                MapEntry storage lastEntry = map._entries[lastIndex];
                // Move the last entry to the index where the entry to delete is
                map._entries[toDeleteIndex] = lastEntry;
                // Update the index for the moved entry
                map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based
                // Delete the slot where the moved entry was stored
                map._entries.pop();
                // Delete the index for the deleted slot
                delete map._indexes[key];
                return true;
            } else {
                return false;
            }
        }
        /**
         * @dev Returns true if the key is in the map. O(1).
         */
        function _contains(Map storage map, bytes32 key) private view returns (bool) {
            return map._indexes[key] != 0;
        }
        /**
         * @dev Returns the number of key-value pairs in the map. O(1).
         */
        function _length(Map storage map) private view returns (uint256) {
            return map._entries.length;
        }
       /**
        * @dev Returns the key-value pair stored at position `index` in the map. O(1).
        *
        * Note that there are no guarantees on the ordering of entries inside the
        * array, and it may change when more entries are added or removed.
        *
        * Requirements:
        *
        * - `index` must be strictly less than {length}.
        */
        function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) {
            require(map._entries.length > index, "EnumerableMap: index out of bounds");
            MapEntry storage entry = map._entries[index];
            return (entry._key, entry._value);
        }
        /**
         * @dev Tries to returns the value associated with `key`.  O(1).
         * Does not revert if `key` is not in the map.
         */
        function _tryGet(Map storage map, bytes32 key) private view returns (bool, bytes32) {
            uint256 keyIndex = map._indexes[key];
            if (keyIndex == 0) return (false, 0); // Equivalent to contains(map, key)
            return (true, map._entries[keyIndex - 1]._value); // All indexes are 1-based
        }
        /**
         * @dev Returns the value associated with `key`.  O(1).
         *
         * Requirements:
         *
         * - `key` must be in the map.
         */
        function _get(Map storage map, bytes32 key) private view returns (bytes32) {
            uint256 keyIndex = map._indexes[key];
            require(keyIndex != 0, "EnumerableMap: nonexistent key"); // Equivalent to contains(map, key)
            return map._entries[keyIndex - 1]._value; // All indexes are 1-based
        }
        /**
         * @dev Same as {_get}, with a custom error message when `key` is not in the map.
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {_tryGet}.
         */
        function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) {
            uint256 keyIndex = map._indexes[key];
            require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key)
            return map._entries[keyIndex - 1]._value; // All indexes are 1-based
        }
        // UintToAddressMap
        struct UintToAddressMap {
            Map _inner;
        }
        /**
         * @dev Adds a key-value pair to a map, or updates the value for an existing
         * key. O(1).
         *
         * Returns true if the key was added to the map, that is if it was not
         * already present.
         */
        function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
            return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
        }
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the key was removed from the map, that is if it was present.
         */
        function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
            return _remove(map._inner, bytes32(key));
        }
        /**
         * @dev Returns true if the key is in the map. O(1).
         */
        function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
            return _contains(map._inner, bytes32(key));
        }
        /**
         * @dev Returns the number of elements in the map. O(1).
         */
        function length(UintToAddressMap storage map) internal view returns (uint256) {
            return _length(map._inner);
        }
       /**
        * @dev Returns the element stored at position `index` in the set. O(1).
        * Note that there are no guarantees on the ordering of values inside the
        * array, and it may change when more values are added or removed.
        *
        * Requirements:
        *
        * - `index` must be strictly less than {length}.
        */
        function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
            (bytes32 key, bytes32 value) = _at(map._inner, index);
            return (uint256(key), address(uint160(uint256(value))));
        }
        /**
         * @dev Tries to returns the value associated with `key`.  O(1).
         * Does not revert if `key` is not in the map.
         *
         * _Available since v3.4._
         */
        function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
            (bool success, bytes32 value) = _tryGet(map._inner, bytes32(key));
            return (success, address(uint160(uint256(value))));
        }
        /**
         * @dev Returns the value associated with `key`.  O(1).
         *
         * Requirements:
         *
         * - `key` must be in the map.
         */
        function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
            return address(uint160(uint256(_get(map._inner, bytes32(key)))));
        }
        /**
         * @dev Same as {get}, with a custom error message when `key` is not in the map.
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {tryGet}.
         */
        function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) {
            return address(uint160(uint256(_get(map._inner, bytes32(key), errorMessage))));
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    /**
     * @dev String operations.
     */
    library Strings {
        /**
         * @dev Converts a `uint256` to its ASCII `string` representation.
         */
        function toString(uint256 value) internal pure returns (string memory) {
            // Inspired by OraclizeAPI's implementation - MIT licence
            // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
            if (value == 0) {
                return "0";
            }
            uint256 temp = value;
            uint256 digits;
            while (temp != 0) {
                digits++;
                temp /= 10;
            }
            bytes memory buffer = new bytes(digits);
            uint256 index = digits - 1;
            temp = value;
            while (temp != 0) {
                buffer[index--] = bytes1(uint8(48 + temp % 10));
                temp /= 10;
            }
            return string(buffer);
        }
    }