ETH Price: $2,673.94 (+0.75%)
Gas: 18 Gwei

Contract Diff Checker

Contract Name:
Mounts

Contract Source Code:

pragma solidity >=0.6.0 <0.8.0;
pragma experimental ABIEncoderV2;

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

	function _msgData() internal view virtual returns (bytes memory) {
		this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
		return msg.data;
	}
}

library Base64 {
	bytes internal constant TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

	/// @notice Encodes some bytes to the base64 representation
	function encode(bytes memory data) internal pure returns (string memory) {
		uint256 len = data.length;
		if (len == 0) return "";

		// multiply by 4/3 rounded up
		uint256 encodedLen = 4 * ((len + 2) / 3);

		// Add some extra buffer at the end
		bytes memory result = new bytes(encodedLen + 32);

		bytes memory table = TABLE;

		assembly {
			let tablePtr := add(table, 1)
			let resultPtr := add(result, 32)

			for {
				let i := 0
			} lt(i, len) {

			} {
				i := add(i, 3)
				let input := and(mload(add(data, i)), 0xffffff)

				let out := mload(add(tablePtr, and(shr(18, input), 0x3F)))
				out := shl(8, out)
				out := add(out, and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF))
				out := shl(8, out)
				out := add(out, and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF))
				out := shl(8, out)
				out := add(out, and(mload(add(tablePtr, and(input, 0x3F))), 0xFF))
				out := shl(224, out)

				mstore(resultPtr, out)

				resultPtr := add(resultPtr, 4)
			}

			switch mod(len, 3)
			case 1 {
				mstore(sub(resultPtr, 2), shl(240, 0x3d3d))
			}
			case 2 {
				mstore(sub(resultPtr, 1), shl(248, 0x3d))
			}

			mstore(result, encodedLen)
		}

		return string(result);
	}
}

interface LootInterface {
	function ownerOf(uint256 tokenId) external view returns (address owner);
}

abstract contract Ownable is Context {
	address private _owner;

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

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

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

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

	/**
	 * @dev Leaves the contract without owner. It will not be possible to call
	 * `onlyOwner` functions anymore. Can only be called by the current owner.
	 *
	 * NOTE: Renouncing ownership will leave the contract without an owner,
	 * thereby removing any functionality that is only available to the owner.
	 */
	function renounceOwnership() public virtual onlyOwner {
		emit OwnershipTransferred(_owner, address(0));
		_owner = address(0);
	}

	/**
	 * @dev Transfers ownership of the contract to a new account (`newOwner`).
	 * Can only be called by the current owner.
	 */
	function transferOwnership(address newOwner) public virtual onlyOwner {
		require(newOwner != address(0), "Ownable: new owner is the zero address");
		emit OwnershipTransferred(_owner, newOwner);
		_owner = newOwner;
	}
}

abstract contract ReentrancyGuard {
	// Booleans are more expensive than uint256 or any type that takes up a full
	// word because each write operation emits an extra SLOAD to first read the
	// slot's contents, replace the bits taken up by the boolean, and then write
	// back. This is the compiler's defense against contract upgrades and
	// pointer aliasing, and it cannot be disabled.

	// The values being non-zero value makes deployment a bit more expensive,
	// but in exchange the refund on every call to nonReentrant will be lower in
	// amount. Since refunds are capped to a percentage of the total
	// transaction's gas, it is best to keep them low in cases like this one, to
	// increase the likelihood of the full refund coming into effect.
	uint256 private constant _NOT_ENTERED = 1;
	uint256 private constant _ENTERED = 2;

	uint256 private _status;

	constructor() {
		_status = _NOT_ENTERED;
	}

	/**
	 * @dev Prevents a contract from calling itself, directly or indirectly.
	 * Calling a `nonReentrant` function from another `nonReentrant`
	 * function is not supported. It is possible to prevent this from happening
	 * by making the `nonReentrant` function external, and make it call a
	 * `private` function that does the actual work.
	 */
	modifier nonReentrant() {
		// On the first call to nonReentrant, _notEntered will be true
		require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

		// Any calls to nonReentrant after this point will fail
		_status = _ENTERED;

		_;

		// By storing the original value once again, a refund is triggered (see
		// https://eips.ethereum.org/EIPS/eip-2200)
		_status = _NOT_ENTERED;
	}
}

interface IERC721Receiver {
	/**
	 * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
	 * by `operator` from `from`, this function is called.
	 *
	 * It must return its Solidity selector to confirm the token transfer.
	 * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
	 *
	 * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
	 */
	function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);
}

library Strings {
	/**
	 * @dev Converts a `uint256` to its ASCII `string` representation.
	 */
	function toString(uint256 value) internal pure returns (string memory) {
		// Inspired by OraclizeAPI's implementation - MIT licence
		// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

		if (value == 0) {
			return "0";
		}
		uint256 temp = value;
		uint256 digits;
		while (temp != 0) {
			digits++;
			temp /= 10;
		}
		bytes memory buffer = new bytes(digits);
		uint256 index = digits - 1;
		temp = value;
		while (temp != 0) {
			buffer[index--] = bytes1(uint8(48 + temp % 10));
			temp /= 10;
		}
		return string(buffer);
	}
}

