ETH Price: $2,511.73 (-1.88%)

Transaction Decoder

Block:
14947638 at Jun-12-2022 02:12:47 AM +UTC
Transaction Fee:
0.010510165766175043 ETH $26.40
Gas Used:
325,837 Gas / 32.255900239 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x5b9D7Ee3...8858bf117
(Ethermine)
1,544.710319441361351025 Eth1,544.711134033861351025 Eth0.0008145925
0xf63BBF79...137A520b1
0.564521537520806823 Eth
Nonce: 2
0.45501137175463178 Eth
Nonce: 3
0.109510165766175043
0xf643e327...D29ea979D 266.333665165484349173 Eth266.432665165484349173 Eth0.099

Execution Trace

ETH 0.099 BananaTaskForceApeNft.CALL( )
  • ETH 0.099 0xf643e3273c51bb6b9b1dc144b14b5b2d29ea979d.CALL( )
    // File: contracts/Flattened-NFTMatcha-v0.5.7.sol
    
    /**
    
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMWWWWWWWWWWWWWWWMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMWWNXXKKKKKKKXXXXKKKKKKXXNWWMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMWNXKKKKXXNWWWWMMWWWWMWWWWNXXXKKKXNWMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMWNXKKKXNWMMMMMMMMMNOdxKWMMMMMMMMWNXKKKXNWMMMMMMMMMMMMMM
    MMMMMMMMMMMMMWXKKKNWMMMMMMMMMMMMNx:;;l0WMMMMMMMMMMMWNK0KXWMMMMMMMMMMMM
    MMMMMMMMMMMWXKKXWMMMMMMMMMMMMMMXd:;;;;cOWMMMMMMMMMMMMMWXKKXWMMMMMMMMMM
    MMMMMMMMMWNKKXWMMMMMMMMMMMMMMWKo;;col:;:kNMMMMMMMMMMMMMMWX0KNWMMMMMMMM
    MMMMMMMMWX0XWMMMMMMMMMMMMMMMWOl;;oKWXkc;:dXMMMMMMMMMMMMMMMWX0XWMMMMMMM
    MMMMMMMNKKNWMMMMMMMMMMMMMMMNkc;:dXMMMWOc;;oKWMMMMMMMMMMMMMMWNKKNMMMMMM
    MMMMMMNKKNMMMMMMMMMMMMMMMMNx:;:xNMMMMMW0l;;l0WMMMMMMMWMMMMMMMNKKNMMMMM
    MMMMMNKKNMMMMMMMMMMMMMMMMXd:;ckNMMMMMMMMKo:;cOWMMMMXkxkXWMMMMMNKKNMMMM
    MMMMWK0NMMMMMMMMMMMMMMMWKo;;l0WMMMMMMMMMMXx:;:xNMMW0lccxXMMMMMMN0KWMMM
    MMMMX0XWMMMMMMWWMMMMMMWOl;;oKWMMMMMMMMMMMMNkc;:dXMMNklcoKMMMMMMMX0XMMM
    MMMWKKNMMWK0OkkkkkkKWNkc;:dXMMMMMMMMMMMMMMMWOl;;oKWMXdcxNMMMMMMMNKKWMM
    MMMN0XWMMWNXX0OdlccdKOc;:xNMMMWXKKXNWNNNNWWMW0o;;l0WNkdKWMMMMMMMWX0NMM
    MMMX0XMMMMMMMMMN0dlcdOxoONMMMMW0xdddddodxk0KNWXd:;l0Kx0WMMMMMMMMMX0XMM
    MMMX0NMMMMMMMMMMWXxlcoOXWMMMMWKkolclodkKNNNNWWMNxcxOkKWMMMMMMMMMMX0XMM
    MMMX0XMMMMMMMMMMMMNklclkNMMWXklccodxdodKWMMMMMMMNKOkKWMMMMMMMMMMMX0XMM
    MMMN0XWMMMMMMMMMMMMNOoclxXN0occcdKX0xlco0WMMMMMMNOOXMMMMMMMMMMMMMX0NMM
    MMMWKKWMMMMMMMMMMMMMW0dccoxocccdKWMWNklclONMMMMXOONMMMMMMMMMMMMMWKKWMM
    MMMMX0XMMMMMMMMMMMMMMWKdcccccco0WMMMMNOoclkNWWKk0NMMMMMMMMMMMMMMX0XWMM
    MMMMWKKNMMMMMMMMMMMMMMMXxlcccckNMMMMMMW0oclxK0kKWMMMMMMMMMMMMMMNKKWMMM
    MMMMMN0KWMMMMMMMMMMMMMMMNklccoKWMMMMMMMWKdlcoxKWMMMMMMMMMMMMMMWK0NMMMM
    MMMMMMN0KWMMMMMMMMMMMMMMMNOod0KXWMMMMMMNK0xoxXWMMMMMMMMMMMMMMWK0NMMMMM
    MMMMMMMN0KNMMMMMMMMMMMMMMMWXKkll0WMMMMXdcoOKNMMMMMMMMMMMMMMMNK0NMMMMMM
    MMMMMMMMNK0XWMMMMMMMMMMMMMMMNd:;cOWMWKo:;c0WMMMMMMMMMMMMMMWX0KNMMMMMMM
    MMMMMMMMMWXKKNWMMMMMMMMMMMMMMXd:;cx0kl;;l0WMMMMMMMMMMMMMWNKKXWMMMMMMMM
    MMMMMMMMMMMWX0KNWMMMMMMMMMMMMMNkc;;::;:oKWMMMMMMMMMMMMWNK0XWMMMMMMMMMM
    MMMMMMMMMMMMMNXKKXNWMMMMMMMMMMMWOc;;;:dXMMMMMMMMMMMWNXKKXWMMMMMMMMMMMM
    MMMMMMMMMMMMMMMWNKKKXNWMMMMMMMMMW0l:ckNMMMMMMMMMWNXKKKNWMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMWNXKKKXXNWWWMMMMX0KWMMMWWWNXXKKKXNWMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMWWNXXKKKKKXXXXXXXXXXKKKKXXNWWMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMWWNNNNNNNNNNNNWWWMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    
    
    ---------------------- [ WPSmartContracts.com ] ----------------------
    
                           [ Blockchain Made Easy ]
    
    
        |
        |  ERC-721 NFT Marketplace
        |
        |----------------------------
        |
        |  Flavors
        |
        |  >  Matcha: Fully featured ERC-721 Token, with Buy, 
        |     Sell and Auction NFT Marketplace
        |
    
    
    */
    
    pragma solidity ^0.5.7;
    
    /**
     * @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);
    }
    
    /**
     * @dev Required interface of an ERC721 compliant contract.
     */
    contract IERC721 is IERC165 {
        event Transfer(
            address indexed from,
            address indexed to,
            uint256 indexed tokenId
        );
        event Approval(
            address indexed owner,
            address indexed approved,
            uint256 indexed tokenId
        );
        event ApprovalForAll(
            address indexed owner,
            address indexed operator,
            bool approved
        );
    
        /**
         * @dev Returns the number of NFTs in `owner`'s account.
         */
        function balanceOf(address owner) public view returns (uint256 balance);
    
        /**
         * @dev Returns the owner of the NFT specified by `tokenId`.
         */
        function ownerOf(uint256 tokenId) public view returns (address owner);
    
        /**
         * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
         * another (`to`).
         *
         *
         *
         * Requirements:
         * - `from`, `to` cannot be zero.
         * - `tokenId` must be owned by `from`.
         * - If the caller is not `from`, it must be have been allowed to move this
         * NFT by either {approve} or {setApproveForAll}.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId
        ) public;
    
        /**
         * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
         * another (`to`).
         *
         * Requirements:
         * - If the caller is not `from`, it must be approved to move this NFT by
         * either {approve} or {setApproveForAll}.
         */
        function transferFrom(
            address from,
            address to,
            uint256 tokenId
        ) public;
    
        function approve(address to, uint256 tokenId) public;
    
        function getApproved(uint256 tokenId)
            public
            view
            returns (address operator);
    
        function setApprovalForAll(address operator, bool _approved) public;
    
        function isApprovedForAll(address owner, address operator)
            public
            view
            returns (bool);
    
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId,
            bytes memory data
        ) public;
    }
    
    /**
     * @title ERC721 token receiver interface
     * @dev Interface for any contract that wants to support safeTransfers
     * from ERC721 asset contracts.
     */
    contract IERC721Receiver {
        /**
         * @notice Handle the receipt of an NFT
         * @dev The ERC721 smart contract calls this function on the recipient
         * after a {IERC721-safeTransfer}. This function MUST return the function selector,
         * otherwise the caller will revert the transaction. The selector to be
         * returned can be obtained as `this.onERC721Received.selector`. This
         * function MAY throw to revert and reject the transfer.
         * Note: the ERC721 contract address is always the message sender.
         * @param operator The address which called `safeTransferFrom` function
         * @param from The address which previously owned the token
         * @param tokenId The NFT identifier which is being transferred
         * @param data Additional data with no specified format
         * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
         */
        function onERC721Received(
            address operator,
            address from,
            uint256 tokenId,
            bytes memory data
        ) public returns (bytes4);
    }
    
    /**
     * @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, 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");
            uint256 c = a - b;
    
            return c;
        }
    
        /**
         * @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) {
            // 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-solidity/pull/522
            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. Reverts 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) {
            // Solidity only automatically asserts when dividing by 0
            require(b > 0, "SafeMath: division by zero");
            uint256 c = a / b;
            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    
            return c;
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * Reverts 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 Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * This test is non-exhaustive, and there may be false-negatives: during the
         * execution of a contract's constructor, its address will be reported as
         * not containing 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.
         */
        function isContract(address account) internal view returns (bool) {
            // This method relies in extcodesize, which returns 0 for contracts in
            // construction, since the code is only stored at the end of the
            // constructor execution.
    
            // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
            // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
            // for accounts without code, i.e. `keccak256('')`
            bytes32 codehash;
            bytes32 accountHash =
                0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
            // solhint-disable-next-line no-inline-assembly
            assembly {
                codehash := extcodehash(account)
            }
            return (codehash != 0x0 && codehash != accountHash);
        }
    
        /**
         * @dev Converts an `address` into `address payable`. Note that this is
         * simply a type cast: the actual underlying value is not changed.
         */
        function toPayable(address account)
            internal
            pure
            returns (address payable)
        {
            return address(uint160(account));
        }
    }
    
    /**
     * @title Counters
     * @author Matt Condon (@shrugs)
     * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
     * of elements in a mapping, issuing ERC721 ids, or counting request ids.
     *
     * Include with `using Counters for Counters.Counter;`
     * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
     * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
     * directly accessed.
     */
    library Counters {
        using SafeMath for uint256;
    
        struct Counter {
            // This variable should never be directly accessed by users of the library: interactions must be restricted to
            // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
            // this feature: see https://github.com/ethereum/solidity/issues/4637
            uint256 _value; // default: 0
        }
    
        function current(Counter storage counter) internal view returns (uint256) {
            return counter._value;
        }
    
        function increment(Counter storage counter) internal {
            counter._value += 1;
        }
    
        function decrement(Counter storage counter) internal {
            counter._value = counter._value.sub(1);
        }
    }
    
    /**
     * @dev Implementation of the {IERC165} interface.
     *
     * Contracts may inherit from this and call {_registerInterface} to declare
     * their support of an interface.
     */
    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)
            external
            view
            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 {
            require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
            _supportedInterfaces[interfaceId] = true;
        }
    }
    
    /**
     * @title ERC721 Non-Fungible Token Standard basic implementation
     * @dev see https://eips.ethereum.org/EIPS/eip-721
     */
    contract ERC721 is ERC165, IERC721 {
        using SafeMath for uint256;
        using Address for address;
        using Counters for Counters.Counter;
    
        // 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 token ID to owner
        mapping(uint256 => address) private _tokenOwner;
    
        // Mapping from token ID to approved address
        mapping(uint256 => address) private _tokenApprovals;
    
        // Mapping from owner to number of owned token
        mapping(address => Counters.Counter) private _ownedTokensCount;
    
        // Mapping from owner to operator approvals
        mapping(address => mapping(address => bool)) private _operatorApprovals;
    
        /*
         *     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 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
         */
        bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
    
        constructor() public {
            // register the supported interfaces to conform to ERC721 via ERC165
            _registerInterface(_INTERFACE_ID_ERC721);
        }
    
        /**
         * @dev Gets the balance of the specified address.
         * @param owner address to query the balance of
         * @return uint256 representing the amount owned by the passed address
         */
        function balanceOf(address owner) public view returns (uint256) {
            require(
                owner != address(0),
                "ERC721: balance query for the zero address"
            );
    
            return _ownedTokensCount[owner].current();
        }
    
        /**
         * @dev Gets the owner of the specified token ID.
         * @param tokenId uint256 ID of the token to query the owner of
         * @return address currently marked as the owner of the given token ID
         */
        function ownerOf(uint256 tokenId) public view returns (address) {
            address owner = _tokenOwner[tokenId];
            require(
                owner != address(0),
                "ERC721: owner query for nonexistent token"
            );
    
            return owner;
        }
    
        /**
         * @dev Approves another address to transfer the given token ID
         * The zero address indicates there is no approved address.
         * There can only be one approved address per token at a given time.
         * Can only be called by the token owner or an approved operator.
         * @param to address to be approved for the given token ID
         * @param tokenId uint256 ID of the token to be approved
         */
        function approve(address to, uint256 tokenId) public {
            address owner = ownerOf(tokenId);
            require(to != owner, "ERC721: approval to current owner");
    
            require(
                msg.sender == owner || isApprovedForAll(owner, msg.sender),
                "ERC721: approve caller is not owner nor approved for all"
            );
    
            _tokenApprovals[tokenId] = to;
            emit Approval(owner, to, tokenId);
        }
    
        /**
         * @dev Gets the approved address for a token ID, or zero if no address set
         * Reverts if the token ID does not exist.
         * @param tokenId uint256 ID of the token to query the approval of
         * @return address currently approved for the given token ID
         */
        function getApproved(uint256 tokenId) public view returns (address) {
            require(
                _exists(tokenId),
                "ERC721: approved query for nonexistent token"
            );
    
            return _tokenApprovals[tokenId];
        }
    
        /**
         * @dev Sets or unsets the approval of a given operator
         * An operator is allowed to transfer all tokens of the sender on their behalf.
         * @param to operator address to set the approval
         * @param approved representing the status of the approval to be set
         */
        function setApprovalForAll(address to, bool approved) public {
            require(to != msg.sender, "ERC721: approve to caller");
    
            _operatorApprovals[msg.sender][to] = approved;
            emit ApprovalForAll(msg.sender, to, approved);
        }
    
        /**
         * @dev Tells whether an operator is approved by a given owner.
         * @param owner owner address which you want to query the approval of
         * @param operator operator address which you want to query the approval of
         * @return bool whether the given operator is approved by the given owner
         */
        function isApprovedForAll(address owner, address operator)
            public
            view
            returns (bool)
        {
            return _operatorApprovals[owner][operator];
        }
    
        /**
         * @dev Transfers the ownership of a given token ID to another address.
         * Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
         * Requires the msg.sender to be the owner, approved, or operator.
         * @param from current owner of the token
         * @param to address to receive the ownership of the given token ID
         * @param tokenId uint256 ID of the token to be transferred
         */
        function transferFrom(
            address from,
            address to,
            uint256 tokenId
        ) public {
            //solhint-disable-next-line max-line-length
            require(
                _isApprovedOrOwner(msg.sender, tokenId),
                "ERC721: transfer caller is not owner nor approved"
            );
    
            _transferFrom(from, to, tokenId);
        }
    
        /**
         * @dev Safely transfers the ownership of a given token ID to another address
         * If the target address is a contract, it must implement {IERC721Receiver-onERC721Received},
         * which is called upon a safe transfer, and return the magic value
         * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
         * the transfer is reverted.
         * Requires the msg.sender to be the owner, approved, or operator
         * @param from current owner of the token
         * @param to address to receive the ownership of the given token ID
         * @param tokenId uint256 ID of the token to be transferred
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId
        ) public {
            safeTransferFrom(from, to, tokenId, "");
        }
    
        /**
         * @dev Safely transfers the ownership of a given token ID to another address
         * If the target address is a contract, it must implement {IERC721Receiver-onERC721Received},
         * which is called upon a safe transfer, and return the magic value
         * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
         * the transfer is reverted.
         * Requires the msg.sender to be the owner, approved, or operator
         * @param from current owner of the token
         * @param to address to receive the ownership of the given token ID
         * @param tokenId uint256 ID of the token to be transferred
         * @param _data bytes data to send along with a safe transfer check
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId,
            bytes memory _data
        ) public {
            transferFrom(from, to, tokenId);
            require(
                _checkOnERC721Received(from, to, tokenId, _data),
                "ERC721: transfer to non ERC721Receiver implementer"
            );
        }
    
        /**
         * @dev Returns whether the specified token exists.
         * @param tokenId uint256 ID of the token to query the existence of
         * @return bool whether the token exists
         */
        function _exists(uint256 tokenId) internal view returns (bool) {
            address owner = _tokenOwner[tokenId];
            return owner != address(0);
        }
    
        /**
         * @dev Returns whether the given spender can transfer a given token ID.
         * @param spender address of the spender to query
         * @param tokenId uint256 ID of the token to be transferred
         * @return bool whether the msg.sender is approved for the given token ID,
         * is an operator of the owner, or is the owner of the token
         */
        function _isApprovedOrOwner(address spender, uint256 tokenId)
            internal
            view
            returns (bool)
        {
            require(
                _exists(tokenId),
                "ERC721: operator query for nonexistent token"
            );
            address owner = ownerOf(tokenId);
            return (spender == owner ||
                getApproved(tokenId) == spender ||
                isApprovedForAll(owner, spender));
        }
    
        /**
         * @dev Internal function to mint a new token.
         * Reverts if the given token ID already exists.
         * @param to The address that will own the minted token
         * @param tokenId uint256 ID of the token to be minted
         */
        function _mint(address to, uint256 tokenId) internal {
            require(to != address(0), "ERC721: mint to the zero address");
            require(!_exists(tokenId), "ERC721: token already minted");
    
            _tokenOwner[tokenId] = to;
            _ownedTokensCount[to].increment();
    
            emit Transfer(address(0), to, tokenId);
        }
    
        /**
         * @dev Internal function to transfer ownership of a given token ID to another address.
         * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
         * @param from current owner of the token
         * @param to address to receive the ownership of the given token ID
         * @param tokenId uint256 ID of the token to be transferred
         */
        function _transferFrom(
            address from,
            address to,
            uint256 tokenId
        ) internal {
            require(
                ownerOf(tokenId) == from,
                "ERC721: transfer of token that is not own"
            );
            require(to != address(0), "ERC721: transfer to the zero address");
    
            _clearApproval(tokenId);
    
            _ownedTokensCount[from].decrement();
            _ownedTokensCount[to].increment();
    
            _tokenOwner[tokenId] = to;
    
            emit Transfer(from, to, tokenId);
        }
    
        /**
         * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
         * The call is not executed if the target address is not a contract.
         *
         * This function is deprecated.
         * @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
        ) internal returns (bool) {
            if (!to.isContract()) {
                return true;
            }
    
            bytes4 retval =
                IERC721Receiver(to).onERC721Received(
                    msg.sender,
                    from,
                    tokenId,
                    _data
                );
            return (retval == _ERC721_RECEIVED);
        }
    
        /**
         * @dev Private function to clear current approval of a given token ID.
         * @param tokenId uint256 ID of the token to be transferred
         */
        function _clearApproval(uint256 tokenId) private {
            if (_tokenApprovals[tokenId] != address(0)) {
                _tokenApprovals[tokenId] = address(0);
            }
        }
    }
    
    /**
     * @title Roles
     * @dev Library for managing addresses assigned to a Role.
     */
    library Roles {
        struct Role {
            mapping(address => bool) bearer;
        }
    
        /**
         * @dev Give an account access to this role.
         */
        function add(Role storage role, address account) internal {
            require(!has(role, account), "Roles: account already has role");
            role.bearer[account] = true;
        }
    
        /**
         * @dev Remove an account's access to this role.
         */
        function remove(Role storage role, address account) internal {
            require(has(role, account), "Roles: account does not have role");
            role.bearer[account] = false;
        }
    
        /**
         * @dev Check if an account has this role.
         * @return bool
         */
        function has(Role storage role, address account)
            internal
            view
            returns (bool)
        {
            require(account != address(0), "Roles: account is the zero address");
            return role.bearer[account];
        }
    }
    
    contract MinterRole {
        using Roles for Roles.Role;
    
        event MinterAdded(address indexed account);
        event MinterRemoved(address indexed account);
    
        Roles.Role private _minters;
    
        constructor() internal {
            _addMinter(msg.sender);
        }
    
        modifier onlyMinter() {
            require(
                isMinter(msg.sender),
                "MinterRole: caller does not have the Minter role"
            );
            _;
        }
    
        function isMinter(address account) public view returns (bool) {
            return _minters.has(account);
        }
    
        function addMinter(address account) public onlyMinter {
            _addMinter(account);
        }
    
        function renounceMinter() public {
            _removeMinter(msg.sender);
        }
    
        function _addMinter(address account) internal {
            _minters.add(account);
            emit MinterAdded(account);
        }
    
        function _removeMinter(address account) internal {
            _minters.remove(account);
            emit MinterRemoved(account);
        }
    }
    
    /**
     * @title ERC721Mintable
     * @dev ERC721 minting logic.
     */
    contract ERC721Mintable is ERC721, MinterRole {
    
        bool public anyoneCanMint;
        
        /**
         * @dev Options to activate or deactivate mint ability
         */
    
        function _setMintableOption(bool _anyoneCanMint) internal {
            anyoneCanMint = _anyoneCanMint;
        }
    
        /**
         * @dev Function to mint tokens.
         * @param to The address that will receive the minted tokens.
         * @param tokenId The token id to mint.
         * @return A boolean that indicates if the operation was successful.
         */
        function mint(address to, uint256 tokenId)
            public
            onlyMinter
            returns (bool)
        {
            _mint(to, tokenId);
            return true;
        }
    
        function canIMint() public view returns (bool) {
            return anyoneCanMint || isMinter(msg.sender);
        }
    
        /**
         * Open modifier to anyone can mint possibility
         */
        modifier onlyMinter() {
            string memory mensaje;
            require(
                canIMint(),
                "MinterRole: caller does not have the Minter role"
            );
            _;
        }
    
    }
    
    /**
     * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
     * @dev See https://eips.ethereum.org/EIPS/eip-721
     */
    contract IERC721Enumerable is IERC721 {
        function totalSupply() public view returns (uint256);
        function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256 tokenId);
        function tokenByIndex(uint256 index) public view returns (uint256);
    }
    
    /**
     * @title ERC-721 Non-Fungible Token with optional enumeration extension logic
     * @dev See https://eips.ethereum.org/EIPS/eip-721
     */
    contract ERC721Enumerable is ERC165, ERC721, IERC721Enumerable {
        // Mapping from owner to list of owned token IDs
        mapping(address => uint256[]) private _ownedTokens;
    
        // Mapping from token ID to index of the owner tokens list
        mapping(uint256 => uint256) private _ownedTokensIndex;
    
        // Array with all token ids, used for enumeration
        uint256[] private _allTokens;
    
        // Mapping from token id to position in the allTokens array
        mapping(uint256 => uint256) private _allTokensIndex;
    
        /*
         *     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 Constructor function.
         */
        constructor () public {
            // register the supported interface to conform to ERC721Enumerable via ERC165
            _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
        }
    
        /**
         * @dev Gets the token ID at a given index of the tokens list of the requested owner.
         * @param owner address owning the tokens list to be accessed
         * @param index uint256 representing the index to be accessed of the requested tokens list
         * @return uint256 token ID at the given index of the tokens list owned by the requested address
         */
        function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) {
            require(index < balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
            return _ownedTokens[owner][index];
        }
    
        /**
         * @dev Gets the total amount of tokens stored by the contract.
         * @return uint256 representing the total amount of tokens
         */
        function totalSupply() public view returns (uint256) {
            return _allTokens.length;
        }
    
        /**
         * @dev Gets the token ID at a given index of all the tokens in this contract
         * Reverts if the index is greater or equal to the total number of tokens.
         * @param index uint256 representing the index to be accessed of the tokens list
         * @return uint256 token ID at the given index of the tokens list
         */
        function tokenByIndex(uint256 index) public view returns (uint256) {
            require(index < totalSupply(), "ERC721Enumerable: global index out of bounds");
            return _allTokens[index];
        }
    
        /**
         * @dev Internal function to transfer ownership of a given token ID to another address.
         * As opposed to transferFrom, this imposes no restrictions on msg.sender.
         * @param from current owner of the token
         * @param to address to receive the ownership of the given token ID
         * @param tokenId uint256 ID of the token to be transferred
         */
        function _transferFrom(address from, address to, uint256 tokenId) internal {
            super._transferFrom(from, to, tokenId);
    
            _removeTokenFromOwnerEnumeration(from, tokenId);
    
            _addTokenToOwnerEnumeration(to, tokenId);
        }
    
        /**
         * @dev Internal function to mint a new token.
         * Reverts if the given token ID already exists.
         * @param to address the beneficiary that will own the minted token
         * @param tokenId uint256 ID of the token to be minted
         */
        function _mint(address to, uint256 tokenId) internal {
            super._mint(to, tokenId);
    
            _addTokenToOwnerEnumeration(to, tokenId);
    
            _addTokenToAllTokensEnumeration(tokenId);
        }
    
        /**
         * @dev Gets the list of token IDs of the requested owner.
         * @param owner address owning the tokens
         * @return uint256[] List of token IDs owned by the requested address
         */
        function _tokensOfOwner(address owner) internal view returns (uint256[] storage) {
            return _ownedTokens[owner];
        }
    
        /**
         * @dev Private function to add a token to this extension's ownership-tracking data structures.
         * @param to address representing the new owner of the given token ID
         * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
         */
        function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
            _ownedTokensIndex[tokenId] = _ownedTokens[to].length;
            _ownedTokens[to].push(tokenId);
        }
    
        /**
         * @dev Private function to add a token to this extension's token tracking data structures.
         * @param tokenId uint256 ID of the token to be added to the tokens list
         */
        function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
            _allTokensIndex[tokenId] = _allTokens.length;
            _allTokens.push(tokenId);
        }
    
        /**
         * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
         * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
         * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
         * This has O(1) time complexity, but alters the order of the _ownedTokens array.
         * @param from address representing the previous owner of the given token ID
         * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
         */
        function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
            // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
            // then delete the last slot (swap and pop).
    
            uint256 lastTokenIndex = _ownedTokens[from].length.sub(1);
            uint256 tokenIndex = _ownedTokensIndex[tokenId];
    
            // When the token to delete is the last token, the swap operation is unnecessary
            if (tokenIndex != lastTokenIndex) {
                uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
    
                _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
                _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
            }
    
            // This also deletes the contents at the last position of the array
            _ownedTokens[from].length--;
    
            // Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occupied by
            // lastTokenId, or just over the end of the array if the token was the last one).
        }
    
    }
    
    /**
     * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
     * @dev See https://eips.ethereum.org/EIPS/eip-721
     */
    contract IERC721Metadata is IERC721 {
        function name() external view returns (string memory);
        function symbol() external view returns (string memory);
        function tokenURI(uint256 tokenId) external view returns (string memory);
    }
    
    contract ERC721Metadata is ERC165, ERC721, IERC721Metadata {
        // Token name
        string private _name;
    
        // Token symbol
        string private _symbol;
    
        // Whether to display the real token URI
        bool public opened;
    
        // Optional mapping for token URIs
        mapping(uint256 => string) private _tokenURIs;
    
        /*
         *     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;
    
        /**
         * @dev Constructor function
         */
        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_METADATA);
        }
    
        /**
         * @dev Gets the token name.
         * @return string representing the token name
         */
        function name() external view returns (string memory) {
            return _name;
        }
    
        /**
         * @dev Gets the token symbol.
         * @return string representing the token symbol
         */
        function symbol() external view returns (string memory) {
            return _symbol;
        }
    
        /**
         * @dev Returns an URI for a given token ID.
         * Throws if the token ID does not exist. May return an empty string.
         * @param tokenId uint256 ID of the token to query
         */
        function tokenURI(uint256 tokenId) external view returns (string memory) {
            require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
            if (opened) {
                return _tokenURIs[tokenId];
            } else {
                return "https://nftstorage.link/ipfs/bafkreibtcne3eh64i2qggvmwded2o3hn42xch34fwed5awxkkmd7a6vu24";
            }
        }
    
        /**
         * @dev Internal function to set the token URI for a given token.
         * Reverts if the token ID does not exist.
         * @param tokenId uint256 ID of the token to set its URI
         * @param uri string URI to assign
         */
        function _setTokenURI(uint256 tokenId, string memory uri) internal {
            require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
            _tokenURIs[tokenId] = uri;
        }
    }
    
    /**
     * @title ERC721MetadataMintable
     * @dev ERC721 minting logic with metadata.
     */
    contract ERC721MetadataMintable is ERC721, ERC721Metadata, MinterRole {
        /**
         * @dev Function to mint tokens.
         * @param to The address that will receive the minted tokens.
         * @param tokenId The token id to mint.
         * @param tokenURI The token URI of the minted token.
         * @return A boolean that indicates if the operation was successful.
         */
        function mintWithTokenURI(address to, uint256 tokenId, string memory tokenURI) public onlyMinter returns (bool) {
            return _mintWithTokenURI(to, tokenId, tokenURI);
        }
    
        function _mintWithTokenURI(address to, uint256 tokenId, string memory tokenURI) internal returns (bool) {
            _mint(to, tokenId);
            _setTokenURI(tokenId, tokenURI);
            return true;
        } 
    }
    
    /**
     * @title ERC721
     * Full ERC-721 Token with automint function
     */
    
    contract ERC721Full is ERC721, ERC721Enumerable, ERC721Metadata, ERC721Mintable, ERC721MetadataMintable {
    
        uint256 autoTokenId;
        constructor (string memory name, string memory symbol, bool _anyoneCanMint) public 
            ERC721Mintable() 
            ERC721Metadata(name, symbol) {
            // solhint-disable-previous-line no-empty-blocks
    
            _setMintableOption(_anyoneCanMint);
    
        }
    
        function exists(uint256 tokenId) public view returns (bool) {
            return _exists(tokenId);
        }
    
        function tokensOfOwner(address owner) public view returns (uint256[] memory) {
            return _tokensOfOwner(owner);
        }
    
        function setTokenURI(uint256 tokenId, string memory uri) public {
            _setTokenURI(tokenId, uri);
        }
    
        /**
         * @dev Function to mint tokens with automatic ID
         * @param to The address that will receive the minted tokens.
         * @return A boolean that indicates if the operation was successful.
         */
        function autoMint(string memory tokenURI, address to) public onlyMinter returns (uint256) {
            do {
                autoTokenId++;
            } while(_exists(autoTokenId));
            _mint(to, autoTokenId);
            _setTokenURI(autoTokenId, tokenURI);
            return autoTokenId;
        }
    
        /**
         * @dev Function to transfer tokens
         * @param to The address that will receive the minted tokens.
         * @param tokenId the token ID
         */
        function transfer(
            address to,
            uint256 tokenId
        ) public {
            _transferFrom(msg.sender, to, tokenId);
        }
    
    }
    
    /**
     * @dev Contract module that helps prevent reentrant calls to a function.
     *
     * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
     * available, which can be aplied to functions to make sure there are no nested
     * (reentrant) calls to them.
     *
     * Note that because there is a single `nonReentrant` guard, functions marked as
     * `nonReentrant` may not call one another. This can be worked around by making
     * those functions `private`, and then adding `external` `nonReentrant` entry
     * points to them.
     */
    contract ReentrancyGuard {
        // counter to allow mutex lock with only one SSTORE operation
        uint256 private _guardCounter;
    
        constructor () internal {
            // The counter starts at one to prevent changing it from zero to a non-zero
            // value, which is a more expensive operation.
            _guardCounter = 1;
        }
    
        /**
         * @dev Prevents a contract from calling itself, directly or indirectly.
         * Calling a `nonReentrant` function from another `nonReentrant`
         * function is not supported. It is possible to prevent this from happening
         * by making the `nonReentrant` function external, and make it call a
         * `private` function that does the actual work.
         */
        modifier nonReentrant() {
            _guardCounter += 1;
            uint256 localCounter = _guardCounter;
            _;
            require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call");
        }
    }
    
    /**
     * @title ERC721Matcha
     * ERC-721 Marketplace
     */
    
    contract BananaTaskForceApeNft is ERC721Full, ReentrancyGuard {
    
        using SafeMath for uint256;
    
        using Address for address payable;
    
        // admin address, the owner of the marketplace
        address payable admin;
    
        address public contract_owner;
    
        // commission rate is a value from 0 to 100
        uint256 commissionRate;
    
        // last price sold or auctioned
        mapping(uint256 => uint256) public soldFor;
        
        // Mapping from token ID to sell price in Ether or to bid price, depending if it is an auction or not
        mapping(uint256 => uint256) public sellBidPrice;
    
        // Mapping payment address for tokenId 
        mapping(uint256 => address payable) private _wallets;
    
        event Sale(uint256 indexed tokenId, address indexed from, address indexed to, uint256 value);
        event Commission(uint256 indexed tokenId, address indexed to, uint256 value, uint256 rate, uint256 total);
    
        /*
    
        index   _isAuction  _sellBidPrice   Meaning
        0       true        0               Item 0 is on auction and no bids so far
        1       true        10              Item 1 is on auction and the last bid is for 10 Ethers
        2       false       0               Item 2 is not on auction nor for sell
        3       false       10              Item 3 is on sale for 10 Ethers
    
        */
    
        // Auction data
        struct Auction {
    
            // Parameters of the auction. Times are either
            // absolute unix timestamps (seconds since 1970-01-01)
            // or time periods in seconds.
            address payable beneficiary;
            uint auctionEnd;
    
            // Current state of the auction.
            address payable highestBidder;
            uint highestBid;
    
            // Set to true at the end, disallows any change
            bool open;
    
            // minimum reserve price in wei
            uint256 reserve;
    
        }
    
        // mapping auctions for each tokenId
        mapping(uint256 => Auction) public auctions;
    
        // Events that will be fired on changes.
        event Refund(address bidder, uint amount);
        event HighestBidIncreased(address indexed bidder, uint amount, uint256 tokenId);
        event AuctionEnded(address winner, uint amount);
    
        event LimitSell(address indexed from, address indexed to, uint256 amount);
        event LimitBuy(address indexed from, address indexed to, uint256 amount);
        event MarketSell(address indexed from, address indexed to, uint256 amount);
        event MarketBuy(address indexed from, address indexed to, uint256 amount);
    
    
        constructor() public 
            ERC721Full("Banana Task Force Ape", "BTFA", false) {
            admin = 0x024cd9a40a7f780d9F3582496A5f3c00bb22c3C6;
            contract_owner = msg.sender;
            commissionRate = 15;
    
            onlyWhitelist = true;
            whitelistLimit = 10;
            buyLimit = 5;
            reserveLimit = 500;
    
            cost = 99 * 10 ** 15;
            total = 10000;
            remaining = 10000;
        }
    
        function canSell(uint256 tokenId) public view returns (bool) {
            return (ownerOf(tokenId)==msg.sender && !auctions[tokenId].open);
        }
    
        // Sell option for a fixed price
        function sell(uint256 tokenId, uint256 price, address payable wallet) public {
    
            // onlyOwner
            require(ownerOf(tokenId)==msg.sender, "ERC721Matcha: Only owner can sell this item");
    
            // cannot set a price if auction is activated
            require(!auctions[tokenId].open, "ERC721Matcha: Cannot sell an item which has an active auction");
    
            // set sell price for index
            sellBidPrice[tokenId] = price;
    
            // If price is zero, means not for sale
            if (price>0) {
    
                // approve the Index to the current contract
                approve(address(this), tokenId);
                
                // set wallet payment
                _wallets[tokenId] = wallet;
                
            }
    
        }
    
        // simple function to return the price of a tokenId
        // returns: sell price, bid price, sold price, only one can be non zero
        function getPrice(uint256 tokenId) public view returns (uint256, uint256, uint256) {
            if (sellBidPrice[tokenId]>0) return (sellBidPrice[tokenId], 0, 0);
            if (auctions[tokenId].highestBid>0) return (0, auctions[tokenId].highestBid, 0);
            return (0, 0, soldFor[tokenId]);
        }
    
        function canBuy(uint256 tokenId) public view returns (uint256) {
            if (!auctions[tokenId].open && sellBidPrice[tokenId]>0 && sellBidPrice[tokenId]>0 && getApproved(tokenId) == address(this)) {
                return sellBidPrice[tokenId];
            } else {
                return 0;
            }
        }
    
        // Buy option
        function buy(uint256 tokenId) public payable nonReentrant {
    
            // is on sale
            require(!auctions[tokenId].open && sellBidPrice[tokenId]>0, "ERC721Matcha: The collectible is not for sale");
    
            // transfer funds
            require(msg.value >= sellBidPrice[tokenId], "ERC721Matcha: Not enough funds");
    
            // transfer ownership
            address owner = ownerOf(tokenId);
    
            require(msg.sender!=owner, "ERC721Matcha: The seller cannot buy his own collectible");
    
            // we need to call a transferFrom from this contract, which is the one with permission to sell the NFT
            callOptionalReturn(this, abi.encodeWithSelector(this.transferFrom.selector, owner, msg.sender, tokenId));
    
            // calculate amounts
            uint256 amount4admin = msg.value.mul(commissionRate).div(100);
            uint256 amount4owner = msg.value.sub(amount4admin);
    
            // to owner
            (bool success, ) = _wallets[tokenId].call.value(amount4owner)("");
            require(success, "Transfer failed.");
    
            // to admin
            (bool success2, ) = admin.call.value(amount4admin)("");
            require(success2, "Transfer failed.");
    
            // close the sell
            sellBidPrice[tokenId] = 0;
            _wallets[tokenId] = address(0);
    
            soldFor[tokenId] = msg.value;
    
            emit Sale(tokenId, owner, msg.sender, msg.value);
            emit Commission(tokenId, owner, msg.value, commissionRate, amount4admin);
    
        }
    
        function canAuction(uint256 tokenId) public view returns (bool) {
            return (ownerOf(tokenId)==msg.sender && !auctions[tokenId].open && sellBidPrice[tokenId]==0);
        }
    
        // Instantiate an auction contract for a tokenId
        function createAuction(uint256 tokenId, uint _closingTime, address payable _beneficiary, uint256 _reservePrice) public {
    
            require(sellBidPrice[tokenId]==0, "ERC721Matcha: The selected NFT is open for sale, cannot be auctioned");
            require(!auctions[tokenId].open, "ERC721Matcha: The selected NFT already has an auction");
            require(ownerOf(tokenId)==msg.sender, "ERC721Matcha: Only owner can auction this item");
    
            auctions[tokenId].beneficiary = _beneficiary;
            auctions[tokenId].auctionEnd = _closingTime;
            auctions[tokenId].reserve = _reservePrice;
            auctions[tokenId].open = true;
    
            // approve the Index to the current contract
            approve(address(this), tokenId);
    
        }
    
        function canBid(uint256 tokenId) public view returns (bool) {
            if (!msg.sender.isContract() &&
                auctions[tokenId].open &&
                now <= auctions[tokenId].auctionEnd &&
                msg.sender != ownerOf(tokenId) &&
                getApproved(tokenId) == address(this)
            ) {
                return true;
            } else {
                return false;
            }
        }
    
        /// Bid on the auction with the value sent
        /// together with this transaction.
        /// The value will only be refunded if the
        /// auction is not won.
        function bid(uint256 tokenId) public payable nonReentrant {
            // No arguments are necessary, all
            // information is already part of
            // the transaction. The keyword payable
            // is required for the function to
            // be able to receive Ether.
    
            // Contracts cannot bid, because they can block the auction with a reentrant attack
            require(!msg.sender.isContract(), "No script kiddies");
    
            // auction has to be opened
            require(auctions[tokenId].open, "No opened auction found");
    
            // approve was lost
            require(getApproved(tokenId) == address(this), "Cannot complete the auction");
    
            // Revert the call if the bidding
            // period is over.
            require(
                now <= auctions[tokenId].auctionEnd,
                "Auction already ended."
            );
    
            // If the bid is not higher, send the
            // money back.
            require(
                msg.value > auctions[tokenId].highestBid,
                "There already is a higher bid."
            );
    
            address owner = ownerOf(tokenId);
            require(msg.sender!=owner, "ERC721Matcha: The owner cannot bid his own collectible");
    
            // return the funds to the previous bidder, if there is one
            if (auctions[tokenId].highestBid>0) {
                (bool success, ) = auctions[tokenId].highestBidder.call.value(auctions[tokenId].highestBid)("");
                require(success, "Transfer failed.");
                emit Refund(auctions[tokenId].highestBidder, auctions[tokenId].highestBid);
            }
    
            // now store the bid data
            auctions[tokenId].highestBidder = msg.sender;
            auctions[tokenId].highestBid = msg.value;
            emit HighestBidIncreased(msg.sender, msg.value, tokenId);
    
        }
    
        // anyone can execute withdraw if auction is opened and 
        // the bid time expired and the reserve was not met
        // or
        // the auction is openen but the contract is unable to transfer
        function canWithdraw(uint256 tokenId) public view returns (bool) {
            if (auctions[tokenId].open && 
                (
                    (
                        now >= auctions[tokenId].auctionEnd &&
                        auctions[tokenId].highestBid > 0 &&
                        auctions[tokenId].highestBid<auctions[tokenId].reserve
                    ) || 
                    getApproved(tokenId) != address(this)
                )
            ) {
                return true;
            } else {
                return false;
            }
        }
    
        /// Withdraw a bid when the auction is not finalized
        function withdraw(uint256 tokenId) public nonReentrant returns (bool) {
    
            require(canWithdraw(tokenId), "Conditions to withdraw are not met");
    
            // transfer funds to highest bidder always
            if (auctions[tokenId].highestBid > 0) {
                (bool success, ) = auctions[tokenId].highestBidder.call.value(auctions[tokenId].highestBid)("");
                require(success, "Transfer failed.");
            }
    
            // finalize the auction
            delete auctions[tokenId];
    
        }
    
        function canFinalize(uint256 tokenId) public view returns (bool) {
            if (auctions[tokenId].open && 
                now >= auctions[tokenId].auctionEnd &&
                (
                    auctions[tokenId].highestBid>=auctions[tokenId].reserve || 
                    auctions[tokenId].highestBid==0
                )
            ) {
                return true;
            } else {
                return false;
            }
        }
    
        // implement the auctionFinalize including the NFT transfer logic
        function auctionFinalize(uint256 tokenId) public nonReentrant {
    
            require(canFinalize(tokenId), "Cannot finalize");
    
            if (auctions[tokenId].highestBid>0) {
    
                // transfer the ownership of token to the highest bidder
                address payable highestBidder = auctions[tokenId].highestBidder;
    
                // calculate payment amounts
                uint256 amount4admin = auctions[tokenId].highestBid.mul(commissionRate).div(100);
                uint256 amount4owner = auctions[tokenId].highestBid.sub(amount4admin);
    
                // to owner
                (bool success, ) = auctions[tokenId].beneficiary.call.value(amount4owner)("");
                require(success, "Transfer failed.");
    
                // to admin
                (bool success2, ) = admin.call.value(amount4admin)("");
                require(success2, "Transfer failed.");
    
                emit Sale(tokenId, auctions[tokenId].beneficiary, highestBidder, auctions[tokenId].highestBid);
                emit Commission(tokenId, auctions[tokenId].beneficiary, auctions[tokenId].highestBid, commissionRate, amount4admin);
    
                // transfer ownership
                address owner = ownerOf(tokenId);
    
                // we need to call a transferFrom from this contract, which is the one with permission to sell the NFT
                // transfer the NFT to the auction's highest bidder
                callOptionalReturn(this, abi.encodeWithSelector(this.transferFrom.selector, owner, highestBidder, tokenId));
    
                soldFor[tokenId] = auctions[tokenId].highestBid;
    
            }
    
            emit AuctionEnded(auctions[tokenId].highestBidder, auctions[tokenId].highestBid);
    
            // finalize the auction
            delete auctions[tokenId];
    
        }
    
        // Bid query functions
        function highestBidder(uint256 tokenId) public view returns (address payable) {
            return auctions[tokenId].highestBidder;
        }
    
        function highestBid(uint256 tokenId) public view returns (uint256) {
            return auctions[tokenId].highestBid;
        }
    
        /**
         * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
         * on the return value: the return value is optional (but if data is returned, it must not be false).
         * @param token The token targeted by the call.
         * @param data The call data (encoded using abi.encode or one of its variants).
         */
        function callOptionalReturn(IERC721 token, bytes memory data) private {
            // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
            // we're implementing it ourselves.
    
            // A Solidity high level call has three parts:
            //  1. The target address is checked to verify it contains contract code
            //  2. The call itself is made, and success asserted
            //  3. The return value is decoded, which in turn checks the size of the returned data.
            // solhint-disable-next-line max-line-length
            require(address(token).isContract(), "SafeERC721: call to non-contract");
    
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = address(token).call(data);
            require(success, "SafeERC721: low-level call failed");
    
            if (returndata.length > 0) { // Return data is optional
                // solhint-disable-next-line max-line-length
                require(abi.decode(returndata, (bool)), "SafeERC721: ERC20 operation did not succeed");
            }
        }
    
        // Blindbox Sales
    
        bool public enabled;
        uint256 public reserved;
        uint256 public reserveLimit;
        bool public onlyWhitelist;
        uint256 public whitelistLimit;
        uint256 public buyLimit;
    
        uint256 public totalCreated;
        mapping(address => uint256[]) private ownerBoxes;
        mapping(address => bool) public whitelist;
    
        uint private nonce = 0;
    
        uint256 cost;
        uint256 total;
        uint256 remaining;
    
        struct Blindbox {
            uint256 id;
            address purchaser;
            uint256 tokenID;
        }
    
        modifier onlyOwner() {
            require(msg.sender == contract_owner, "can only be called by the contract owner");
            _;
        }
    
        modifier isEnabled() {
            require(enabled, "Contract is currently disabled");
            _;
        }
    
        function status() public view returns (bool canPurchase, uint256 boxCost, uint256 boxRemaining, uint256 hasPurchased, uint256 purchaseLimit) {
            canPurchase = enabled && ((onlyWhitelist == false && ownerBoxes[msg.sender].length < buyLimit) || (whitelist[msg.sender] && ownerBoxes[msg.sender].length < whitelistLimit));
            boxCost = cost;
            boxRemaining = remaining;
            hasPurchased = ownerBoxes[msg.sender].length;
            purchaseLimit = whitelistLimit;
        }
    
        function purchaseBlindbox() public payable isEnabled {
            require (remaining > 0, "No more blindboxes available");
            require((onlyWhitelist == false && ownerBoxes[msg.sender].length < buyLimit) || (whitelist[msg.sender] && ownerBoxes[msg.sender].length < whitelistLimit), "You are not on the whitelist");
            require (msg.value == cost, "Incorrect BNB value.");
    
            admin.transfer(cost);
    
            mint(msg.sender);
        }
    
    
        // Private methods
    
        function mint(address who) private {
            uint256 request = requestRandomWords();
            uint256 roll = request.mod(total).add(1);
    
            while (exists(roll)) {
                roll++;
    
                if (roll > total) {
                    roll = 1;
                }
            }
    
            string memory uri = string(abi.encodePacked("https://nftstorage.link/ipfs/bafybeic2hzyfaxo7gvezfnllsgxusjpb6rj6s77vru34yhbnghdjkxv3xe/", uint2str(roll), ".json"));
            remaining--;
            require(_mintWithTokenURI(who, roll, uri), "Minting error");
            ownerBoxes[who].push(roll);
        }
    
        function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
            if (_i == 0) {
                return "0";
            }
            uint j = _i;
            uint len;
            while (j != 0) {
                len++;
                j /= 10;
            }
            bytes memory bstr = new bytes(len);
            uint k = len - 1;
            while (_i != 0) {
                bstr[k--] = byte(uint8(48 + _i % 10));
                _i /= 10;
            }
            return string(bstr);
        }
    
        function requestRandomWords() private returns (uint256) {
            nonce += 1;
            return uint(keccak256(abi.encodePacked(nonce, msg.sender, blockhash(block.number - 1))));
        }
    
    
        // Admin Only
    
        // update contract fields
        function updateAdmin(address payable _admin, uint256 _commissionRate, bool _anyoneCanMint) public onlyOwner {
            admin=_admin;
            commissionRate=_commissionRate;
            anyoneCanMint=_anyoneCanMint;
        }
    
        function changeOwner(address who) external onlyOwner {
            contract_owner = who;
        } 
    
        function openBoxes() external onlyOwner {
            opened = true;
        } 
    
        function setPrice(uint256 price) external onlyOwner {
            cost = price;
        }
    
        function setEnabled(bool canPurchase) external onlyOwner {
            enabled = canPurchase;
        }
    
        function enableWhitelist(bool on) external onlyOwner {
            onlyWhitelist = on;
        }
    
        function setWhitelist(address who, bool whitelisted) external onlyOwner {
            whitelist[who] = whitelisted;
        }
    
        function setWhitelisted(address[] calldata who, bool whitelisted) external onlyOwner {
            for (uint256 i = 0; i < who.length; i++) {
                whitelist[who[i]] = whitelisted;
            }
        }
    
        function setBuyLimits(uint256 white, uint256 normal) external onlyOwner {
            whitelistLimit = white;
            buyLimit = normal;
        }
    
        function reserveNfts(address who, uint256 amount) external onlyOwner {
            require(reserved + amount <= reserveLimit, "NFTS have already been reserved");
    
            for (uint256 i = 0; i < amount; i++) {
                mint(who);
            }
    
            reserved += amount;
        }
    
    }