ETH Price: $2,147.44 (+0.53%)

Transaction Decoder

Block:
10715212 at Aug-23-2020 07:27:10 AM +UTC
Transaction Fee:
0.01588605 ETH $34.11
Gas Used:
211,814 Gas / 75 Gwei

Emitted Events:

152 MintableToken.Transfer( from=0x9ddae9b61b790e16d4fe92a6ede1339da0f9e7bd, to=[Sender] 0x3433c2753da24df566ea14c40584179e97396cf3, tokenId=5867 )
153 0xa5af48b105ddf2fa73cbaac61d420ea31b3c2a07.0x7a212d757c7290587e1c8f7100a01a3d09466d58945058b6f22a179013475a90( 0x7a212d757c7290587e1c8f7100a01a3d09466d58945058b6f22a179013475a90, 0x00000000000000000000000060f80121c31a0d46b5279700f9df786054aa5ee5, 0x00000000000000000000000000000000000000000000000000000000000016eb, 0000000000000000000000009ddae9b61b790e16d4fe92a6ede1339da0f9e7bd, 0000000000000000000000003433c2753da24df566ea14c40584179e97396cf3, 0000000000000000000000000000000000000000000000000186cc6acd4b0000, 0000000000000000000000000000000000000000000000000000000000000001 )

Account State Difference:

  Address   Before After State Difference Code
0x3433C275...e97396cf3
2.247648491793963823 Eth
Nonce: 175
2.121762441793963823 Eth
Nonce: 176
0.12588605
0x60F80121...054aa5eE5
0x9DDaE9B6...dA0F9e7BD 5.284739745529018515 Eth5.394739745529018515 Eth0.11
(Ethermine)
925.61130603401321764 Eth925.62719208401321764 Eth0.01588605
0xefAefA82...7aC9D54AF

Execution Trace