library EnumerableMap {
	// To implement this library for multiple types with as little code
	// repetition as possible, we write it in terms of a generic Map type with
	// bytes32 keys and values.
	// The Map implementation uses private functions, and user-facing
	// implementations (such as Uint256ToAddressMap) are just wrappers around
	// the underlying Map.
	// This means that we can only create new EnumerableMaps for types that fit
	// in bytes32.

	struct MapEntry {
		bytes32 _key;
		bytes32 _value;
	}

	struct Map {
		// Storage of map keys and values
		MapEntry[] _entries;

		// Position of the entry defined by a key in the `entries` array, plus 1
		// because index 0 means a key is not in the map.
		mapping (bytes32 => uint256) _indexes;
	}

	/**
	 * @dev Adds a key-value pair to a map, or updates the value for an existing
	 * key. O(1).
	 *
	 * Returns true if the key was added to the map, that is if it was not
	 * already present.
	 */
	function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) {
		// We read and store the key's index to prevent multiple reads from the same storage slot
		uint256 keyIndex = map._indexes[key];

		if (keyIndex == 0) { // Equivalent to !contains(map, key)
			map._entries.push(MapEntry({ _key: key, _value: value }));
			// The entry is stored at length-1, but we add 1 to all indexes
			// and use 0 as a sentinel value
			map._indexes[key] = map._entries.length;
			return true;
		} else {
			map._entries[keyIndex - 1]._value = value;
			return false;
		}
	}

	/**
	 * @dev Removes a key-value pair from a map. O(1).
	 *
	 * Returns true if the key was removed from the map, that is if it was present.
	 */
	function _remove(Map storage map, bytes32 key) private returns (bool) {
		// We read and store the key's index to prevent multiple reads from the same storage slot
		uint256 keyIndex = map._indexes[key];

		if (keyIndex != 0) { // Equivalent to contains(map, key)
			// To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one
			// in the array, and then remove the last entry (sometimes called as 'swap and pop').
			// This modifies the order of the array, as noted in {at}.

			uint256 toDeleteIndex = keyIndex - 1;
			uint256 lastIndex = map._entries.length - 1;

			// When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs
			// so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

			MapEntry storage lastEntry = map._entries[lastIndex];

			// Move the last entry to the index where the entry to delete is
			map._entries[toDeleteIndex] = lastEntry;
			// Update the index for the moved entry
			map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based

			// Delete the slot where the moved entry was stored
			map._entries.pop();

			// Delete the index for the deleted slot
			delete map._indexes[key];

			return true;
		} else {
			return false;
		}
	}

	/**
	 * @dev Returns true if the key is in the map. O(1).
	 */
	function _contains(Map storage map, bytes32 key) private view returns (bool) {
		return map._indexes[key] != 0;
	}

	/**
	 * @dev Returns the number of key-value pairs in the map. O(1).
	 */
	function _length(Map storage map) private view returns (uint256) {
		return map._entries.length;
	}

	/**
	 * @dev Returns the key-value pair stored at position `index` in the map. O(1).
	 *
	 * Note that there are no guarantees on the ordering of entries inside the
	 * array, and it may change when more entries are added or removed.
	 *
	 * Requirements:
	 *
	 * - `index` must be strictly less than {length}.
	 */
	function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) {
		require(map._entries.length > index, "EnumerableMap: index out of bounds");

		MapEntry storage entry = map._entries[index];
		return (entry._key, entry._value);
	}

	/**
	 * @dev Tries to returns the value associated with `key`.  O(1).
	 * Does not revert if `key` is not in the map.
	 */
	function _tryGet(Map storage map, bytes32 key) private view returns (bool, bytes32) {
		uint256 keyIndex = map._indexes[key];
		if (keyIndex == 0) return (false, 0); // Equivalent to contains(map, key)
		return (true, map._entries[keyIndex - 1]._value); // All indexes are 1-based
	}

	/**
	 * @dev Returns the value associated with `key`.  O(1).
	 *
	 * Requirements:
	 *
	 * - `key` must be in the map.
	 */
	function _get(Map storage map, bytes32 key) private view returns (bytes32) {
		uint256 keyIndex = map._indexes[key];
		require(keyIndex != 0, "EnumerableMap: nonexistent key"); // Equivalent to contains(map, key)
		return map._entries[keyIndex - 1]._value; // All indexes are 1-based
	}

	/**
	 * @dev Same as {_get}, with a custom error message when `key` is not in the map.
	 *
	 * CAUTION: This function is deprecated because it requires allocating memory for the error
	 * message unnecessarily. For custom revert reasons use {_tryGet}.
	 */
	function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) {
		uint256 keyIndex = map._indexes[key];
		require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key)
		return map._entries[keyIndex - 1]._value; // All indexes are 1-based
	}

	// UintToAddressMap

	struct UintToAddressMap {
		Map _inner;
	}

	/**
	 * @dev Adds a key-value pair to a map, or updates the value for an existing
	 * key. O(1).
	 *
	 * Returns true if the key was added to the map, that is if it was not
	 * already present.
	 */
	function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
		return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
	}

	/**
	 * @dev Removes a value from a set. O(1).
	 *
	 * Returns true if the key was removed from the map, that is if it was present.
	 */
	function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
		return _remove(map._inner, bytes32(key));
	}

	/**
	 * @dev Returns true if the key is in the map. O(1).
	 */
	function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
		return _contains(map._inner, bytes32(key));
	}

	/**
	 * @dev Returns the number of elements in the map. O(1).
	 */
	function length(UintToAddressMap storage map) internal view returns (uint256) {
		return _length(map._inner);
	}

	/**
	 * @dev Returns the element stored at position `index` in the set. O(1).
	 * Note that there are no guarantees on the ordering of values inside the
	 * array, and it may change when more values are added or removed.
	 *
	 * Requirements:
	 *
	 * - `index` must be strictly less than {length}.
	 */
	function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
		(bytes32 key, bytes32 value) = _at(map._inner, index);
		return (uint256(key), address(uint160(uint256(value))));
	}

	/**
	 * @dev Tries to returns the value associated with `key`.  O(1).
	 * Does not revert if `key` is not in the map.
	 *
	 * _Available since v3.4._
	 */
	function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
		(bool success, bytes32 value) = _tryGet(map._inner, bytes32(key));
		return (success, address(uint160(uint256(value))));
	}

	/**
	 * @dev Returns the value associated with `key`.  O(1).
	 *
	 * Requirements:
	 *
	 * - `key` must be in the map.
	 */
	function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
		return address(uint160(uint256(_get(map._inner, bytes32(key)))));
	}

	/**
	 * @dev Same as {get}, with a custom error message when `key` is not in the map.
	 *
	 * CAUTION: This function is deprecated because it requires allocating memory for the error
	 * message unnecessarily. For custom revert reasons use {tryGet}.
	 */
	function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) {
		return address(uint160(uint256(_get(map._inner, bytes32(key), errorMessage))));
	}
}

