ETH Price: $2,492.29 (-4.01%)

Transaction Decoder

Block:
22839673 at Jul-03-2025 03:44:59 PM +UTC
Transaction Fee:
0.0001812253795257 ETH $0.45
Gas Used:
75,045 Gas / 2.41488946 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x49dfba00...5335Ae887 From: 22892027388384995767342970845840195767820421313931743448 To: 22892026365094219175075457891378177040480732125407136429
0x72785D42...e1a5238df
3.056171664004887532 Eth
Nonce: 1232
3.055990438625361832 Eth
Nonce: 1233
0.0001812253795257
0xAa9ae095...3f38A23C0
(BuilderNet)
15.007101235047444906 Eth15.007101275348260896 Eth0.00000004030081599

Execution Trace

0x49dfba008e80aebd9ee5cbffc92581b5335ae887.174dea71( )
  • Stampu.safeTransferFrom( from=0x49dfba008E80AEbd9Ee5CBffC92581b5335Ae887, to=0x72785D42874E965086829eA789a703fe1a5238df, id=19, amount=4, data=0x )
    • 0x72785d42874e965086829ea789a703fe1a5238df.f23a6e61( )
      //SPDX-License-Identifier: MIT
      pragma solidity ^0.8.4;
      import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
      import "@openzeppelin/contracts/access/Ownable.sol";
      import "@openzeppelin/contracts/utils/Strings.sol";
      import "@openzeppelin/contracts/utils/Counters.sol";
      import "./IERC2981.sol";
      /////////////////////////////////////////////////////////////////////
      //  ______     ______   ______     __    __     ______   __  __    //
      // /\\  ___\\   /\\__  _\\ /\\  __ \\   /\\ "-./  \\   /\\  == \\ /\\ \\/\\ \\   //
      // \\ \\___  \\  \\/_/\\ \\/ \\ \\  __ \\  \\ \\ \\-./\\ \\  \\ \\  _-/ \\ \\ \\_\\ \\  //
      //  \\/\\_____\\    \\ \\_\\  \\ \\_\\ \\_\\  \\ \\_\\ \\ \\_\\  \\ \\_\\    \\ \\_____\\ //
      //   \\/_____/     \\/_/   \\/_/\\/_/   \\/_/  \\/_/   \\/_/     \\/_____/ //
      //                                                                 //
      /////////////////////////////////////////////////////////////////////
      contract Stampu is IERC2981, ERC1155, Ownable {
        bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a;
        struct StampInfo {
          address payable artist;
          uint256 maxSupply;
          uint256 currentSupply;
          uint256 mintPrice;
          uint256 mintLimit; // mint limit per tx. 0 works as pause.
        }
        event SendPostcard(
          uint256 indexed postcardId,
          address indexed from,
          address indexed to,
          uint256 tokenId,
          string fromText,
          string toText,
          string message,
          uint256 value
        );
        using Strings for uint256;
        using Counters for Counters.Counter;
        Counters.Counter private _tokenIdCounter;
        Counters.Counter private _postcardIdCounter;
        string internal _baseURI;
        address internal _royaltyRecipient;
        uint8 internal _royaltyFee; // out of 1000
        // Contract name
        string public name;
        // Contract symbol
        string public symbol;
        mapping(uint256 => StampInfo) public tokenIdToStampInfo;
        constructor(
          string memory _name,
          string memory _symbol,
          string memory _uri,
          address royaltyRecipient,
          uint8 royaltyFee
        ) ERC1155("") {
          name = _name;
          symbol = _symbol;
          _baseURI = _uri;
          setRoyaltyRecipient(royaltyRecipient);
          setRoyaltyFee(royaltyFee);
        }
        function setURI(string memory newuri) public onlyOwner {
          _baseURI = newuri;
        }
        function uri(uint256 _id) public view override returns (string memory) {
          require(_id < _tokenIdCounter.current(), "nonexistent token");
          return string(abi.encodePacked(_baseURI, _id.toString()));
        }
        /**
         * @dev Adds new Stampus (mint is paused by default).
         */
        function addStampus(
          address payable[] calldata artists,
          uint256[] calldata maxSupplies,
          uint256[] calldata mintPrices
        ) public onlyOwner {
          require(artists.length == maxSupplies.length && artists.length == mintPrices.length, "input lengths do not match");
          for (uint256 i = 0; i < artists.length; i++) {
            uint256 tokenId = _tokenIdCounter.current();
            _tokenIdCounter.increment();
            tokenIdToStampInfo[tokenId] = StampInfo({
              artist: artists[i],
              maxSupply: maxSupplies[i],
              currentSupply: 0,
              mintPrice: mintPrices[i],
              mintLimit: 0 // paused by default. Can be unpaused through `setMintLimit`.
            });
          }
        }
        /**
         * @dev Updates artist address (in case of theft or lost wallet).
         */
        function updateArtistAddress(uint256 id, address payable artist) public onlyOwner {
          require(id < _tokenIdCounter.current(), "nonexistent token");
          require(artist != address(0), "Invalid artist address");
          StampInfo storage stampInfo = tokenIdToStampInfo[id];
          stampInfo.artist = artist;
        }
        /**
         * @dev Mints ignoring the mint limit and price (onlyOwner).
         */
        function preMint(
          address account,
          uint256 id,
          uint256 amount
        ) public onlyOwner {
          require(id < _tokenIdCounter.current(), "nonexistent token");
          StampInfo storage stampInfo = tokenIdToStampInfo[id];
          uint256 newSupply = stampInfo.currentSupply + amount;
          require(newSupply <= stampInfo.maxSupply, "exceeds max supply");
          stampInfo.currentSupply = newSupply;
          _mint(account, id, amount, "");
        }
        /**
         * @dev Mints Stampu(s).
         */
        function mint(
          address account,
          uint256 id,
          uint256 amount
        ) public payable {
          require(id < _tokenIdCounter.current(), "nonexistent token");
          StampInfo storage stampInfo = tokenIdToStampInfo[id];
          // Owner is allowed to mint even when minting is paused.
          if (owner() != _msgSender()) {
            require(amount <= stampInfo.mintLimit, "exceeds the allowed mint limit");
          }
          require(msg.value >= stampInfo.mintPrice * amount, "insufficient mint price");
          uint256 newSupply = stampInfo.currentSupply + amount;
          require(newSupply <= stampInfo.maxSupply, "exceeds max supply");
          stampInfo.currentSupply = newSupply;
          uint256 artistCut = _getArtistCut(stampInfo.mintPrice * amount);
          (bool success, ) = stampInfo.artist.call{value: artistCut}("");
          require(success, "arist payment failed");
          _mint(account, id, amount, "");
        }
        /**
         * @dev Sets `mintLimit` of `tokenIds`.
         *
         * Setting `mintLimit` from 0 is equivalent to unpausing mint.
         */
        function setMintLimit(uint256[] calldata tokenIds, uint256[] calldata mintLimits) public onlyOwner {
          require(tokenIds.length == mintLimits.length, "input array lengths must be the same");
          for (uint256 i = 0; i < tokenIds.length; i++) {
            uint256 tokenId = tokenIds[i];
            require(tokenId < _tokenIdCounter.current(), "nonexistent token");
            tokenIdToStampInfo[tokenId].mintLimit = mintLimits[i];
          }
        }
        /**
         * @dev Sends a postcard along with a Stampu and optionally with ETH.
         */
        function sendPostcard(
          address payable to,
          uint256 id,
          string calldata fromText,
          string calldata toText,
          string calldata message
        ) public payable {
          _sendPostcard(to, id, fromText, toText, message, msg.value);
        }
        function _sendPostcard(
          address payable to,
          uint256 id,
          string calldata fromText,
          string calldata toText,
          string calldata message,
          uint256 value
        ) private {
          if (value > 0) {
            (bool success, ) = to.call{value: value}("");
            require(success, "payment failed");
          }
          safeTransferFrom(_msgSender(), to, id, 1, "");
          emit SendPostcard(_postcardIdCounter.current(), _msgSender(), to, id, fromText, toText, message, value);
          _postcardIdCounter.increment();
        }
        /**
         * @dev Sends multiple postcards in a single transaction.
         */
        function batchSendPostcards(
          address payable[] calldata toAddresses,
          uint256 id,
          string calldata fromText,
          string calldata toText,
          string calldata message
        ) public payable {
          // Value should be a multiple of the number of receipents.
          // The contract will keep the remainder if any.
          uint256 valuePerPostCard = msg.value / toAddresses.length;
          for (uint256 i = 0; i < toAddresses.length; i++) {
            _sendPostcard(toAddresses[i], id, fromText, toText, message, valuePerPostCard);
          }
        }
        /**
         * @dev Withdraws fees accumulated in the contract (onlyOwner).
         */
        function withdrawFees() public onlyOwner {
          (bool sent, ) = msg.sender.call{value: address(this).balance}("");
          require(sent, "failed to send collected fees");
        }
        /**
         * @dev Mints and sends a postcard in a single transaction.
         */
        function mintAndSendPostcard(
          address payable to,
          uint256 id,
          string calldata fromText,
          string calldata toText,
          string calldata message
        ) public payable {
          mint(_msgSender(), id, 1);
          uint256 valueLeft = msg.value - tokenIdToStampInfo[id].mintPrice;
          _sendPostcard(to, id, fromText, toText, message, valueLeft);
        }
        // Royalty functions:
        function setRoyaltyRecipient(address royaltyRecipient) public onlyOwner {
          require(royaltyRecipient != address(0), "Invalid royalty recipient address");
          _royaltyRecipient = royaltyRecipient;
        }
        function setRoyaltyFee(uint8 royaltyFee) public onlyOwner {
          require(royaltyFee <= 1000, "Invalid royalty fee");
          _royaltyFee = royaltyFee;
        }
        function royaltyInfo(uint256, uint256 _salePrice) external view override returns (address, uint256) {
          return (_royaltyRecipient, (_salePrice * _royaltyFee) / 1000);
        }
        function supportsInterface(bytes4 interfaceId) public view override(IERC2981, ERC1155) returns (bool) {
          return interfaceId == _INTERFACE_ID_ERC2981 || super.supportsInterface(interfaceId);
        }
        // Utility functions:
        function _getArtistCut(uint256 mintPrice) internal pure returns (uint256) {
          return (mintPrice * 9) / 10;
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import "./IERC1155.sol";
      import "./IERC1155Receiver.sol";
      import "./extensions/IERC1155MetadataURI.sol";
      import "../../utils/Address.sol";
      import "../../utils/Context.sol";
      import "../../utils/introspection/ERC165.sol";
      /**
       * @dev Implementation of the basic standard multi-token.
       * See https://eips.ethereum.org/EIPS/eip-1155
       * Originally based on code by Enjin: https://github.com/enjin/erc-1155
       *
       * _Available since v3.1._
       */
      contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
          using Address for address;
          // Mapping from token ID to account balances
          mapping(uint256 => mapping(address => uint256)) private _balances;
          // Mapping from account to operator approvals
          mapping(address => mapping(address => bool)) private _operatorApprovals;
          // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
          string private _uri;
          /**
           * @dev See {_setURI}.
           */
          constructor(string memory uri_) {
              _setURI(uri_);
          }
          /**
           * @dev See {IERC165-supportsInterface}.
           */
          function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
              return
                  interfaceId == type(IERC1155).interfaceId ||
                  interfaceId == type(IERC1155MetadataURI).interfaceId ||
                  super.supportsInterface(interfaceId);
          }
          /**
           * @dev See {IERC1155MetadataURI-uri}.
           *
           * This implementation returns the same URI for *all* token types. It relies
           * on the token type ID substitution mechanism
           * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
           *
           * Clients calling this function must replace the `\\{id\\}` substring with the
           * actual token type ID.
           */
          function uri(uint256) public view virtual override returns (string memory) {
              return _uri;
          }
          /**
           * @dev See {IERC1155-balanceOf}.
           *
           * Requirements:
           *
           * - `account` cannot be the zero address.
           */
          function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
              require(account != address(0), "ERC1155: balance query for the zero address");
              return _balances[id][account];
          }
          /**
           * @dev See {IERC1155-balanceOfBatch}.
           *
           * Requirements:
           *
           * - `accounts` and `ids` must have the same length.
           */
          function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
              public
              view
              virtual
              override
              returns (uint256[] memory)
          {
              require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
              uint256[] memory batchBalances = new uint256[](accounts.length);
              for (uint256 i = 0; i < accounts.length; ++i) {
                  batchBalances[i] = balanceOf(accounts[i], ids[i]);
              }
              return batchBalances;
          }
          /**
           * @dev See {IERC1155-setApprovalForAll}.
           */
          function setApprovalForAll(address operator, bool approved) public virtual override {
              require(_msgSender() != operator, "ERC1155: setting approval status for self");
              _operatorApprovals[_msgSender()][operator] = approved;
              emit ApprovalForAll(_msgSender(), operator, approved);
          }
          /**
           * @dev See {IERC1155-isApprovedForAll}.
           */
          function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
              return _operatorApprovals[account][operator];
          }
          /**
           * @dev See {IERC1155-safeTransferFrom}.
           */
          function safeTransferFrom(
              address from,
              address to,
              uint256 id,
              uint256 amount,
              bytes memory data
          ) public virtual override {
              require(
                  from == _msgSender() || isApprovedForAll(from, _msgSender()),
                  "ERC1155: caller is not owner nor approved"
              );
              _safeTransferFrom(from, to, id, amount, data);
          }
          /**
           * @dev See {IERC1155-safeBatchTransferFrom}.
           */
          function safeBatchTransferFrom(
              address from,
              address to,
              uint256[] memory ids,
              uint256[] memory amounts,
              bytes memory data
          ) public virtual override {
              require(
                  from == _msgSender() || isApprovedForAll(from, _msgSender()),
                  "ERC1155: transfer caller is not owner nor approved"
              );
              _safeBatchTransferFrom(from, to, ids, amounts, data);
          }
          /**
           * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
           *
           * Emits a {TransferSingle} event.
           *
           * Requirements:
           *
           * - `to` cannot be the zero address.
           * - `from` must have a balance of tokens of type `id` of at least `amount`.
           * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
           * acceptance magic value.
           */
          function _safeTransferFrom(
              address from,
              address to,
              uint256 id,
              uint256 amount,
              bytes memory data
          ) internal virtual {
              require(to != address(0), "ERC1155: transfer to the zero address");
              address operator = _msgSender();
              _beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data);
              uint256 fromBalance = _balances[id][from];
              require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
              unchecked {
                  _balances[id][from] = fromBalance - amount;
              }
              _balances[id][to] += amount;
              emit TransferSingle(operator, from, to, id, amount);
              _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
          }
          /**
           * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
           *
           * Emits a {TransferBatch} event.
           *
           * Requirements:
           *
           * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
           * acceptance magic value.
           */
          function _safeBatchTransferFrom(
              address from,
              address to,
              uint256[] memory ids,
              uint256[] memory amounts,
              bytes memory data
          ) internal virtual {
              require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
              require(to != address(0), "ERC1155: transfer to the zero address");
              address operator = _msgSender();
              _beforeTokenTransfer(operator, from, to, ids, amounts, data);
              for (uint256 i = 0; i < ids.length; ++i) {
                  uint256 id = ids[i];
                  uint256 amount = amounts[i];
                  uint256 fromBalance = _balances[id][from];
                  require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
                  unchecked {
                      _balances[id][from] = fromBalance - amount;
                  }
                  _balances[id][to] += amount;
              }
              emit TransferBatch(operator, from, to, ids, amounts);
              _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
          }
          /**
           * @dev Sets a new URI for all token types, by relying on the token type ID
           * substitution mechanism
           * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
           *
           * By this mechanism, any occurrence of the `\\{id\\}` substring in either the
           * URI or any of the amounts in the JSON file at said URI will be replaced by
           * clients with the token type ID.
           *
           * For example, the `https://token-cdn-domain/\\{id\\}.json` URI would be
           * interpreted by clients as
           * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
           * for token type ID 0x4cce0.
           *
           * See {uri}.
           *
           * Because these URIs cannot be meaningfully represented by the {URI} event,
           * this function emits no events.
           */
          function _setURI(string memory newuri) internal virtual {
              _uri = newuri;
          }
          /**
           * @dev Creates `amount` tokens of token type `id`, and assigns them to `account`.
           *
           * Emits a {TransferSingle} event.
           *
           * Requirements:
           *
           * - `account` cannot be the zero address.
           * - If `account` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
           * acceptance magic value.
           */
          function _mint(
              address account,
              uint256 id,
              uint256 amount,
              bytes memory data
          ) internal virtual {
              require(account != address(0), "ERC1155: mint to the zero address");
              address operator = _msgSender();
              _beforeTokenTransfer(operator, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data);
              _balances[id][account] += amount;
              emit TransferSingle(operator, address(0), account, id, amount);
              _doSafeTransferAcceptanceCheck(operator, address(0), account, id, amount, data);
          }
          /**
           * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
           *
           * Requirements:
           *
           * - `ids` and `amounts` must have the same length.
           * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
           * acceptance magic value.
           */
          function _mintBatch(
              address to,
              uint256[] memory ids,
              uint256[] memory amounts,
              bytes memory data
          ) internal virtual {
              require(to != address(0), "ERC1155: mint to the zero address");
              require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
              address operator = _msgSender();
              _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
              for (uint256 i = 0; i < ids.length; i++) {
                  _balances[ids[i]][to] += amounts[i];
              }
              emit TransferBatch(operator, address(0), to, ids, amounts);
              _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
          }
          /**
           * @dev Destroys `amount` tokens of token type `id` from `account`
           *
           * Requirements:
           *
           * - `account` cannot be the zero address.
           * - `account` must have at least `amount` tokens of token type `id`.
           */
          function _burn(
              address account,
              uint256 id,
              uint256 amount
          ) internal virtual {
              require(account != address(0), "ERC1155: burn from the zero address");
              address operator = _msgSender();
              _beforeTokenTransfer(operator, account, address(0), _asSingletonArray(id), _asSingletonArray(amount), "");
              uint256 accountBalance = _balances[id][account];
              require(accountBalance >= amount, "ERC1155: burn amount exceeds balance");
              unchecked {
                  _balances[id][account] = accountBalance - amount;
              }
              emit TransferSingle(operator, account, address(0), id, amount);
          }
          /**
           * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
           *
           * Requirements:
           *
           * - `ids` and `amounts` must have the same length.
           */
          function _burnBatch(
              address account,
              uint256[] memory ids,
              uint256[] memory amounts
          ) internal virtual {
              require(account != address(0), "ERC1155: burn from the zero address");
              require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
              address operator = _msgSender();
              _beforeTokenTransfer(operator, account, address(0), ids, amounts, "");
              for (uint256 i = 0; i < ids.length; i++) {
                  uint256 id = ids[i];
                  uint256 amount = amounts[i];
                  uint256 accountBalance = _balances[id][account];
                  require(accountBalance >= amount, "ERC1155: burn amount exceeds balance");
                  unchecked {
                      _balances[id][account] = accountBalance - amount;
                  }
              }
              emit TransferBatch(operator, account, address(0), ids, amounts);
          }
          /**
           * @dev Hook that is called before any token transfer. This includes minting
           * and burning, as well as batched variants.
           *
           * The same hook is called on both single and batched variants. For single
           * transfers, the length of the `id` and `amount` arrays will be 1.
           *
           * Calling conditions (for each `id` and `amount` pair):
           *
           * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
           * of token type `id` will be  transferred to `to`.
           * - When `from` is zero, `amount` tokens of token type `id` will be minted
           * for `to`.
           * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
           * will be burned.
           * - `from` and `to` are never both zero.
           * - `ids` and `amounts` have the same, non-zero length.
           *
           * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
           */
          function _beforeTokenTransfer(
              address operator,
              address from,
              address to,
              uint256[] memory ids,
              uint256[] memory amounts,
              bytes memory data
          ) internal virtual {}
          function _doSafeTransferAcceptanceCheck(
              address operator,
              address from,
              address to,
              uint256 id,
              uint256 amount,
              bytes memory data
          ) private {
              if (to.isContract()) {
                  try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
                      if (response != IERC1155Receiver.onERC1155Received.selector) {
                          revert("ERC1155: ERC1155Receiver rejected tokens");
                      }
                  } catch Error(string memory reason) {
                      revert(reason);
                  } catch {
                      revert("ERC1155: transfer to non ERC1155Receiver implementer");
                  }
              }
          }
          function _doSafeBatchTransferAcceptanceCheck(
              address operator,
              address from,
              address to,
              uint256[] memory ids,
              uint256[] memory amounts,
              bytes memory data
          ) private {
              if (to.isContract()) {
                  try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
                      bytes4 response
                  ) {
                      if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
                          revert("ERC1155: ERC1155Receiver rejected tokens");
                      }
                  } catch Error(string memory reason) {
                      revert(reason);
                  } catch {
                      revert("ERC1155: transfer to non ERC1155Receiver implementer");
                  }
              }
          }
          function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
              uint256[] memory array = new uint256[](1);
              array[0] = element;
              return array;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import "../utils/Context.sol";
      /**
       * @dev Contract module which provides a basic access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * By default, the owner account will be the one that deploys the contract. This
       * can later be changed with {transferOwnership}.
       *
       * This module is used through inheritance. It will make available the modifier
       * `onlyOwner`, which can be applied to your functions to restrict their use to
       * the owner.
       */
      abstract contract Ownable is Context {
          address private _owner;
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
          /**
           * @dev Initializes the contract setting the deployer as the initial owner.
           */
          constructor() {
              _setOwner(_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 {
              _setOwner(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");
              _setOwner(newOwner);
          }
          function _setOwner(address newOwner) private {
              address oldOwner = _owner;
              _owner = newOwner;
              emit OwnershipTransferred(oldOwner, newOwner);
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @dev String operations.
       */
      library Strings {
          bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
          /**
           * @dev Converts a `uint256` to its ASCII `string` decimal 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);
              while (value != 0) {
                  digits -= 1;
                  buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                  value /= 10;
              }
              return string(buffer);
          }
          /**
           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
           */
          function toHexString(uint256 value) internal pure returns (string memory) {
              if (value == 0) {
                  return "0x00";
              }
              uint256 temp = value;
              uint256 length = 0;
              while (temp != 0) {
                  length++;
                  temp >>= 8;
              }
              return toHexString(value, length);
          }
          /**
           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
           */
          function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
              bytes memory buffer = new bytes(2 * length + 2);
              buffer[0] = "0";
              buffer[1] = "x";
              for (uint256 i = 2 * length + 1; i > 1; --i) {
                  buffer[i] = _HEX_SYMBOLS[value & 0xf];
                  value >>= 4;
              }
              require(value == 0, "Strings: hex length insufficient");
              return string(buffer);
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @title Counters
       * @author Matt Condon (@shrugs)
       * @dev Provides counters that can only be incremented, decremented or reset. 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;`
       */
      library Counters {
          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 {
              unchecked {
                  counter._value += 1;
              }
          }
          function decrement(Counter storage counter) internal {
              uint256 value = counter._value;
              require(value > 0, "Counter: decrement overflow");
              unchecked {
                  counter._value = value - 1;
              }
          }
          function reset(Counter storage counter) internal {
              counter._value = 0;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.4;
      import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
      /**
       * @dev Interface for the NFT Royalty Standard.
       * See https://eips.ethereum.org/EIPS/eip-2981
       */
      interface IERC2981 is IERC165 {
        function royaltyInfo(uint256 _tokenId, uint256 _salePrice)
          external
          view
          returns (address receiver, uint256 royaltyAmount);
        function supportsInterface(bytes4 interfaceID) external view override(IERC165) returns (bool);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import "../../utils/introspection/IERC165.sol";
      /**
       * @dev Required interface of an ERC1155 compliant contract, as defined in the
       * https://eips.ethereum.org/EIPS/eip-1155[EIP].
       *
       * _Available since v3.1._
       */
      interface IERC1155 is IERC165 {
          /**
           * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
           */
          event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
          /**
           * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
           * transfers.
           */
          event TransferBatch(
              address indexed operator,
              address indexed from,
              address indexed to,
              uint256[] ids,
              uint256[] values
          );
          /**
           * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
           * `approved`.
           */
          event ApprovalForAll(address indexed account, address indexed operator, bool approved);
          /**
           * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
           *
           * If an {URI} event was emitted for `id`, the standard
           * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
           * returned by {IERC1155MetadataURI-uri}.
           */
          event URI(string value, uint256 indexed id);
          /**
           * @dev Returns the amount of tokens of token type `id` owned by `account`.
           *
           * Requirements:
           *
           * - `account` cannot be the zero address.
           */
          function balanceOf(address account, uint256 id) external view returns (uint256);
          /**
           * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
           *
           * Requirements:
           *
           * - `accounts` and `ids` must have the same length.
           */
          function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
              external
              view
              returns (uint256[] memory);
          /**
           * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
           *
           * Emits an {ApprovalForAll} event.
           *
           * Requirements:
           *
           * - `operator` cannot be the caller.
           */
          function setApprovalForAll(address operator, bool approved) external;
          /**
           * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
           *
           * See {setApprovalForAll}.
           */
          function isApprovedForAll(address account, address operator) external view returns (bool);
          /**
           * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
           *
           * Emits a {TransferSingle} event.
           *
           * Requirements:
           *
           * - `to` cannot be the zero address.
           * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
           * - `from` must have a balance of tokens of type `id` of at least `amount`.
           * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
           * acceptance magic value.
           */
          function safeTransferFrom(
              address from,
              address to,
              uint256 id,
              uint256 amount,
              bytes calldata data
          ) external;
          /**
           * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
           *
           * Emits a {TransferBatch} event.
           *
           * Requirements:
           *
           * - `ids` and `amounts` must have the same length.
           * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
           * acceptance magic value.
           */
          function safeBatchTransferFrom(
              address from,
              address to,
              uint256[] calldata ids,
              uint256[] calldata amounts,
              bytes calldata data
          ) external;
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import "../../utils/introspection/IERC165.sol";
      /**
       * @dev _Available since v3.1._
       */
      interface IERC1155Receiver is IERC165 {
          /**
              @dev Handles the receipt of a single ERC1155 token type. This function is
              called at the end of a `safeTransferFrom` after the balance has been updated.
              To accept the transfer, this must return
              `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
              (i.e. 0xf23a6e61, or its own function selector).
              @param operator The address which initiated the transfer (i.e. msg.sender)
              @param from The address which previously owned the token
              @param id The ID of the token being transferred
              @param value The amount of tokens being transferred
              @param data Additional data with no specified format
              @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
          */
          function onERC1155Received(
              address operator,
              address from,
              uint256 id,
              uint256 value,
              bytes calldata data
          ) external returns (bytes4);
          /**
              @dev Handles the receipt of a multiple ERC1155 token types. This function
              is called at the end of a `safeBatchTransferFrom` after the balances have
              been updated. To accept the transfer(s), this must return
              `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
              (i.e. 0xbc197c81, or its own function selector).
              @param operator The address which initiated the batch transfer (i.e. msg.sender)
              @param from The address which previously owned the token
              @param ids An array containing ids of each token being transferred (order and length must match values array)
              @param values An array containing amounts of each token being transferred (order and length must match ids array)
              @param data Additional data with no specified format
              @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
          */
          function onERC1155BatchReceived(
              address operator,
              address from,
              uint256[] calldata ids,
              uint256[] calldata values,
              bytes calldata data
          ) external returns (bytes4);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import "../IERC1155.sol";
      /**
       * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
       * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
       *
       * _Available since v3.1._
       */
      interface IERC1155MetadataURI is IERC1155 {
          /**
           * @dev Returns the URI for token type `id`.
           *
           * If the `\\{id\\}` substring is present in the URI, it must be replaced by
           * clients with the actual token type ID.
           */
          function uri(uint256 id) external view returns (string memory);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @dev Collection of functions related to the address type
       */
      library Address {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * [IMPORTANT]
           * ====
           * It is unsafe to assume that an address for which this function returns
           * false is an externally-owned account (EOA) and not a contract.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           * ====
           */
          function isContract(address account) internal view returns (bool) {
              // This method relies on extcodesize, which returns 0 for contracts in
              // construction, since the code is only stored at the end of the
              // constructor execution.
              uint256 size;
              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");
              (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");
              (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");
              (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");
              (bool success, bytes memory returndata) = target.delegatecall(data);
              return verifyCallResult(success, returndata, errorMessage);
          }
          /**
           * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
           * revert reason using the provided one.
           *
           * _Available since v4.3._
           */
          function verifyCallResult(
              bool success,
              bytes memory returndata,
              string memory errorMessage
          ) internal 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
                      assembly {
                          let returndata_size := mload(returndata)
                          revert(add(32, returndata), returndata_size)
                      }
                  } else {
                      revert(errorMessage);
                  }
              }
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @dev Provides information about the current execution context, including the
       * sender of the transaction and its data. While these are generally available
       * via msg.sender and msg.data, they should not be accessed in such a direct
       * manner, since when dealing with meta-transactions the account sending and
       * paying for execution may not be the actual sender (as far as an application
       * is concerned).
       *
       * This contract is only required for intermediate, library-like contracts.
       */
      abstract contract Context {
          function _msgSender() internal view virtual returns (address) {
              return msg.sender;
          }
          function _msgData() internal view virtual returns (bytes calldata) {
              return msg.data;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import "./IERC165.sol";
      /**
       * @dev Implementation of the {IERC165} interface.
       *
       * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
       * for the additional interface id that will be supported. For example:
       *
       * ```solidity
       * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
       *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
       * }
       * ```
       *
       * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
       */
      abstract contract ERC165 is IERC165 {
          /**
           * @dev See {IERC165-supportsInterface}.
           */
          function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
              return interfaceId == type(IERC165).interfaceId;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @dev Interface of the ERC165 standard, as defined in the
       * https://eips.ethereum.org/EIPS/eip-165[EIP].
       *
       * Implementers can declare support of contract interfaces, which can then be
       * queried by others ({ERC165Checker}).
       *
       * For an implementation, see {ERC165}.
       */
      interface IERC165 {
          /**
           * @dev Returns true if this contract implements the interface defined by
           * `interfaceId`. See the corresponding
           * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
           * to learn more about how these ids are created.
           *
           * This function call must use less than 30 000 gas.
           */
          function supportsInterface(bytes4 interfaceId) external view returns (bool);
      }