ETH 0.11 0xa5af48b105ddf2fa73cbaac61d420ea31b3c2a07.39b4d0b8( )
  • MintableToken.ownerOf( tokenId=5867 ) => ( 0x9DDaE9B61B790E16d4Fe92A6eDE1339dA0F9e7BD )
  • ERC721SaleNonceHolder.getNonce( token=0x60F80121C31A0d46B5279700f9DF786054aa5eE5, tokenId=5867 ) => ( 0 )
    • TokenSale.getNonce( token=0x60F80121C31A0d46B5279700f9DF786054aa5eE5, tokenId=5867 ) => ( 0 )
    • Null: 0x000...001.4c01cc47( )
    • TransferProxy.erc721safeTransferFrom( token=0x60F80121C31A0d46B5279700f9DF786054aa5eE5, from=0x9DDaE9B61B790E16d4Fe92A6eDE1339dA0F9e7BD, to=0x3433C2753da24Df566eA14c40584179e97396cf3, tokenId=5867 )
      • MintableToken.safeTransferFrom( from=0x9DDaE9B61B790E16d4Fe92A6eDE1339dA0F9e7BD, to=0x3433C2753da24Df566eA14c40584179e97396cf3, tokenId=5867 )
      • ETH 0.11 0x9ddae9b61b790e16d4fe92a6ede1339da0f9e7bd.CALL( )
      • ERC721SaleNonceHolder.setNonce( token=0x60F80121C31A0d46B5279700f9DF786054aa5eE5, tokenId=5867, nonce=1 )
        File 1 of 4: MintableToken
        pragma solidity ^0.5.0;
        pragma experimental ABIEncoderV2;
        
        /*
         * @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.
         */
        contract Context {
            // Empty internal constructor, to prevent people from mistakenly deploying
            // an instance of this contract, which should be used via inheritance.
            constructor () internal { }
            // solhint-disable-previous-line no-empty-blocks
        
            function _msgSender() internal view returns (address payable) {
                return msg.sender;
            }
        
            function _msgData() internal view returns (bytes memory) {
                this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                return msg.data;
            }
        }
        
        /**
         * @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.
         *
         * 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.
         */
        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 returns (address) {
                return _owner;
            }
        
            /**
             * @dev Throws if called by any account other than the owner.
             */
            modifier onlyOwner() {
                require(isOwner(), "Ownable: caller is not the owner");
                _;
            }
        
            /**
             * @dev Returns true if the caller is the current owner.
             */
            function isOwner() public view returns (bool) {
                return _msgSender() == _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 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 onlyOwner {
                _transferOwnership(newOwner);
            }
        
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             */
            function _transferOwnership(address newOwner) internal {
                require(newOwner != address(0), "Ownable: new owner is the zero address");
                emit OwnershipTransferred(_owner, newOwner);
                _owner = newOwner;
            }
        }
        
        /**
         * @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 {setApprovalForAll}.
             */
            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 {setApprovalForAll}.
             */
            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 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);
        }
        
        /**
         * @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-safeTransferFrom}. 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) {
                return sub(a, b, "SafeMath: subtraction overflow");
            }
        
            /**
             * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
             * overflow (when the result is negative).
             *
             * Counterpart to Solidity's `-` operator.
             *
             * Requirements:
             * - Subtraction cannot overflow.
             *
             * _Available since v2.4.0._
             */
            function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                require(b <= a, errorMessage);
                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-contracts/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) {
                return div(a, b, "SafeMath: division by zero");
            }
        
            /**
             * @dev Returns the integer division of two unsigned integers. Reverts with custom message 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.
             *
             * _Available since v2.4.0._
             */
            function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                // Solidity only automatically asserts when dividing by 0
                require(b > 0, errorMessage);
                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) {
                return mod(a, b, "SafeMath: modulo by zero");
            }
        
            /**
             * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
             * Reverts with custom message 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.
             *
             * _Available since v2.4.0._
             */
            function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                require(b != 0, errorMessage);
                return a % b;
            }
        }
        
        /**
         * @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) {
                // 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 != accountHash && codehash != 0x0);
            }
        
            /**
             * @dev Converts an `address` into `address payable`. Note that this is
             * simply a type cast: the actual underlying value is not changed.
             *
             * _Available since v2.4.0._
             */
            function toPayable(address account) internal pure returns (address payable) {
                return address(uint160(account));
            }
        
            /**
             * @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].
             *
             * _Available since v2.4.0._
             */
            function sendValue(address payable recipient, uint256 amount) internal {
                require(address(this).balance >= amount, "Address: insufficient balance");
        
                // solhint-disable-next-line avoid-call-value
                (bool success, ) = recipient.call.value(amount)("");
                require(success, "Address: unable to send value, recipient may have reverted");
            }
        }
        
        /**
         * @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 {
                // The {SafeMath} overflow check can be skipped here, see the comment at the top
                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 Context, 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(_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
                    "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 != _msgSender(), "ERC721: approve to caller");
        
                _operatorApprovals[_msgSender()][to] = approved;
                emit ApprovalForAll(_msgSender(), 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(_msgSender(), 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 _msgSender() 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 {
                require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
                _safeTransferFrom(from, to, tokenId, _data);
            }
        
            /**
             * @dev Safely transfers the ownership of a given token ID to another address
             * If the target address is a contract, it must implement `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) internal {
                _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 safely mint a new token.
             * Reverts if the given token ID already exists.
             * If the target address is a contract, it must implement `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.
             * @param to The address that will own the minted token
             * @param tokenId uint256 ID of the token to be minted
             */
            function _safeMint(address to, uint256 tokenId) internal {
                _safeMint(to, tokenId, "");
            }
        
            /**
             * @dev Internal function to safely mint a new token.
             * Reverts if the given token ID already exists.
             * If the target address is a contract, it must implement `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.
             * @param to The address that will own the minted token
             * @param tokenId uint256 ID of the token to be minted
             * @param _data bytes data to send along with a safe transfer check
             */
            function _safeMint(address to, uint256 tokenId, bytes memory _data) internal {
                _mint(to, tokenId);
                require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
            }
        
            /**
             * @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 burn a specific token.
             * Reverts if the token does not exist.
             * Deprecated, use {_burn} instead.
             * @param owner owner of the token to burn
             * @param tokenId uint256 ID of the token being burned
             */
            function _burn(address owner, uint256 tokenId) internal {
                require(ownerOf(tokenId) == owner, "ERC721: burn of token that is not own");
        
                _clearApproval(tokenId);
        
                _ownedTokensCount[owner].decrement();
                _tokenOwner[tokenId] = address(0);
        
                emit Transfer(owner, address(0), tokenId);
            }
        
            /**
             * @dev Internal function to burn a specific token.
             * Reverts if the token does not exist.
             * @param tokenId uint256 ID of the token being burned
             */
            function _burn(uint256 tokenId) internal {
                _burn(ownerOf(tokenId), 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 is an internal detail of the `ERC721` contract and its use 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;
                }
                // solhint-disable-next-line avoid-low-level-calls
                (bool success, bytes memory returndata) = to.call(abi.encodeWithSelector(
                    IERC721Receiver(to).onERC721Received.selector,
                    _msgSender(),
                    from,
                    tokenId,
                    _data
                ));
                if (!success) {
                    if (returndata.length > 0) {
                        // solhint-disable-next-line no-inline-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert("ERC721: transfer to non ERC721Receiver implementer");
                    }
                } else {
                    bytes4 retval = abi.decode(returndata, (bytes4));
                    return (retval == _ERC721_RECEIVED);
                }
            }
        
            /**
             * @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 ERC721 Burnable Token
         * @dev ERC721 Token that can be irreversibly burned (destroyed).
         */
        contract ERC721Burnable is Context, ERC721 {
            /**
             * @dev Burns a specific ERC721 token.
             * @param tokenId uint256 id of the ERC721 token to be burned.
             */
            function burn(uint256 tokenId) public {
                //solhint-disable-next-line max-line-length
                require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721Burnable: caller is not owner nor approved");
                _burn(tokenId);
            }
        }
        
        /**
         * @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 Context, 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 Internal function to burn a specific token.
             * Reverts if the token does not exist.
             * Deprecated, use {ERC721-_burn} instead.
             * @param owner owner of the token to burn
             * @param tokenId uint256 ID of the token being burned
             */
            function _burn(address owner, uint256 tokenId) internal {
                super._burn(owner, tokenId);
        
                _removeTokenFromOwnerEnumeration(owner, tokenId);
                // Since tokenId will be deleted, we can clear its slot in _ownedTokensIndex to trigger a gas refund
                _ownedTokensIndex[tokenId] = 0;
        
                _removeTokenFromAllTokensEnumeration(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).
            }
        
            /**
             * @dev Private function to remove a token from this extension's token tracking data structures.
             * This has O(1) time complexity, but alters the order of the _allTokens array.
             * @param tokenId uint256 ID of the token to be removed from the tokens list
             */
            function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
                // To prevent a gap in the 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 = _allTokens.length.sub(1);
                uint256 tokenIndex = _allTokensIndex[tokenId];
        
                // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
                // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
                // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
                uint256 lastTokenId = _allTokens[lastTokenIndex];
        
                _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
                _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
        
                // This also deletes the contents at the last position of the array
                _allTokens.length--;
                _allTokensIndex[tokenId] = 0;
            }
        }
        
        library UintLibrary {
            function toString(uint256 _i) internal pure returns (string memory) {
                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);
            }
        }
        
        library StringLibrary {
            using UintLibrary for uint256;
        
            function append(string memory _a, string memory _b) internal pure returns (string memory) {
                bytes memory _ba = bytes(_a);
                bytes memory _bb = bytes(_b);
                bytes memory bab = new bytes(_ba.length + _bb.length);
                uint k = 0;
                for (uint i = 0; i < _ba.length; i++) bab[k++] = _ba[i];
                for (uint i = 0; i < _bb.length; i++) bab[k++] = _bb[i];
                return string(bab);
            }
        
            function append(string memory _a, string memory _b, string memory _c) internal pure returns (string memory) {
                bytes memory _ba = bytes(_a);
                bytes memory _bb = bytes(_b);
                bytes memory _bc = bytes(_c);
                bytes memory bbb = new bytes(_ba.length + _bb.length + _bc.length);
                uint k = 0;
                for (uint i = 0; i < _ba.length; i++) bbb[k++] = _ba[i];
                for (uint i = 0; i < _bb.length; i++) bbb[k++] = _bb[i];
                for (uint i = 0; i < _bc.length; i++) bbb[k++] = _bc[i];
                return string(bbb);
            }
        
            function recover(string memory message, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
                bytes memory msgBytes = bytes(message);
                bytes memory fullMessage = concat(
                    bytes("\x19Ethereum Signed Message:\n"),
                    bytes(msgBytes.length.toString()),
                    msgBytes,
                    new bytes(0), new bytes(0), new bytes(0), new bytes(0)
                );
                return ecrecover(keccak256(fullMessage), v, r, s);
            }
        
            function concat(bytes memory _ba, bytes memory _bb, bytes memory _bc, bytes memory _bd, bytes memory _be, bytes memory _bf, bytes memory _bg) internal pure returns (bytes memory) {
                bytes memory resultBytes = new bytes(_ba.length + _bb.length + _bc.length + _bd.length + _be.length + _bf.length + _bg.length);
                uint k = 0;
                for (uint i = 0; i < _ba.length; i++) resultBytes[k++] = _ba[i];
                for (uint i = 0; i < _bb.length; i++) resultBytes[k++] = _bb[i];
                for (uint i = 0; i < _bc.length; i++) resultBytes[k++] = _bc[i];
                for (uint i = 0; i < _bd.length; i++) resultBytes[k++] = _bd[i];
                for (uint i = 0; i < _be.length; i++) resultBytes[k++] = _be[i];
                for (uint i = 0; i < _bf.length; i++) resultBytes[k++] = _bf[i];
                for (uint i = 0; i < _bg.length; i++) resultBytes[k++] = _bg[i];
                return resultBytes;
            }
        }
        
        contract HasContractURI is ERC165 {
        
            string public contractURI;
        
            /*
             * bytes4(keccak256('contractURI()')) == 0xe8a3d485
             */
            bytes4 private constant _INTERFACE_ID_CONTRACT_URI = 0xe8a3d485;
        
            constructor(string memory _contractURI) public {
                contractURI = _contractURI;
                _registerInterface(_INTERFACE_ID_CONTRACT_URI);
            }
        
            /**
             * @dev Internal function to set the contract URI
             * @param _contractURI string URI prefix to assign
             */
            function _setContractURI(string memory _contractURI) internal {
                contractURI = _contractURI;
            }
        }
        
        contract HasTokenURI {
            using StringLibrary for string;
        
            //Token URI prefix
            string public tokenURIPrefix;
        
            // Optional mapping for token URIs
            mapping(uint256 => string) private _tokenURIs;
        
            constructor(string memory _tokenURIPrefix) public {
                tokenURIPrefix = _tokenURIPrefix;
            }
        
            /**
             * @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) internal view returns (string memory) {
                return tokenURIPrefix.append(_tokenURIs[tokenId]);
            }
        
            /**
             * @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 {
                _tokenURIs[tokenId] = uri;
            }
        
            /**
             * @dev Internal function to set the token URI prefix.
             * @param _tokenURIPrefix string URI prefix to assign
             */
            function _setTokenURIPrefix(string memory _tokenURIPrefix) internal {
                tokenURIPrefix = _tokenURIPrefix;
            }
        
            function _clearTokenURI(uint256 tokenId) internal {
                if (bytes(_tokenURIs[tokenId]).length != 0) {
                    delete _tokenURIs[tokenId];
                }
            }
        }
        
        contract HasSecondarySaleFees is ERC165 {
        
            event SecondarySaleFees(uint256 tokenId, address[] recipients, uint[] bps);
        
            /*
             * bytes4(keccak256('getFeeBps(uint256)')) == 0x0ebd4c7f
             * bytes4(keccak256('getFeeRecipients(uint256)')) == 0xb9c4d9fb
             *
             * => 0x0ebd4c7f ^ 0xb9c4d9fb == 0xb7799584
             */
            bytes4 private constant _INTERFACE_ID_FEES = 0xb7799584;
        
            constructor() public {
                _registerInterface(_INTERFACE_ID_FEES);
            }
        
            function getFeeRecipients(uint256 id) public view returns (address payable[] memory);
            function getFeeBps(uint256 id) public view returns (uint[] memory);
        }
        
        /**
         * @title Full ERC721 Token with support for tokenURIPrefix
         * This implementation includes all the required and some optional functionality of the ERC721 standard
         * Moreover, it includes approve all functionality using operator terminology
         * @dev see https://eips.ethereum.org/EIPS/eip-721
         */
        contract ERC721Base is HasSecondarySaleFees, ERC721, HasContractURI, HasTokenURI, ERC721Enumerable {
            // Token name
            string public name;
        
            // Token symbol
            string public symbol;
        
            struct Fee {
                address payable recipient;
                uint256 value;
            }
        
            // id => fees
            mapping (uint256 => Fee[]) public fees;
        
            /*
             *     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, string memory contractURI, string memory _tokenURIPrefix) HasContractURI(contractURI) HasTokenURI(_tokenURIPrefix) public {
                name = _name;
                symbol = _symbol;
        
                // register the supported interfaces to conform to ERC721 via ERC165
                _registerInterface(_INTERFACE_ID_ERC721_METADATA);
            }
        
            function getFeeRecipients(uint256 id) public view returns (address payable[] memory) {
                Fee[] memory _fees = fees[id];
                address payable[] memory result = new address payable[](_fees.length);
                for (uint i = 0; i < _fees.length; i++) {
                    result[i] = _fees[i].recipient;
                }
                return result;
            }
        
            function getFeeBps(uint256 id) public view returns (uint[] memory) {
                Fee[] memory _fees = fees[id];
                uint[] memory result = new uint[](_fees.length);
                for (uint i = 0; i < _fees.length; i++) {
                    result[i] = _fees[i].value;
                }
                return result;
            }
        
            function _mint(address to, uint256 tokenId, Fee[] memory _fees) internal {
                _mint(to, tokenId);
                address[] memory recipients = new address[](_fees.length);
                uint[] memory bps = new uint[](_fees.length);
                for (uint i = 0; i < _fees.length; i++) {
                    require(_fees[i].recipient != address(0x0), "Recipient should be present");
                    require(_fees[i].value != 0, "Fee value should be positive");
                    fees[tokenId].push(_fees[i]);
                    recipients[i] = _fees[i].recipient;
                    bps[i] = _fees[i].value;
                }
                if (_fees.length > 0) {
                    emit SecondarySaleFees(tokenId, recipients, bps);
                }
            }
        
            /**
             * @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");
                return super._tokenURI(tokenId);
            }
        
            /**
             * @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");
                super._setTokenURI(tokenId, uri);
            }
        
            /**
             * @dev Internal function to burn a specific token.
             * Reverts if the token does not exist.
             * Deprecated, use _burn(uint256) instead.
             * @param owner owner of the token to burn
             * @param tokenId uint256 ID of the token being burned by the msg.sender
             */
            function _burn(address owner, uint256 tokenId) internal {
                super._burn(owner, tokenId);
                _clearTokenURI(tokenId);
            }
        }
        
        
        
        
        
        
        
        /**
         * @title MintableToken
         * @dev anyone can mint token.
         */
        contract MintableToken is Ownable, IERC721, IERC721Metadata, ERC721Burnable, ERC721Base {
        
            constructor (string memory name, string memory symbol, address newOwner, string memory contractURI, string memory tokenURIPrefix) public ERC721Base(name, symbol, contractURI, tokenURIPrefix) {
                _registerInterface(bytes4(keccak256('MINT_WITH_ADDRESS')));
                transferOwnership(newOwner);
            }
        
            function mint(uint256 tokenId, uint8 v, bytes32 r, bytes32 s, Fee[] memory _fees, string memory tokenURI) public {
                require(owner() == ecrecover(keccak256(abi.encodePacked(this, tokenId)), v, r, s), "owner should sign tokenId");
                _mint(msg.sender, tokenId, _fees);
                _setTokenURI(tokenId, tokenURI);
            }
        
            function setTokenURIPrefix(string memory tokenURIPrefix) public onlyOwner {
                _setTokenURIPrefix(tokenURIPrefix);
            }
        
            function setContractURI(string memory contractURI) public onlyOwner {
                _setContractURI(contractURI);
            }
        }

        File 2 of 4: ERC721SaleNonceHolder
        pragma solidity ^0.5.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);
        }
        
        /**
         * @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 {setApprovalForAll}.
             */
            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 {setApprovalForAll}.
             */
            function transferFrom(address from, address to, uint256 tokenId) public;
            function approve(address to, uint256 tokenId) public;
            function getApproved(uint256 tokenId) public view returns (address operator);
        
            function setApprovalForAll(address operator, bool _approved) public;
            function isApprovedForAll(address owner, address operator) public view returns (bool);
        
        
            function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
        }
        
        contract IERC721Sale {
            function getNonce(IERC721 token, uint256 tokenId) view public returns (uint256);
        }
        
        /*
         * @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.
         */
        contract Context {
            // Empty internal constructor, to prevent people from mistakenly deploying
            // an instance of this contract, which should be used via inheritance.
            constructor () internal { }
            // solhint-disable-previous-line no-empty-blocks
        
            function _msgSender() internal view returns (address payable) {
                return msg.sender;
            }
        
            function _msgData() internal view returns (bytes memory) {
                this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                return msg.data;
            }
        }
        
        /**
         * @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 OperatorRole is Context {
            using Roles for Roles.Role;
        
            event OperatorAdded(address indexed account);
            event OperatorRemoved(address indexed account);
        
            Roles.Role private _operators;
        
            constructor () internal {
        
            }
        
            modifier onlyOperator() {
                require(isOperator(_msgSender()), "OperatorRole: caller does not have the Operator role");
                _;
            }
        
            function isOperator(address account) public view returns (bool) {
                return _operators.has(account);
            }
        
            function _addOperator(address account) internal {
                _operators.add(account);
                emit OperatorAdded(account);
            }
        
            function _removeOperator(address account) internal {
                _operators.remove(account);
                emit OperatorRemoved(account);
            }
        }
        
        /**
         * @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.
         *
         * 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.
         */
        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 returns (address) {
                return _owner;
            }
        
            /**
             * @dev Throws if called by any account other than the owner.
             */
            modifier onlyOwner() {
                require(isOwner(), "Ownable: caller is not the owner");
                _;
            }
        
            /**
             * @dev Returns true if the caller is the current owner.
             */
            function isOwner() public view returns (bool) {
                return _msgSender() == _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 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 onlyOwner {
                _transferOwnership(newOwner);
            }
        
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             */
            function _transferOwnership(address newOwner) internal {
                require(newOwner != address(0), "Ownable: new owner is the zero address");
                emit OwnershipTransferred(_owner, newOwner);
                _owner = newOwner;
            }
        }
        
        contract OwnableOperatorRole is Ownable, OperatorRole {
            function addOperator(address account) public onlyOwner {
                _addOperator(account);
            }
        
            function removeOperator(address account) public onlyOwner {
                _removeOperator(account);
            }
        }
        
        contract ERC721SaleNonceHolder is OwnableOperatorRole {
            mapping(bytes32 => uint256) public nonces;
            IERC721Sale public previous;
        
            constructor(IERC721Sale _previous) public {
                previous = _previous;
            }
        
            function getNonce(IERC721 token, uint256 tokenId) view public returns (uint256) {
                uint256 newNonce = nonces[getPositionKey(token, tokenId)];
                if (newNonce != 0) {
                    return newNonce;
                }
                if (address(previous) == address(0x0)) {
                    return 0;
                }
                return previous.getNonce(token, tokenId);
            }
        
            function setNonce(IERC721 token, uint256 tokenId, uint256 nonce) public onlyOperator {
                nonces[getPositionKey(token, tokenId)] = nonce;
            }
        
            function getPositionKey(IERC721 token, uint256 tokenId) pure public returns (bytes32) {
                return keccak256(abi.encodePacked(token, tokenId));
            }
        }

        File 3 of 4: TokenSale
        pragma solidity ^0.5.0;
        
        /**
         * @dev Interface of the ERC165 standard, as defined in the
         * [EIP](https://eips.ethereum.org/EIPS/eip-165).
         *
         * 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
             * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
             * 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 `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);
        }
        
        /**
         * @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);
        }
        
        /**
         * @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.
             *
             * > 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.
        
                uint256 size;
                // solhint-disable-next-line no-inline-assembly
                assembly { size := extcodesize(account) }
                return size > 0;
            }
        }
        
        /**
         * @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)')) == 0xe985e9c
             *     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 `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 `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 burn a specific token.
             * Reverts if the token does not exist.
             * Deprecated, use _burn(uint256) instead.
             * @param owner owner of the token to burn
             * @param tokenId uint256 ID of the token being burned
             */
            function _burn(address owner, uint256 tokenId) internal {
                require(ownerOf(tokenId) == owner, "ERC721: burn of token that is not own");
        
                _clearApproval(tokenId);
        
                _ownedTokensCount[owner].decrement();
                _tokenOwner[tokenId] = address(0);
        
                emit Transfer(owner, address(0), tokenId);
            }
        
            /**
             * @dev Internal function to burn a specific token.
             * Reverts if the token does not exist.
             * @param tokenId uint256 ID of the token being burned
             */
            function _burn(uint256 tokenId) internal {
                _burn(ownerOf(tokenId), 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 `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 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 Internal function to burn a specific token.
             * Reverts if the token does not exist.
             * Deprecated, use _burn(uint256) instead.
             * @param owner owner of the token to burn
             * @param tokenId uint256 ID of the token being burned
             */
            function _burn(address owner, uint256 tokenId) internal {
                super._burn(owner, tokenId);
        
                _removeTokenFromOwnerEnumeration(owner, tokenId);
                // Since tokenId will be deleted, we can clear its slot in _ownedTokensIndex to trigger a gas refund
                _ownedTokensIndex[tokenId] = 0;
        
                _removeTokenFromAllTokensEnumeration(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).
            }
        
            /**
             * @dev Private function to remove a token from this extension's token tracking data structures.
             * This has O(1) time complexity, but alters the order of the _allTokens array.
             * @param tokenId uint256 ID of the token to be removed from the tokens list
             */
            function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
                // To prevent a gap in the 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 = _allTokens.length.sub(1);
                uint256 tokenIndex = _allTokensIndex[tokenId];
        
                // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
                // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
                // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
                uint256 lastTokenId = _allTokens[lastTokenIndex];
        
                _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
                _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
        
                // This also deletes the contents at the last position of the array
                _allTokens.length--;
                _allTokensIndex[tokenId] = 0;
            }
        }
        
        contract ERC721Metadata is ERC165, ERC721, IERC721Metadata {
            // Token name
            string private _name;
        
            // Token symbol
            string private _symbol;
        
            // 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");
                return _tokenURIs[tokenId];
            }
        
            /**
             * @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;
            }
        
            /**
             * @dev Internal function to burn a specific token.
             * Reverts if the token does not exist.
             * Deprecated, use _burn(uint256) instead.
             * @param owner owner of the token to burn
             * @param tokenId uint256 ID of the token being burned by the msg.sender
             */
            function _burn(address owner, uint256 tokenId) internal {
                super._burn(owner, tokenId);
        
                // Clear metadata (if any)
                if (bytes(_tokenURIs[tokenId]).length != 0) {
                    delete _tokenURIs[tokenId];
                }
            }
        }
        
        /**
         * @title Full ERC721 Token
         * This implementation includes all the required and some optional functionality of the ERC721 standard
         * Moreover, it includes approve all functionality using operator terminology
         * @dev see https://eips.ethereum.org/EIPS/eip-721
         */
        contract ERC721Full is ERC721, ERC721Enumerable, ERC721Metadata {
            constructor (string memory name, string memory symbol) public ERC721Metadata(name, symbol) {
                // solhint-disable-previous-line no-empty-blocks
            }
        }
        
        /**
         * @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.
         *
         * This module is used through inheritance. It will make available the modifier
         * `onlyOwner`, which can be aplied to your functions to restrict their use to
         * the owner.
         */
        contract Ownable {
            address private _owner;
        
            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        
            /**
             * @dev Initializes the contract setting the deployer as the initial owner.
             */
            constructor () internal {
                _owner = msg.sender;
                emit OwnershipTransferred(address(0), _owner);
            }
        
            /**
             * @dev Returns the address of the current owner.
             */
            function owner() public view returns (address) {
                return _owner;
            }
        
            /**
             * @dev Throws if called by any account other than the owner.
             */
            modifier onlyOwner() {
                require(isOwner(), "Ownable: caller is not the owner");
                _;
            }
        
            /**
             * @dev Returns true if the caller is the current owner.
             */
            function isOwner() public view returns (bool) {
                return msg.sender == _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 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 onlyOwner {
                _transferOwnership(newOwner);
            }
        
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             */
            function _transferOwnership(address newOwner) internal {
                require(newOwner != address(0), "Ownable: new owner is the zero address");
                emit OwnershipTransferred(_owner, newOwner);
                _owner = newOwner;
            }
        }
        
        /**
         * @title MintableToken
         * @dev anyone can mint token.
         */
        contract MintableToken is IERC721, IERC721Metadata, ERC721Full, Ownable {
        
            constructor (string memory name, string memory symbol) public ERC721Full(name, symbol) {
        
            }
        
            function mint(uint256 tokenId, uint8 v, bytes32 r, bytes32 s, string memory tokenURI) public {
                require(owner() == ecrecover(keccak256(abi.encodePacked(tokenId)), v, r, s), "owner should sign tokenId");
                _mint(msg.sender, tokenId);
                _setTokenURI(tokenId, tokenURI);
            }
        }
        
        contract TokenSale is IERC721Receiver {
        
            mapping(bytes32 => uint256) public nonces;
        
            event Cancel(address indexed token, uint256 indexed tokenId, address owner, uint256 nonce);
            event Buy(address indexed token, uint256 indexed tokenId, address seller, address buyer, uint256 price, uint256 nonce);
        
            function cancel(IERC721 token, uint256 tokenId) public {
                address owner = token.ownerOf(tokenId);
                require(owner == msg.sender, "not an owner");
                bytes32 key = getPositionKey(token, tokenId);
                uint256 nonce = nonces[key] + 1;
                nonces[key] = nonce;
                emit Cancel(address(token), tokenId, owner, nonce);
            }
        
            function buy(IERC721 token, uint256 tokenId, uint8 v, bytes32 r, bytes32 s) public payable {
                bytes32 key = getPositionKey(token, tokenId);
                bytes memory message = prepare(address(token), tokenId, msg.value, nonces[key]);
                address payable owner = address(uint160(token.ownerOf(tokenId)));
                require(owner == testRecovery(message, v, r, s), "owner should sign correct message");
                uint256 nonce = nonces[key] + 1;
                nonces[key] = nonce;
                token.transferFrom(owner, msg.sender, tokenId);
                owner.transfer(msg.value);
                emit Buy(address(token), tokenId, owner, msg.sender, msg.value, nonce);
            }
        
            function testRecovery(bytes memory message, uint8 v, bytes32 r, bytes32 s) private pure returns (address) {
                bytes memory fullMessage = strConcat(
                    bytes("\x19Ethereum Signed Message:\n"),
                    toAsciiBytes(message.length),
                    message,
                    new bytes(0), new bytes(0), new bytes(0), new bytes(0)
                );
                return ecrecover(keccak256(fullMessage), v, r, s);
            }
        
            function prepare(address token, uint256 tokenId, uint256 price, uint256 nonce) private pure returns (bytes memory) {
                return strConcat(
                    toAsciiBytes(token),
                    bytes(". tokenId: "),
                    toAsciiBytes(tokenId),
                    bytes(". price: "),
                    toAsciiBytes(price),
                    bytes(". nonce: "),
                    toAsciiBytes(nonce)
                );
            }
        
            function strConcat(bytes memory _ba, bytes memory _bb, bytes memory _bc, bytes memory _bd, bytes memory _be, bytes memory _bf, bytes memory _bg) internal pure returns (bytes memory) {
                bytes memory resultBytes = new bytes(_ba.length + _bb.length + _bc.length + _bd.length + _be.length + _bf.length + _bg.length);
                uint k = 0;
                for (uint i = 0; i < _ba.length; i++) resultBytes[k++] = _ba[i];
                for (uint i = 0; i < _bb.length; i++) resultBytes[k++] = _bb[i];
                for (uint i = 0; i < _bc.length; i++) resultBytes[k++] = _bc[i];
                for (uint i = 0; i < _bd.length; i++) resultBytes[k++] = _bd[i];
                for (uint i = 0; i < _be.length; i++) resultBytes[k++] = _be[i];
                for (uint i = 0; i < _bf.length; i++) resultBytes[k++] = _bf[i];
                for (uint i = 0; i < _bg.length; i++) resultBytes[k++] = _bg[i];
                return resultBytes;
            }
        
            function toAsciiBytes(uint _i) internal pure returns (bytes memory) {
                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 bstr;
            }
        
            function toAsciiBytes(address _addr) internal pure returns(bytes memory) {
                bytes32 value = bytes32(uint256(_addr));
                bytes memory alphabet = "0123456789abcdef";
                bytes memory str = new bytes(42);
                str[0] = '0';
                str[1] = 'x';
                for (uint256 i = 0; i < 20; i++) {
                    str[2+i*2] = alphabet[uint8(value[i + 12] >> 4)];
                    str[3+i*2] = alphabet[uint8(value[i + 12] & 0x0f)];
                }
                return str;
            }
        
            function getNonce(IERC721 token, uint256 tokenId) view public returns (uint256) {
                return nonces[getPositionKey(token, tokenId)];
            }
        
            function getPositionKey(IERC721 token, uint256 tokenId) pure public returns (bytes32) {
                return keccak256(abi.encodePacked(token, tokenId));
            }
        
            function onERC721Received(address, address, uint256, bytes memory) public returns (bytes4) {
                return this.onERC721Received.selector;
            }
        }

        File 4 of 4: TransferProxy
        pragma solidity ^0.5.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);
        }
        
        /**
         * @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`.
             * - `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 {setApprovalForAll}.
             */
            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 {setApprovalForAll}.
             */
            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;
        }
        
        /*
         * @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.
         */
        contract Context {
            // Empty internal constructor, to prevent people from mistakenly deploying
            // an instance of this contract, which should be used via inheritance.
            constructor () internal { }
            // solhint-disable-previous-line no-empty-blocks
        
            function _msgSender() internal view returns (address payable) {
                return msg.sender;
            }
        
            function _msgData() internal view returns (bytes memory) {
                this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                return msg.data;
            }
        }
        
        /**
         * @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 OperatorRole is Context {
            using Roles for Roles.Role;
        
            event OperatorAdded(address indexed account);
            event OperatorRemoved(address indexed account);
        
            Roles.Role private _operators;
        
            constructor () internal {
        
            }
        
            modifier onlyOperator() {
                require(isOperator(_msgSender()), "OperatorRole: caller does not have the Operator role");
                _;
            }
        
            function isOperator(address account) public view returns (bool) {
                return _operators.has(account);
            }
        
            function _addOperator(address account) internal {
                _operators.add(account);
                emit OperatorAdded(account);
            }
        
            function _removeOperator(address account) internal {
                _operators.remove(account);
                emit OperatorRemoved(account);
            }
        }
        
        /**
         * @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.
         *
         * 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.
         */
        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 returns (address) {
                return _owner;
            }
        
            /**
             * @dev Throws if called by any account other than the owner.
             */
            modifier onlyOwner() {
                require(isOwner(), "Ownable: caller is not the owner");
                _;
            }
        
            /**
             * @dev Returns true if the caller is the current owner.
             */
            function isOwner() public view returns (bool) {
                return _msgSender() == _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 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 onlyOwner {
                _transferOwnership(newOwner);
            }
        
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             */
            function _transferOwnership(address newOwner) internal {
                require(newOwner != address(0), "Ownable: new owner is the zero address");
                emit OwnershipTransferred(_owner, newOwner);
                _owner = newOwner;
            }
        }
        
        contract OwnableOperatorRole is Ownable, OperatorRole {
            function addOperator(address account) external onlyOwner {
                _addOperator(account);
            }
        
            function removeOperator(address account) external onlyOwner {
                _removeOperator(account);
            }
        }
        
        /**
            @title ERC-1155 Multi Token Standard
            @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md
            Note: The ERC-165 identifier for this interface is 0xd9b67a26.
         */
        contract IERC1155 is IERC165 {
            /**
                @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard).
                The `_operator` argument MUST be msg.sender.
                The `_from` argument MUST be the address of the holder whose balance is decreased.
                The `_to` argument MUST be the address of the recipient whose balance is increased.
                The `_id` argument MUST be the token type being transferred.
                The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by.
                When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).
                When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).
            */
            event TransferSingle(address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value);
        
            /**
                @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard).
                The `_operator` argument MUST be msg.sender.
                The `_from` argument MUST be the address of the holder whose balance is decreased.
                The `_to` argument MUST be the address of the recipient whose balance is increased.
                The `_ids` argument MUST be the list of tokens being transferred.
                The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by.
                When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).
                When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).
            */
            event TransferBatch(address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values);
        
            /**
                @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absense of an event assumes disabled).
            */
            event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
        
            /**
                @dev MUST emit when the URI is updated for a token ID.
                URIs are defined in RFC 3986.
                The URI MUST point a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema".
            */
            event URI(string _value, uint256 indexed _id);
        
            /**
                @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call).
                @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard).
                MUST revert if `_to` is the zero address.
                MUST revert if balance of holder for token `_id` is lower than the `_value` sent.
                MUST revert on any other error.
                MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard).
                After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard).
                @param _from    Source address
                @param _to      Target address
                @param _id      ID of the token type
                @param _value   Transfer amount
                @param _data    Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to`
            */
            function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external;
        
            /**
                @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call).
                @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard).
                MUST revert if `_to` is the zero address.
                MUST revert if length of `_ids` is not the same as length of `_values`.
                MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient.
                MUST revert on any other error.
                MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard).
                Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).
                After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard).
                @param _from    Source address
                @param _to      Target address
                @param _ids     IDs of each token type (order and length must match _values array)
                @param _values  Transfer amounts per token type (order and length must match _ids array)
                @param _data    Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to`
            */
            function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external;
        
            /**
                @notice Get the balance of an account's Tokens.
                @param _owner  The address of the token holder
                @param _id     ID of the Token
                @return        The _owner's balance of the Token type requested
             */
            function balanceOf(address _owner, uint256 _id) external view returns (uint256);
        
            /**
                @notice Get the balance of multiple account/token pairs
                @param _owners The addresses of the token holders
                @param _ids    ID of the Tokens
                @return        The _owner's balance of the Token types requested (i.e. balance for each (owner, id) pair)
             */
            function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory);
        
            /**
                @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens.
                @dev MUST emit the ApprovalForAll event on success.
                @param _operator  Address to add to the set of authorized operators
                @param _approved  True if the operator is approved, false to revoke approval
            */
            function setApprovalForAll(address _operator, bool _approved) external;
        
            /**
                @notice Queries the approval status of an operator for a given owner.
                @param _owner     The owner of the Tokens
                @param _operator  Address of authorized operator
                @return           True if the operator is approved, false if not
            */
            function isApprovedForAll(address _owner, address _operator) external view returns (bool);
        }
        
        contract TransferProxy is OwnableOperatorRole {
        
            function erc721safeTransferFrom(IERC721 token, address from, address to, uint256 tokenId) external onlyOperator {
                token.safeTransferFrom(from, to, tokenId);
            }
        
            function erc1155safeTransferFrom(IERC1155 token, address from, address to, uint256 id, uint256 value, bytes calldata data) external onlyOperator {
                token.safeTransferFrom(from, to, id, value, data);
            }
        }