library EnumerableSet {
	// To implement this library for multiple types with as little code
	// repetition as possible, we write it in terms of a generic Set type with
	// bytes32 values.
	// The Set implementation uses private functions, and user-facing
	// implementations (such as AddressSet) are just wrappers around the
	// underlying Set.
	// This means that we can only create new EnumerableSets for types that fit
	// in bytes32.

	struct Set {
		// Storage of set values
		bytes32[] _values;

		// Position of the value in the `values` array, plus 1 because index 0
		// means a value is not in the set.
		mapping (bytes32 => uint256) _indexes;
	}

	/**
	 * @dev Add a value to a set. O(1).
	 *
	 * Returns true if the value was added to the set, that is if it was not
	 * already present.
	 */
	function _add(Set storage set, bytes32 value) private returns (bool) {
		if (!_contains(set, value)) {
			set._values.push(value);
			// The value is stored at length-1, but we add 1 to all indexes
			// and use 0 as a sentinel value
			set._indexes[value] = set._values.length;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * @dev Removes a value from a set. O(1).
	 *
	 * Returns true if the value was removed from the set, that is if it was
	 * present.
	 */
	function _remove(Set storage set, bytes32 value) private returns (bool) {
		// We read and store the value's index to prevent multiple reads from the same storage slot
		uint256 valueIndex = set._indexes[value];

		if (valueIndex != 0) { // Equivalent to contains(set, value)
			// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
			// the array, and then remove the last element (sometimes called as 'swap and pop').
			// This modifies the order of the array, as noted in {at}.

			uint256 toDeleteIndex = valueIndex - 1;
			uint256 lastIndex = set._values.length - 1;

			// When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
			// so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

			bytes32 lastvalue = set._values[lastIndex];

			// Move the last value to the index where the value to delete is
			set._values[toDeleteIndex] = lastvalue;
			// Update the index for the moved value
			set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based

			// Delete the slot where the moved value was stored
			set._values.pop();

			// Delete the index for the deleted slot
			delete set._indexes[value];

			return true;
		} else {
			return false;
		}
	}

	/**
	 * @dev Returns true if the value is in the set. O(1).
	 */
	function _contains(Set storage set, bytes32 value) private view returns (bool) {
		return set._indexes[value] != 0;
	}

	/**
	 * @dev Returns the number of values on the set. O(1).
	 */
	function _length(Set storage set) private view returns (uint256) {
		return set._values.length;
	}

	/**
	 * @dev Returns the value stored at position `index` in the set. O(1).
	 *
	 * Note that there are no guarantees on the ordering of values inside the
	 * array, and it may change when more values are added or removed.
	 *
	 * Requirements:
	 *
	 * - `index` must be strictly less than {length}.
	 */
	function _at(Set storage set, uint256 index) private view returns (bytes32) {
		require(set._values.length > index, "EnumerableSet: index out of bounds");
		return set._values[index];
	}

	// Bytes32Set

	struct Bytes32Set {
		Set _inner;
	}

	/**
	 * @dev Add a value to a set. O(1).
	 *
	 * Returns true if the value was added to the set, that is if it was not
	 * already present.
	 */
	function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
		return _add(set._inner, value);
	}

	/**
	 * @dev Removes a value from a set. O(1).
	 *
	 * Returns true if the value was removed from the set, that is if it was
	 * present.
	 */
	function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
		return _remove(set._inner, value);
	}

	/**
	 * @dev Returns true if the value is in the set. O(1).
	 */
	function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
		return _contains(set._inner, value);
	}

	/**
	 * @dev Returns the number of values in the set. O(1).
	 */
	function length(Bytes32Set storage set) internal view returns (uint256) {
		return _length(set._inner);
	}

	/**
	 * @dev Returns the value stored at position `index` in the set. O(1).
	 *
	 * Note that there are no guarantees on the ordering of values inside the
	 * array, and it may change when more values are added or removed.
	 *
	 * Requirements:
	 *
	 * - `index` must be strictly less than {length}.
	 */
	function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
		return _at(set._inner, index);
	}

	// AddressSet

	struct AddressSet {
		Set _inner;
	}

	/**
	 * @dev Add a value to a set. O(1).
	 *
	 * Returns true if the value was added to the set, that is if it was not
	 * already present.
	 */
	function add(AddressSet storage set, address value) internal returns (bool) {
		return _add(set._inner, bytes32(uint256(uint160(value))));
	}

	/**
	 * @dev Removes a value from a set. O(1).
	 *
	 * Returns true if the value was removed from the set, that is if it was
	 * present.
	 */
	function remove(AddressSet storage set, address value) internal returns (bool) {
		return _remove(set._inner, bytes32(uint256(uint160(value))));
	}

	/**
	 * @dev Returns true if the value is in the set. O(1).
	 */
	function contains(AddressSet storage set, address value) internal view returns (bool) {
		return _contains(set._inner, bytes32(uint256(uint160(value))));
	}

	/**
	 * @dev Returns the number of values in the set. O(1).
	 */
	function length(AddressSet storage set) internal view returns (uint256) {
		return _length(set._inner);
	}

	/**
	 * @dev Returns the value stored at position `index` in the set. O(1).
	 *
	 * Note that there are no guarantees on the ordering of values inside the
	 * array, and it may change when more values are added or removed.
	 *
	 * Requirements:
	 *
	 * - `index` must be strictly less than {length}.
	 */
	function at(AddressSet storage set, uint256 index) internal view returns (address) {
		return address(uint160(uint256(_at(set._inner, index))));
	}


	// UintSet

	struct UintSet {
		Set _inner;
	}

	/**
	 * @dev Add a value to a set. O(1).
	 *
	 * Returns true if the value was added to the set, that is if it was not
	 * already present.
	 */
	function add(UintSet storage set, uint256 value) internal returns (bool) {
		return _add(set._inner, bytes32(value));
	}

	/**
	 * @dev Removes a value from a set. O(1).
	 *
	 * Returns true if the value was removed from the set, that is if it was
	 * present.
	 */
	function remove(UintSet storage set, uint256 value) internal returns (bool) {
		return _remove(set._inner, bytes32(value));
	}

	/**
	 * @dev Returns true if the value is in the set. O(1).
	 */
	function contains(UintSet storage set, uint256 value) internal view returns (bool) {
		return _contains(set._inner, bytes32(value));
	}

	/**
	 * @dev Returns the number of values on the set. O(1).
	 */
	function length(UintSet storage set) internal view returns (uint256) {
		return _length(set._inner);
	}

	/**
	 * @dev Returns the value stored at position `index` in the set. O(1).
	 *
	 * Note that there are no guarantees on the ordering of values inside the
	 * array, and it may change when more values are added or removed.
	 *
	 * Requirements:
	 *
	 * - `index` must be strictly less than {length}.
	 */
	function at(UintSet storage set, uint256 index) internal view returns (uint256) {
		return uint256(_at(set._inner, index));
	}
}

library Address {
	/**
	 * @dev Returns true if `account` is a contract.
	 *
	 * [IMPORTANT]
	 * ====
	 * It is unsafe to assume that an address for which this function returns
	 * false is an externally-owned account (EOA) and not a contract.
	 *
	 * Among others, `isContract` will return false for the following
	 * types of addresses:
	 *
	 *  - an externally-owned account
	 *  - a contract in construction
	 *  - an address where a contract will be created
	 *  - an address where a contract lived, but was destroyed
	 * ====
	 */
	function isContract(address account) internal view returns (bool) {
		// This method relies on extcodesize, which returns 0 for contracts in
		// construction, since the code is only stored at the end of the
		// constructor execution.

		uint256 size;
		// solhint-disable-next-line no-inline-assembly
		assembly { size := extcodesize(account) }
		return size > 0;
	}

	/**
	 * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
	 * `recipient`, forwarding all available gas and reverting on errors.
	 *
	 * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
	 * of certain opcodes, possibly making contracts go over the 2300 gas limit
	 * imposed by `transfer`, making them unable to receive funds via
	 * `transfer`. {sendValue} removes this limitation.
	 *
	 * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
	 *
	 * IMPORTANT: because control is transferred to `recipient`, care must be
	 * taken to not create reentrancy vulnerabilities. Consider using
	 * {ReentrancyGuard} or the
	 * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
	 */
	function sendValue(address payable recipient, uint256 amount) internal {
		require(address(this).balance >= amount, "Address: insufficient balance");

		// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
		(bool success, ) = recipient.call{ value: amount }("");
		require(success, "Address: unable to send value, recipient may have reverted");
	}

	/**
	 * @dev Performs a Solidity function call using a low level `call`. A
	 * plain`call` is an unsafe replacement for a function call: use this
	 * function instead.
	 *
	 * If `target` reverts with a revert reason, it is bubbled up by this
	 * function (like regular Solidity function calls).
	 *
	 * Returns the raw returned data. To convert to the expected return value,
	 * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
	 *
	 * Requirements:
	 *
	 * - `target` must be a contract.
	 * - calling `target` with `data` must not revert.
	 *
	 * _Available since v3.1._
	 */
	function functionCall(address target, bytes memory data) internal returns (bytes memory) {
		return functionCall(target, data, "Address: low-level call failed");
	}

	/**
	 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
	 * `errorMessage` as a fallback revert reason when `target` reverts.
	 *
	 * _Available since v3.1._
	 */
	function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
		return functionCallWithValue(target, data, 0, errorMessage);
	}

	/**
	 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
	 * but also transferring `value` wei to `target`.
	 *
	 * Requirements:
	 *
	 * - the calling contract must have an ETH balance of at least `value`.
	 * - the called Solidity function must be `payable`.
	 *
	 * _Available since v3.1._
	 */
	function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
		return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
	}

	/**
	 * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
	 * with `errorMessage` as a fallback revert reason when `target` reverts.
	 *
	 * _Available since v3.1._
	 */
	function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
		require(address(this).balance >= value, "Address: insufficient balance for call");
		require(isContract(target), "Address: call to non-contract");

		// solhint-disable-next-line avoid-low-level-calls
		(bool success, bytes memory returndata) = target.call{ value: value }(data);
		return _verifyCallResult(success, returndata, errorMessage);
	}

	/**
	 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
	 * but performing a static call.
	 *
	 * _Available since v3.3._
	 */
	function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
		return functionStaticCall(target, data, "Address: low-level static call failed");
	}

	/**
	 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
	 * but performing a static call.
	 *
	 * _Available since v3.3._
	 */
	function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
		require(isContract(target), "Address: static call to non-contract");

		// solhint-disable-next-line avoid-low-level-calls
		(bool success, bytes memory returndata) = target.staticcall(data);
		return _verifyCallResult(success, returndata, errorMessage);
	}

	/**
	 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
	 * but performing a delegate call.
	 *
	 * _Available since v3.4._
	 */
	function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
		return functionDelegateCall(target, data, "Address: low-level delegate call failed");
	}

	/**
	 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
	 * but performing a delegate call.
	 *
	 * _Available since v3.4._
	 */
	function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
		require(isContract(target), "Address: delegate call to non-contract");

		// solhint-disable-next-line avoid-low-level-calls
		(bool success, bytes memory returndata) = target.delegatecall(data);
		return _verifyCallResult(success, returndata, errorMessage);
	}

	function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
		if (success) {
			return returndata;
		} else {
			// Look for revert reason and bubble it up if present
			if (returndata.length > 0) {
				// The easiest way to bubble the revert reason is using memory via assembly

				// solhint-disable-next-line no-inline-assembly
				assembly {
					let returndata_size := mload(returndata)
					revert(add(32, returndata), returndata_size)
				}
			} else {
				revert(errorMessage);
			}
		}
	}
}

library SafeMath {
	/**
	 * @dev Returns the addition of two unsigned integers, with an overflow flag.
	 *
	 * _Available since v3.4._
	 */
	function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
		uint256 c = a + b;
		if (c < a) return (false, 0);
		return (true, c);
	}

	/**
	 * @dev Returns the substraction of two unsigned integers, with an overflow flag.
	 *
	 * _Available since v3.4._
	 */
	function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
		if (b > a) return (false, 0);
		return (true, a - b);
	}

	/**
	 * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
	 *
	 * _Available since v3.4._
	 */
	function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
		// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
		// benefit is lost if 'b' is also tested.
		// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
		if (a == 0) return (true, 0);
		uint256 c = a * b;
		if (c / a != b) return (false, 0);
		return (true, c);
	}

	/**
	 * @dev Returns the division of two unsigned integers, with a division by zero flag.
	 *
	 * _Available since v3.4._
	 */
	function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
		if (b == 0) return (false, 0);
		return (true, a / b);
	}

	/**
	 * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
	 *
	 * _Available since v3.4._
	 */
	function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
		if (b == 0) return (false, 0);
		return (true, a % b);
	}

	/**
	 * @dev Returns the addition of two unsigned integers, reverting on
	 * overflow.
	 *
	 * Counterpart to Solidity's `+` operator.
	 *
	 * Requirements:
	 *
	 * - Addition cannot overflow.
	 */
	function add(uint256 a, uint256 b) internal pure returns (uint256) {
		uint256 c = a + b;
		require(c >= a, "SafeMath: addition overflow");
		return c;
	}

	/**
	 * @dev Returns the subtraction of two unsigned integers, reverting on
	 * overflow (when the result is negative).
	 *
	 * Counterpart to Solidity's `-` operator.
	 *
	 * Requirements:
	 *
	 * - Subtraction cannot overflow.
	 */
	function sub(uint256 a, uint256 b) internal pure returns (uint256) {
		require(b <= a, "SafeMath: subtraction overflow");
		return a - b;
	}

	/**
	 * @dev Returns the multiplication of two unsigned integers, reverting on
	 * overflow.
	 *
	 * Counterpart to Solidity's `*` operator.
	 *
	 * Requirements:
	 *
	 * - Multiplication cannot overflow.
	 */
	function mul(uint256 a, uint256 b) internal pure returns (uint256) {
		if (a == 0) return 0;
		uint256 c = a * b;
		require(c / a == b, "SafeMath: multiplication overflow");
		return c;
	}

	/**
	 * @dev Returns the integer division of two unsigned integers, reverting on
	 * division by zero. The result is rounded towards zero.
	 *
	 * Counterpart to Solidity's `/` operator. Note: this function uses a
	 * `revert` opcode (which leaves remaining gas untouched) while Solidity
	 * uses an invalid opcode to revert (consuming all remaining gas).
	 *
	 * Requirements:
	 *
	 * - The divisor cannot be zero.
	 */
	function div(uint256 a, uint256 b) internal pure returns (uint256) {
		require(b > 0, "SafeMath: division by zero");
		return a / b;
	}

	/**
	 * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
	 * reverting when dividing by zero.
	 *
	 * Counterpart to Solidity's `%` operator. This function uses a `revert`
	 * opcode (which leaves remaining gas untouched) while Solidity uses an
	 * invalid opcode to revert (consuming all remaining gas).
	 *
	 * Requirements:
	 *
	 * - The divisor cannot be zero.
	 */
	function mod(uint256 a, uint256 b) internal pure returns (uint256) {
		require(b > 0, "SafeMath: modulo by zero");
		return a % b;
	}

	/**
	 * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
	 * overflow (when the result is negative).
	 *
	 * CAUTION: This function is deprecated because it requires allocating memory for the error
	 * message unnecessarily. For custom revert reasons use {trySub}.
	 *
	 * Counterpart to Solidity's `-` operator.
	 *
	 * Requirements:
	 *
	 * - Subtraction cannot overflow.
	 */
	function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
		require(b <= a, errorMessage);
		return a - b;
	}

	/**
	 * @dev Returns the integer division of two unsigned integers, reverting with custom message on
	 * division by zero. The result is rounded towards zero.
	 *
	 * CAUTION: This function is deprecated because it requires allocating memory for the error
	 * message unnecessarily. For custom revert reasons use {tryDiv}.
	 *
	 * Counterpart to Solidity's `/` operator. Note: this function uses a
	 * `revert` opcode (which leaves remaining gas untouched) while Solidity
	 * uses an invalid opcode to revert (consuming all remaining gas).
	 *
	 * Requirements:
	 *
	 * - The divisor cannot be zero.
	 */
	function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
		require(b > 0, errorMessage);
		return a / b;
	}

	/**
	 * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
	 * reverting with custom message when dividing by zero.
	 *
	 * CAUTION: This function is deprecated because it requires allocating memory for the error
	 * message unnecessarily. For custom revert reasons use {tryMod}.
	 *
	 * Counterpart to Solidity's `%` operator. This function uses a `revert`
	 * opcode (which leaves remaining gas untouched) while Solidity uses an
	 * invalid opcode to revert (consuming all remaining gas).
	 *
	 * Requirements:
	 *
	 * - The divisor cannot be zero.
	 */
	function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
		require(b > 0, errorMessage);
		return a % b;
	}
}

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);
}

abstract contract ERC165 is IERC165 {
	/*
	 * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
	 */
	bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

	/**
	 * @dev Mapping of interface ids to whether or not it's supported.
	 */
	mapping(bytes4 => bool) private _supportedInterfaces;

	constructor () internal {
		// Derived contracts need only register support for their own interfaces,
		// we register support for ERC165 itself here
		_registerInterface(_INTERFACE_ID_ERC165);
	}

	/**
	 * @dev See {IERC165-supportsInterface}.
	 *
	 * Time complexity O(1), guaranteed to always use less than 30 000 gas.
	 */
	function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
		return _supportedInterfaces[interfaceId];
	}

	/**
	 * @dev Registers the contract as an implementer of the interface defined by
	 * `interfaceId`. Support of the actual ERC165 interface is automatic and
	 * registering its interface id is not required.
	 *
	 * See {IERC165-supportsInterface}.
	 *
	 * Requirements:
	 *
	 * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
	 */
	function _registerInterface(bytes4 interfaceId) internal virtual {
		require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
		_supportedInterfaces[interfaceId] = true;
	}
}

interface IERC721 is IERC165 {
	/**
	 * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
	 */
	event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

	/**
	 * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
	 */
	event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

	/**
	 * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
	 */
	event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

	/**
	 * @dev Returns the number of tokens in ``owner``'s account.
	 */
	function balanceOf(address owner) external view returns (uint256 balance);

	/**
	 * @dev Returns the owner of the `tokenId` token.
	 *
	 * Requirements:
	 *
	 * - `tokenId` must exist.
	 */
	function ownerOf(uint256 tokenId) external view returns (address owner);

	/**
	 * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
	 * are aware of the ERC721 protocol to prevent tokens from being forever locked.
	 *
	 * Requirements:
	 *
	 * - `from` cannot be the zero address.
	 * - `to` cannot be the zero address.
	 * - `tokenId` token must exist and be owned by `from`.
	 * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
	 * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
	 *
	 * Emits a {Transfer} event.
	 */
	function safeTransferFrom(address from, address to, uint256 tokenId) external;

	/**
	 * @dev Transfers `tokenId` token from `from` to `to`.
	 *
	 * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
	 *
	 * Requirements:
	 *
	 * - `from` cannot be the zero address.
	 * - `to` cannot be the zero address.
	 * - `tokenId` token must be owned by `from`.
	 * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
	 *
	 * Emits a {Transfer} event.
	 */
	function transferFrom(address from, address to, uint256 tokenId) external;

	/**
	 * @dev Gives permission to `to` to transfer `tokenId` token to another account.
	 * The approval is cleared when the token is transferred.
	 *
	 * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
	 *
	 * Requirements:
	 *
	 * - The caller must own the token or be an approved operator.
	 * - `tokenId` must exist.
	 *
	 * Emits an {Approval} event.
	 */
	function approve(address to, uint256 tokenId) external;

	/**
	 * @dev Returns the account approved for `tokenId` token.
	 *
	 * Requirements:
	 *
	 * - `tokenId` must exist.
	 */
	function getApproved(uint256 tokenId) external view returns (address operator);

	/**
	 * @dev Approve or remove `operator` as an operator for the caller.
	 * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
	 *
	 * Requirements:
	 *
	 * - The `operator` cannot be the caller.
	 *
	 * Emits an {ApprovalForAll} event.
	 */
	function setApprovalForAll(address operator, bool _approved) external;

	/**
	 * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
	 *
	 * See {setApprovalForAll}
	 */
	function isApprovedForAll(address owner, address operator) external view returns (bool);

	/**
	  * @dev Safely transfers `tokenId` token from `from` to `to`.
	  *
	  * Requirements:
	  *
	  * - `from` cannot be the zero address.
	  * - `to` cannot be the zero address.
	  * - `tokenId` token must exist and be owned by `from`.
	  * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
	  * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
	  *
	  * Emits a {Transfer} event.
	  */
	function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}

interface IERC721Enumerable is IERC721 {

	/**
	 * @dev Returns the total amount of tokens stored by the contract.
	 */
	function totalSupply() external view returns (uint256);

	/**
	 * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
	 * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
	 */
	function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);

	/**
	 * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
	 * Use along with {totalSupply} to enumerate all tokens.
	 */
	function tokenByIndex(uint256 index) external view returns (uint256);
}

interface IERC721Metadata is IERC721 {

	/**
	 * @dev Returns the token collection name.
	 */
	function name() external view returns (string memory);

	/**
	 * @dev Returns the token collection symbol.
	 */
	function symbol() external view returns (string memory);

	/**
	 * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
	 */
	function tokenURI(uint256 tokenId) external view returns (string memory);
}

contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable {
	using SafeMath for uint256;
	using Address for address;
	using EnumerableSet for EnumerableSet.UintSet;
	using EnumerableMap for EnumerableMap.UintToAddressMap;
	using Strings for uint256;

	// Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
	// which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
	bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

	// Mapping from holder address to their (enumerable) set of owned tokens
	mapping (address => EnumerableSet.UintSet) private _holderTokens;

	// Enumerable mapping from token ids to their owners
	EnumerableMap.UintToAddressMap private _tokenOwners;

	// Mapping from token ID to approved address
	mapping (uint256 => address) private _tokenApprovals;

	// Mapping from owner to operator approvals
	mapping (address => mapping (address => bool)) private _operatorApprovals;

	// Token name
	string private _name;

	// Token symbol
	string private _symbol;

	// Optional mapping for token URIs
	mapping (uint256 => string) private _tokenURIs;

	// Base URI
	string private _baseURI;

	/*
	 *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
	 *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
	 *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
	 *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
	 *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
	 *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
	 *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
	 *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
	 *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
	 *
	 *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
	 *        0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
	 */
	bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

	/*
	 *     bytes4(keccak256('name()')) == 0x06fdde03
	 *     bytes4(keccak256('symbol()')) == 0x95d89b41
	 *     bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
	 *
	 *     => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
	 */
	bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;

	/*
	 *     bytes4(keccak256('totalSupply()')) == 0x18160ddd
	 *     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
	 *     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
	 *
	 *     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
	 */
	bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;

	/**
	 * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
	 */
	constructor (string memory name_, string memory symbol_) public {
		_name = name_;
		_symbol = symbol_;

		// register the supported interfaces to conform to ERC721 via ERC165
		_registerInterface(_INTERFACE_ID_ERC721);
		_registerInterface(_INTERFACE_ID_ERC721_METADATA);
		_registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
	}

	/**
	 * @dev See {IERC721-balanceOf}.
	 */
	function balanceOf(address owner) public view virtual override returns (uint256) {
		require(owner != address(0), "ERC721: balance query for the zero address");
		return _holderTokens[owner].length();
	}

	/**
	 * @dev See {IERC721-ownerOf}.
	 */
	function ownerOf(uint256 tokenId) public view virtual override returns (address) {
		return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token");
	}

	/**
	 * @dev See {IERC721Metadata-name}.
	 */
	function name() public view virtual override returns (string memory) {
		return _name;
	}

	/**
	 * @dev See {IERC721Metadata-symbol}.
	 */
	function symbol() public view virtual override returns (string memory) {
		return _symbol;
	}

	/**
	 * @dev See {IERC721Metadata-tokenURI}.
	 */
	function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
		require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

		string memory _tokenURI = _tokenURIs[tokenId];
		string memory base = baseURI();

		// If there is no base URI, return the token URI.
		if (bytes(base).length == 0) {
			return _tokenURI;
		}
		// If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
		if (bytes(_tokenURI).length > 0) {
			return string(abi.encodePacked(base, _tokenURI));
		}
		// If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
		return string(abi.encodePacked(base, tokenId.toString()));
	}

	/**
	* @dev Returns the base URI set via {_setBaseURI}. This will be
	* automatically added as a prefix in {tokenURI} to each token's URI, or
	* to the token ID if no specific URI is set for that token ID.
	*/
	function baseURI() public view virtual returns (string memory) {
		return _baseURI;
	}

	/**
	 * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
	 */
	function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
		return _holderTokens[owner].at(index);
	}

	/**
	 * @dev See {IERC721Enumerable-totalSupply}.
	 */
	function totalSupply() public view virtual override returns (uint256) {
		// _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds
		return _tokenOwners.length();
	}

	/**
	 * @dev See {IERC721Enumerable-tokenByIndex}.
	 */
	function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
		(uint256 tokenId, ) = _tokenOwners.at(index);
		return tokenId;
	}

	/**
	 * @dev See {IERC721-approve}.
	 */
	function approve(address to, uint256 tokenId) public virtual override {
		address owner = ERC721.ownerOf(tokenId);
		require(to != owner, "ERC721: approval to current owner");

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

		_approve(to, tokenId);
	}

	/**
	 * @dev See {IERC721-getApproved}.
	 */
	function getApproved(uint256 tokenId) public view virtual override returns (address) {
		require(_exists(tokenId), "ERC721: approved query for nonexistent token");

		return _tokenApprovals[tokenId];
	}

	/**
	 * @dev See {IERC721-setApprovalForAll}.
	 */
	function setApprovalForAll(address operator, bool approved) public virtual override {
		require(operator != _msgSender(), "ERC721: approve to caller");

		_operatorApprovals[_msgSender()][operator] = approved;
		emit ApprovalForAll(_msgSender(), operator, approved);
	}

	/**
	 * @dev See {IERC721-isApprovedForAll}.
	 */
	function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
		return _operatorApprovals[owner][operator];
	}

	/**
	 * @dev See {IERC721-transferFrom}.
	 */
	function transferFrom(address from, address to, uint256 tokenId) public virtual override {
		//solhint-disable-next-line max-line-length
		require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

		_transfer(from, to, tokenId);
	}

	/**
	 * @dev See {IERC721-safeTransferFrom}.
	 */
	function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
		safeTransferFrom(from, to, tokenId, "");
	}

	/**
	 * @dev See {IERC721-safeTransferFrom}.
	 */
	function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override {
		require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
		_safeTransfer(from, to, tokenId, _data);
	}

	/**
	 * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
	 * are aware of the ERC721 protocol to prevent tokens from being forever locked.
	 *
	 * `_data` is additional data, it has no specified format and it is sent in call to `to`.
	 *
	 * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
	 * implement alternative mechanisms to perform token transfer, such as signature-based.
	 *
	 * Requirements:
	 *
	 * - `from` cannot be the zero address.
	 * - `to` cannot be the zero address.
	 * - `tokenId` token must exist and be owned by `from`.
	 * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
	 *
	 * Emits a {Transfer} event.
	 */
	function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {
		_transfer(from, to, tokenId);
		require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
	}

	/**
	 * @dev Returns whether `tokenId` exists.
	 *
	 * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
	 *
	 * Tokens start existing when they are minted (`_mint`),
	 * and stop existing when they are burned (`_burn`).
	 */
	function _exists(uint256 tokenId) internal view virtual returns (bool) {
		return _tokenOwners.contains(tokenId);
	}

	/**
	 * @dev Returns whether `spender` is allowed to manage `tokenId`.
	 *
	 * Requirements:
	 *
	 * - `tokenId` must exist.
	 */
	function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
		require(_exists(tokenId), "ERC721: operator query for nonexistent token");
		address owner = ERC721.ownerOf(tokenId);
		return (spender == owner || getApproved(tokenId) == spender || ERC721.isApprovedForAll(owner, spender));
	}

	/**
	 * @dev Safely mints `tokenId` and transfers it to `to`.
	 *
	 * Requirements:
	 d*
	 * - `tokenId` must not exist.
	 * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
	 *
	 * Emits a {Transfer} event.
	 */
	function _safeMint(address to, uint256 tokenId) internal virtual {
		_safeMint(to, tokenId, "");
	}

	/**
	 * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
	 * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
	 */
	function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
		_mint(to, tokenId);
		require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
	}

	/**
	 * @dev Mints `tokenId` and transfers it to `to`.
	 *
	 * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
	 *
	 * Requirements:
	 *
	 * - `tokenId` must not exist.
	 * - `to` cannot be the zero address.
	 *
	 * Emits a {Transfer} event.
	 */
	function _mint(address to, uint256 tokenId) internal virtual {
		require(to != address(0), "ERC721: mint to the zero address");
		require(!_exists(tokenId), "ERC721: token already minted");

		_beforeTokenTransfer(address(0), to, tokenId);

		_holderTokens[to].add(tokenId);

		_tokenOwners.set(tokenId, to);

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

	/**
	 * @dev Destroys `tokenId`.
	 * The approval is cleared when the token is burned.
	 *
	 * Requirements:
	 *
	 * - `tokenId` must exist.
	 *
	 * Emits a {Transfer} event.
	 */
	function _burn(uint256 tokenId) internal virtual {
		address owner = ERC721.ownerOf(tokenId); // internal owner

		_beforeTokenTransfer(owner, address(0), tokenId);

		// Clear approvals
		_approve(address(0), tokenId);

		// Clear metadata (if any)
		if (bytes(_tokenURIs[tokenId]).length != 0) {
			delete _tokenURIs[tokenId];
		}

		_holderTokens[owner].remove(tokenId);

		_tokenOwners.remove(tokenId);

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

	/**
	 * @dev Transfers `tokenId` from `from` to `to`.
	 *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
	 *
	 * Requirements:
	 *
	 * - `to` cannot be the zero address.
	 * - `tokenId` token must be owned by `from`.
	 *
	 * Emits a {Transfer} event.
	 */
	function _transfer(address from, address to, uint256 tokenId) internal virtual {
		require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); // internal owner
		require(to != address(0), "ERC721: transfer to the zero address");

		_beforeTokenTransfer(from, to, tokenId);

		// Clear approvals from the previous owner
		_approve(address(0), tokenId);

		_holderTokens[from].remove(tokenId);
		_holderTokens[to].add(tokenId);

		_tokenOwners.set(tokenId, to);

		emit Transfer(from, to, tokenId);
	}

	/**
	 * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
	 *
	 * Requirements:
	 *
	 * - `tokenId` must exist.
	 */
	function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
		require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
		_tokenURIs[tokenId] = _tokenURI;
	}

	/**
	 * @dev Internal function to set the base URI for all token IDs. It is
	 * automatically added as a prefix to the value returned in {tokenURI},
	 * or to the token ID if {tokenURI} is empty.
	 */
	function _setBaseURI(string memory baseURI_) internal virtual {
		_baseURI = baseURI_;
	}

	/**
	 * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
	 * The call is not executed if the target address is not a contract.
	 *
	 * @param from address representing the previous owner of the given token ID
	 * @param to target address that will receive the tokens
	 * @param tokenId uint256 ID of the token to be transferred
	 * @param _data bytes optional data to send along with the call
	 * @return bool whether the call correctly returned the expected magic value
	 */
	function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
	private returns (bool)
	{
		if (!to.isContract()) {
			return true;
		}
		bytes memory returndata = to.functionCall(abi.encodeWithSelector(
				IERC721Receiver(to).onERC721Received.selector,
				_msgSender(),
				from,
				tokenId,
				_data
			), "ERC721: transfer to non ERC721Receiver implementer");
		bytes4 retval = abi.decode(returndata, (bytes4));
		return (retval == _ERC721_RECEIVED);
	}

	/**
	 * @dev Approve `to` to operate on `tokenId`
	 *
	 * Emits an {Approval} event.
	 */
	function _approve(address to, uint256 tokenId) internal virtual {
		_tokenApprovals[tokenId] = to;
		emit Approval(ERC721.ownerOf(tokenId), to, tokenId); // internal owner
	}

	/**
	 * @dev Hook that is called before any token transfer. This includes minting
	 * and burning.
	 *
	 * Calling conditions:
	 *
	 * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
	 * transferred to `to`.
	 * - When `from` is zero, `tokenId` will be minted for `to`.
	 * - When `to` is zero, ``from``'s `tokenId` will be burned.
	 * - `from` cannot be the zero address.
	 * - `to` cannot be the zero address.
	 *
	 * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
	 */
	function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { }
}

pragma solidity >=0.6.0 <0.8.0;
pragma experimental ABIEncoderV2;

//SPDX-License-Identifier: UNLICENSED

import "./ERC721.sol";

contract Mounts is ERC721, ReentrancyGuard, Ownable {
	using SafeMath for uint256;

	constructor() ERC721("Mounts (for Adventurers)", "MOUNT") {}
	address public lootAddress = 0xFF9C1b15B16263C61d017ee9F65C50e4AE0113D7;
	LootInterface lootContract = LootInterface(lootAddress);

	string public PROVENANCE = "";

	uint256 public maxSupply = 8000;
	uint256 public currentSupply = 0;

	uint256 public lootersPrice = 10000000000000000; // 0.01 ETH
	uint256 public publicPrice = 20000000000000000; // 0.02 ETH

	string[] private creature = [
		"Horse", "Horse", "Horse",
		"Dragon",
		"Gryffin", "Gryffin",
		"Camel", "Camel", "Camel",
		"Poney", "Poney", "Poney",
		"Elephant", "Elephant",
		"Hound", "Hound", "Hound",
		"Shark", "Shark",
		"Hippogryff", "Hippogryff",
		"Bull", "Bull", "Bull",
		"Bear", "Bear", "Bear",
		"Ostrich", "Ostrich",
		"Donkey", "Donkey"
	];
	string[] private creaturePrefix = ["Black", "White", "Blue", "Red", "Green", "Silver", "Golden", "Courageous", "Divine", "Holy", "Demonic", "Young", "Ancient", "Docile", "Proud", "Bold", "Quirky", "Brave", "Rash", "Impish", "Quiet", "Lonely", "Ice", "Fire"];

	string[] private saddle = ["saddle"];
	string[] private saddlePrefix = ["General purpose", "Dressage", "Jumping", "Hunting", "Racing", "Double", "Endurance", "Roping", "Leather"];

	string[] private equipment = ["Helmet", "Armor", "Collar", "Harness"];
	string[] private equipmentPrefix = ["Ancient", "Golden", "Heavy", "Light", "Dragonskin", "Chain", "Ornate", "Spiky", "Holy", "Silver", "Great", "Bronze", "Iron", "Platinum", "Unholy"];

	string[] private inventory = ["pouch", "bag", "satchel", "purse", "saddlebag", "basket", "seat bag", "wedge pack"];
	string[] private inventoryPrefix = ["Large", "Small", "Medium", "Bountiful", "Empty"];

	function getCreature(uint256 tokenId) public view returns (string memory) {
		return pluck(tokenId, "Creature", creature, creaturePrefix);
	}

	function getSaddle(uint256 tokenId) public view returns (string memory) {
		return pluck(tokenId, "Saddle", saddle, saddlePrefix);
	}

	function getEquipment(uint256 tokenId) public view returns (string memory) {
		return pluck(tokenId, "Equipment", equipment, equipmentPrefix);
	}

	function getInventory(uint256 tokenId) public view returns (string memory) {
		return pluck(tokenId, "Inventory", inventory, inventoryPrefix);
	}

	function getFullDescription(uint256 tokenId) public view returns (string memory) {
		return string(abi.encodePacked(
			getCreature(tokenId), " + ",
			getSaddle(tokenId), " + ",
			getEquipment(tokenId), " + ",
			getInventory(tokenId)
		));
	}

	function random(string memory input) public pure returns (uint256) {
		return uint256(keccak256(abi.encodePacked(input))) % 31;
	}

	function pluckRoll(uint256 tokenId, string memory keyPrefix) internal pure returns (string memory) {
		uint256 roll1 = random(string(abi.encodePacked(keyPrefix, toString(tokenId), "1")));
		uint256 min = roll1;
		uint256 roll2 = random(string(abi.encodePacked(keyPrefix, toString(tokenId), "2")));
		min = min > roll2 ? roll2 : min;
		uint256 roll3 = random(string(abi.encodePacked(keyPrefix, toString(tokenId), "3")));
		min = min > roll3 ? roll3 : min;
		uint256 roll4 = random(string(abi.encodePacked(keyPrefix, toString(tokenId), "4")));
		min = min > roll4 ? roll4 : min;

		// get 3 highest dice rolls
		uint256 stat = roll1 * roll2 * roll3 + roll4 + roll3 - min;

		string memory output = string(abi.encodePacked(toString(stat)));

		return output;
	}

	function pluck(
		uint256 tokenId,
		string memory keyPrefix,
		string[] memory sourceArray,
		string[] memory prefixes
	) internal view returns (string memory) {
		uint256 randA = random(
			string(abi.encodePacked(keyPrefix, toString(tokenId*7)))
		);
		uint256 randB = random(
			string(abi.encodePacked(keyPrefix, toString(tokenId*4)))
		);

		string memory output = sourceArray[randA % sourceArray.length];
		output = string(
			abi.encodePacked(prefixes[randB % prefixes.length], " ", output)
		);

		string memory actual = string(abi.encodePacked(output));
		return actual;
	}

	function withdraw() public onlyOwner {
		uint balance = address(this).balance;
		msg.sender.transfer(balance);
	}

	function deposit() public payable onlyOwner {}


	function setLootersPrice(uint256 newPrice) public onlyOwner {
		lootersPrice = newPrice;
	}

	function setPublicPrice(uint256 newPrice) public onlyOwner {
		publicPrice = newPrice;
	}

	function setBaseURI(string memory baseURI) public onlyOwner {
		_setBaseURI(baseURI);
	}

	function setProvenance(string memory prov) public onlyOwner {
		PROVENANCE = prov;
	}

	// Loot owners minting
	function mintWithLoot(uint lootId) public payable nonReentrant {
		require(lootContract.ownerOf(lootId) == msg.sender, "This Loot is not owned by the minter");
		require(lootersPrice <= msg.value, "Not enough Ether sent");
		require(currentSupply < maxSupply, "All mounts are minted");
		_safeMint(msg.sender, currentSupply);
		currentSupply += 1;
	}

	// Public minting
	function mint() public payable nonReentrant {
		require(publicPrice <= msg.value, "Not enough Ether sent");
		require(currentSupply < maxSupply, "All mounts are minted");

		_safeMint(msg.sender, currentSupply);
		currentSupply += 1;
	}

	function toString(uint256 value) internal pure returns (string memory) {
		if (value == 0) {
			return "0";
		}
		uint256 temp = value;
		uint256 digits;
		while (temp != 0) {
			digits++;
			temp /= 10;
		}
		bytes memory buffer = new bytes(digits);
		while (value != 0) {
			digits -= 1;
			buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
			value /= 10;
		}
		return string(buffer);
	}

	function tokenURI(uint256 tokenId) override public view returns (string memory) {
		string[9] memory parts;
		parts[0] = '<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350"><style>.base { fill: white; font-family: serif; font-size: 14px; }</style><rect width="100%" height="100%" fill="black" /><text x="10" y="20" class="base">';

		parts[1] = getCreature(tokenId);

		parts[2] = '</text><text x="10" y="40" class="base">';

		parts[3] = getSaddle(tokenId);

		parts[4] = '</text><text x="10" y="60" class="base">';

		parts[5] = getEquipment(tokenId);

		parts[6] = '</text><text x="10" y="80" class="base">';

		parts[7] = getInventory(tokenId);

		parts[8] = '</text></svg>';

		string memory output = string(abi.encodePacked(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8]));
		//output = string(abi.encodePacked(output, parts[9], parts[10], parts[11], parts[12], parts[13], parts[14], parts[15], parts[16]));

		string memory json = Base64.encode(bytes(string(abi.encodePacked('{"name": "Mount #', toString(tokenId), '", "description": "Welcome, weary traveler ! Which mounts will you pick to help you wander from realms to realms ?", "image": "data:image/svg+xml;base64,', Base64.encode(bytes(output)), '"}'))));
		output = string(abi.encodePacked('data:application/json;base64,', json));

		return output;
	}
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):