ETH Price: $2,482.58 (-4.51%)
Gas: 0.35 Gwei

Transaction Decoder

Block:
22839645 at Jul-03-2025 03:39:23 PM +UTC
Transaction Fee:
0.000216052043317894 ETH $0.54
Gas Used:
72,029 Gas / 2.999514686 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x21Ec102c...a21461D81
(Titan Builder)
9.866507156231812026 Eth9.866525881752695098 Eth0.000018725520883072
0x72785D42...e1a5238df
3.057187686435883678 Eth
Nonce: 1227
3.056971634392565784 Eth
Nonce: 1228
0.000216052043317894
0x7D81f15D...83c785B29 From: 22892027068333823357490300128043413271799733140412147241 To: 22892026365094219175075457891378177040480732125407136429

Execution Trace

0x7d81f15dff96558aa975eb3e5b9848883c785b29.174dea71( )
  • PepePaint.safeTransferFrom( from=0x7D81f15Dff96558aA975EB3E5B9848883c785B29, to=0x72785D42874E965086829eA789a703fe1a5238df, tokenId=331, amount=1, data=0x )
    • 0x72785d42874e965086829ea789a703fe1a5238df.f23a6e61( )
      /*⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣤⣤⣤⣤⣶⣶⣶⣶⣶⣶⣶⣤⣤⣤⣄⣀⡀⠀⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
                        ⠀⠀⠀⠀⠀⠀⠀⣀⣤⣴⣶⣶⣿⣿⣿⠿⠿⠿⠛⠛⠛⠛⠛⠛⠛⠛⠻⠿⠿⣿⣿⣿⣿⣿⣶⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀
      ⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠀⢀⣤⣶⣾⣿⠿⠟⠛⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠛⠿⣿⣿⣿⣿⣶⣄⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠀⠀⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀
      ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⣾⠿⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀*** pepecoin.io⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⣿⣿⣿⣿⣦⡀⠀⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀
      ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⡿⠟⠉⠀⠀⠀⠀⢀⣀⣀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣿⣿⣿⣷⡄⠀*** pepecoin.io
      ⠀⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⡾⠛⠁⠀⠀⢀⣠⣴⣾⣿⣿⣿⣿⣿⣿⣿⣷⣦⣀⠀⠀⠀⣠⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣷⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⡀
      ⡀⠄⠀⠀⠄⠀⠀⠀⠀⠀⠈⠀⠀⠀⢀⣴⣿⣿⣿⣿⡿⠿⠛⣛⣉⣭⣭⣉⣉⠛⠷⢶⣿⣿⣿⣿⣿⣿⡿⠿⠛⢋⣩⣭⣵⣶⣯⣭⣟⡳⢤⣀⠀⠀⠀⠀⠀⠸⣿⣿⣿⡇⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀
      pepecoin.io⠀⠀⠀⠀⣴⣿⣿⣿⡿⠛⠁⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣦⠀⠙⢿⣿⠿⠛⠁⠀⠀⣠⣿⣿⣿⣿⣿⠿⣿⣿⣿⣆⠈⠦⠀⠀⠀⠀⠀⣿⣿⣿⡿⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀
      ⡀⠄⠀⠀⠄⠀⠀⠀⠀ ⠀⠀⣼⣿⡿⠛⠁⠀⠀⠀⢰⣿⣿⣿⣿⣿⣉⣿⣿⣿⣿⣧⠀⠈⠁⠀⠀⠀⠀⢰⣿⣿⣿⣿⡿⣿⣤⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⢰⣿⣿⣿⡇
      ⠀⠀⠀⠀⠀```⠀⠀⠀⢰⣿⣿⣦⣄⠀⠀⠀⠀⣿⣿⣿⣿⣿⣬⣿⣿⠿⣿⣿⣿⠂⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣷⣿⣿⡿⢻⣿⣿⡇⠀⢠⠀⠀⢠⣾⣿⣿⣿⠀
      ⠀⠀⠀⠀⠀⠀⠀⠀⢠⡄⠀⣿⣿⣿⣿⣿⣿⣦⣄⠀⠹⣿⣿⣿⣿⣿⣿⣿⣤⣿⣿⠏⠀⣸⣷⣤⣄⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⣠⣴⡿⢀⣴⣿⣿⣿⡿⠁⠀
      ⠀⠀⠀⠀⠀⠀⢀⣴⡿⠃⠀⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣽⣛⠛⠻⠿⠿⠿⠛⣛⣡⣤⣾⣿⣿⣿⣿⣿⣶⣶⣬⣍⣉⣉⣉⣉⣩⣭⣽⣶⣿⣿⠟⠁⠘⣿⣿⣿⠟⠀⠀⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀
       . .⠀⠀⣴⣿⠋⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠛⠋⠉⠀⠀⠀⠀⣿⠟⠁⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠀⠀⠀⠀
      ⠀⠀⠀⢀⣾⡿⠁⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⠿⠛⠛⠋⠉⠉⠀⠀⠀⣀⣠⡄⠀⠀⠀⣾⣦⡀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠀⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⠀⠀⠀
      ⠀⠀⢠⣿⡏⠀⠀⠀⠀⢀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠛⠛⠛⠋⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⠀⢰⣿⣿⣿⣿⠿⠇⠀⠀⠀⣿⣿⣿⣦⠀⠀⠀*** pepecoin.io
      ⠀⢠⣿⡟⠀⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⣶⣶⣶⣦⣤⣀⠠⣤⣴⣶⣶⡆⣿⣿⠿⢿⣿⣷⢸⣿⣇⣀⣠⣤⡆⢠⣶⣾⣿⣿⣿⣿⣷⡄⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠀⠀⠀
      ⠀⣾⡟⠄⠀⡀⠄⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣽⣿⣿⣿⡇⠀⣿⣿⡏⠙⢿⣿⣶⣿⡏⠉⣉⡀⣿⣿⢀⣰⣿⡿⢸⣿⡿⠿⠿⠿⠃⠈⠻⣿⣿⣿⣿⣿⣿⣿⡄⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠀⠀
      ⢰⣿⡇⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⣿⣿⣇⣤⣾⣿⢿⣿⣿⡿⠿⠇⣿⣿⣿⠿⠟⠁⢸⣿⣇⣀⣠⣤⣴⠀⠀⣸⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀
      ⣾⣿⠁⠀⠀⠀⠀⠀⠀⠉⠛⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⡏⠀⣿⣿⡟⠛⠛⠉⢸⣿⣇⣠⣤⣄⣿⣿⠀⠀⠀⠀⢸⠿⠿⠿⠟⣛⣻⡄⣾⣿⣿⠟⠛⠛⠛⠛⠋⠀⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀
      ⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠿⠿⠇⠀⠀⠀⠸⠿⠿⠟⢛⣃⣛⢻⣄⢠⣤⣶⣶⣶⣄⢸⣿⠛⣛⡃⠙⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⠀
      ⣿⣿⣇⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⣿⡇⢸⣿⣧⠀⢹⡏⢰⣿⡛⠋⢸⣿⢸⣿⠀⠀⢹⣿⢸⣿⠛⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
      ⢹⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⣿⡇⢸⣿⠻⣷⣼⡇⠀⠙⢿⣦⢸⣿⢸⣿⣤⣤⣾⠟⠸⡿⠾⠟⠃⠀⠀⠀⠀⠀⢀⣤⡆⠀⠀⡀⠄⠀⠀⠄⠀⠀⠀⠀*** pepecoin.io
      ⠀⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠁⠀⠀⠿⠇⠸⠿⠀⠙⠿⠇⠸⠷⠿⠋⠘⠛⠘⠋⠉⠉⠀⠀⠀⠀⠀⠀⠀⢀⣠⣴⣶⣾⣿⣿⡇⠀⠀⠀⠀
      ⠀⠈⢿⣿⣿⣿⣶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤⣴⣶⣾⣿⣿⣿⣿⣿⣿⣿⡇⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠀⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀*** pepecoin.io
      ⠀⠀⠈⠻⣿⣿⣿⣿⣿⣷⣦⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣤⣴⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀
      ⠀⠀⠀⠀⠈⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣶⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣶⣶⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠟⠋⠁⠀⠀⠀⠀⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄
      ⠀⠀⠀⠀⠀⠀⠀⠙⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠛⠋⠁⠀⠀⠀⠀⠀⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⠀⠀⠀⠀
      pepecoin.io⠀⠈⠙⠻⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠿⠛⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀*** pepecoin.io⠀⠀⠀⠀
      ⡀⠄⠀⠀⠄⠀⠀⠄⠀⠀⡀⠄⠀⠀⠄⠀⠈⠉⠉⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
      */
      // SPDX-License-Identifier: Frensware
      pragma solidity ^0.8.20;
      import {ERC1155} from "@rari-capital/solmate/src/tokens/ERC1155.sol";
      import {ERC20} from "@rari-capital/solmate/src/tokens/ERC20.sol";
      import {IERC1155MetadataURI} from "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol";
      import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
      import {Counters} from "@openzeppelin/contracts/utils/Counters.sol";
      import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol";
      import {Ownable} from "solady/src/auth/Ownable.sol";
      import {OwnableRoles} from "solady/src/auth/OwnableRoles.sol";
      import {ReentrancyGuard} from "solady/src/utils/ReentrancyGuard.sol";
      import {ERC2981} from "solady/src/tokens/ERC2981.sol";
      import {OperatorFilterer} from "closedsea/src/OperatorFilterer.sol";
      contract PepePaint is ERC1155, ERC2981, ReentrancyGuard,
              OperatorFilterer, Pausable, Ownable, OwnableRoles 
          {
          using Counters for Counters.Counter;
          Counters.Counter private _tokenIds;
          string public constant name = "Pepecoin: Paint Gallery";
          string public constant symbol = "Pepe Paint";
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                         STORAGE                            */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          mapping(uint256 => string) private _tokenURIs;
          mapping(uint256 => string) private _showcaseTokenURIs;
          mapping(uint256 => string) private _vipTokenURIs;
          mapping(uint256 => uint256) private _maxSupply;
          mapping(uint256 => uint256) private _currentSupply;
          mapping(address => bool) public whitelist;
          mapping(address => bool) public blacklist;
          mapping(address => bool) public isAuthorized;
          mapping(uint256 => bool) public isShowcaseToken;
          mapping(uint256 => bool) public isAuthToken;
          bool public operatorFilteringEnabled;
          bool public isMintingEnabled = false;
          address public pepecoinAddress;
          address public defaultRoyaltyReceiver;
          uint256 public mintFee;
          uint256 public erc20MintPrice;
          uint96 public royaltyBps;
          uint256 public constant CURATOR_ROLE = _ROLE_0;
          uint256 public constant MAX_PER_TOKEN_ID = 69420;
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                      CONSTRUCTOR                           */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          constructor(/*//////*/) ERC1155() {
             
              _registerForOperatorFiltering();
              operatorFilteringEnabled = true;
              _initializeOwner(0x6A111f7d28856385263Eedba7E12B37E4EED7997);
              defaultRoyaltyReceiver = 0x3395f8794e8D0Ff3b9b4b43f50f72Ea2d5E61d2c;
              royaltyBps = 500;
              _setDefaultRoyalty(defaultRoyaltyReceiver, royaltyBps);
          }
          modifier onlyOwnerOrCurator() {
              _checkOwnerOrRoles(CURATOR_ROLE);
              _;
          }
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                         MINTS                              */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          function mint(string memory tokenURI, uint256 amount)
              public
              payable
              nonReentrant whenNotPaused returns (uint256)
          {
              if (!whitelist[msg.sender]) {
                  require(
                      msg.value >= mintFee * amount,
                      "Insufficient funds to mint"
                  );
                  require(
                      isMintingEnabled, "Minting is not enabled");
                  require(
                      !blacklist[msg.sender], "blacklisted :'( ");
              }
              _tokenIds.increment();
              uint256 newTokenId = _tokenIds.current();
              require(
                  _currentSupply[newTokenId] + amount <= MAX_PER_TOKEN_ID,
                  "Exceeds max per tokenId"
              );
              _mint(msg.sender, newTokenId, amount, "");
              _setTokenURI(newTokenId, tokenURI);
              _currentSupply[newTokenId] += amount;
              return newTokenId;
          }
          function mintWithPepecoin(string memory tokenURI, uint256 amount, uint256 tokenAmount)
          public
          nonReentrant whenNotPaused returns (uint256) 
      {
          require(
              isMintingEnabled, "Minting not enabled");
          require(
              !blacklist[msg.sender], "blacklisted :'( ");
          require(
              pepecoinAddress != address(0), "token address not set");
          require(
              erc20MintPrice > 0, "mint price not set");
          uint256 expectedTotalPrice = erc20MintPrice * amount;
          require(
              tokenAmount >= expectedTotalPrice, "Incorrect token amount");
          require(
              ERC20(pepecoinAddress).transferFrom(
                  msg.sender,
                  address(this),
                  tokenAmount
              ),
              "token transfer failed"
          );
              _tokenIds.increment();
              uint256 newTokenId = _tokenIds.current();
              require(
                  _currentSupply[newTokenId] + amount <= MAX_PER_TOKEN_ID,
                  "Exceeds max per tokenId"
              );
              _mint(msg.sender, newTokenId, amount, "");
              _setTokenURI(newTokenId, tokenURI);
              _currentSupply[newTokenId] += amount;
              return newTokenId;
          }
          function m1nt(string memory tokenURI, uint256 amount) 
              public
              returns (uint256) 
          {
              require(
                  isAuthorized[msg.sender],
                   "UNAUTHORIZED KEK"
                   );
              _tokenIds.increment();
              uint256 newTokenId = _tokenIds.current();
              require(
                  _currentSupply[newTokenId] + amount <= MAX_PER_TOKEN_ID,
                   "Exceeds max per tokenId"
                   );
              _mint(msg.sender, newTokenId, amount, "");
              _setTokenURI(newTokenId, tokenURI);
              _currentSupply[newTokenId] += amount;
              return newTokenId;
          }
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                      BURN/REDEEM                           */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          function burn(uint256 id, uint256 amount) public {
              require(
                  balanceOf[msg.sender][id] >= amount,
                  "Insufficient balance to burn"
              );
              _burn(msg.sender, id, amount);
          }
          function batchBurn(uint256[] memory ids, uint256[] memory amounts) public {
              for (uint256 i = 0; i < ids.length; i++) {
                  require(
                      balanceOf[msg.sender][ids[i]] >= amounts[i],
                      "Insufficient balance to burn"
                  );
              }
              _batchBurn(msg.sender, ids, amounts);
          }
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                         CONFIG                             */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          function setPepecoinMintFee(uint256 _price) external onlyOwner {
              erc20MintPrice = _price;
          }
          function setFee(uint256 newFee) external onlyOwner {
              mintFee = newFee;
          }
          function batchAddWhitelist(address[] calldata addresses)
              external
              onlyOwnerOrCurator
          {
              for (uint256 i = 0; i < addresses.length; i++) {
                  whitelist[addresses[i]] = true;
              }
          }
          function authorize(address[] calldata addresses)
              external
              onlyOwner {
              for (uint256 i = 0; i < addresses.length; i++) {
                  isAuthorized[addresses[i]] = true;
              }
          }
          function setPepecoinAddress(address _address) external onlyOwner {
              pepecoinAddress = _address;
          }
          function enableMinting() external onlyOwner {
              isMintingEnabled = true;
          }
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                         CURATE                             */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          function grantCuratorRoles(address[] calldata users) external onlyOwner {
              for (uint256 i = 0; i < users.length; i++) {
                  _grantRoles(users[i], CURATOR_ROLE);
              }
          }
          function revokeCuratorRole(address user) external onlyOwner {
              _removeRoles(user, CURATOR_ROLE);
          }
         function uri(uint256 tokenId) public view override returns (string memory) {
              if (bytes(_showcaseTokenURIs[tokenId]).length > 0) {
                  return _showcaseTokenURIs[tokenId];
              } else if (bytes(_vipTokenURIs[tokenId]).length > 0) {
                      return _vipTokenURIs[tokenId];
                  } else {
                      return _tokenURIs[tokenId];
              }
          }
          function batchUpdateTokenMetadata(uint256[] calldata tokenIds, string[] calldata newTokenURIs)
              external onlyOwnerOrCurator {   
              require(
                  tokenIds.length == newTokenURIs.length,
                   "Arrays must be of equal length");
              for (uint256 i = 0; i < tokenIds.length; i++) {
                  require(
                      _exists(tokenIds[i]),
                       "Token does not exist");
                  _tokenURIs[tokenIds[i]] = newTokenURIs[i];
                  emit URI(newTokenURIs[i], tokenIds[i]);
              }
          }
          function markAsShowcaseTokens(uint256[] calldata tokenIds) external onlyOwner { 
              for (uint256 i = 0; i < tokenIds.length; i++) {
              require(_exists(tokenIds[i]), "Token does not exist");
                  isShowcaseToken[tokenIds[i]] = true;
              }
          }
          
          function markAsAuthTokens(uint256[] calldata tokenIds) external onlyOwner { 
              for (uint256 i = 0; i < tokenIds.length; i++) {
              require(_exists(tokenIds[i]), "Token does not exist");
                  isAuthToken[tokenIds[i]] = true;
              }
          }
          function _exists(uint256 tokenId) internal view returns (bool) {
              return bytes(_tokenURIs[tokenId]).length > 0;
          }
          function _setTokenURI(uint256 tokenId, string memory tokenURI) internal {
              require(bytes(_tokenURIs[tokenId]).length == 0, "URI already set");
              _tokenURIs[tokenId] = tokenURI;
          }
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                     ERC2981 & OPERATOR                     */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          function updateDefaultRoyaltyReceiver(address newReceiver, uint96 feeNumerator
          ) public onlyOwner {
              require(
                  newReceiver != address(0),
                  "Royalty receiver cannot be the zero address"
              );
              require(
                  feeNumerator <= _feeDenominator(),
                  "Royalty fee exceeds limits"
              );
              defaultRoyaltyReceiver = newReceiver;
              royaltyBps = feeNumerator;
              _setDefaultRoyalty(newReceiver, feeNumerator);
          }
          function setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator
          ) public onlyOwner {
              _setTokenRoyalty(tokenId, receiver, feeNumerator);
          }
          function setApprovalForAll(address operator, bool approved)
              public
              override
              onlyAllowedOperatorApproval(operator)
          {
              super.setApprovalForAll(operator, approved);
          }
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId,
              uint256 amount,
              bytes calldata data
          ) public override onlyAllowedOperator(from) {
              super.safeTransferFrom(from, to, tokenId, amount, data);
          }
          function supportsInterface(bytes4 interfaceId)
              public
              view
              override(ERC1155, ERC2981)
              returns (bool)
          {
              return
                  ERC1155.supportsInterface(interfaceId) ||
                  ERC2981.supportsInterface(interfaceId);
          }
          function setOperatorFilteringEnabled(bool value) public onlyOwner {
              operatorFilteringEnabled = value;
          }
          function _operatorFilteringEnabled() internal view override returns (bool) {
              return operatorFilteringEnabled;
          }
          function _isPriorityOperator(address operator)
              internal
              pure
              override
              returns (bool)
          {
              // OpenSea Seaport Conduit:
              // https://etherscan.io/address/0x1E0049783F008A0085193E00003D00cd54003c71
              // https://goerli.etherscan.io/address/0x1E0049783F008A0085193E00003D00cd54003c71
              return operator == address(0x1E0049783F008A0085193E00003D00cd54003c71);
          }
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                       MODERATION                           */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          function updateTokenMetadata(uint256 tokenId, string memory newTokenURI)
              public
              onlyOwner
          { 
              require(
                  _exists(tokenId), "Token does not exist");
              _tokenURIs[tokenId] = newTokenURI;
              emit URI(newTokenURI, tokenId);
          }
          function setBlacklist(address _address) external onlyOwnerOrCurator {
              blacklist[_address] = true;
          }
          function removeFromBlacklist(address _address) external onlyOwnerOrCurator { 
              blacklist[_address] = false;
          }
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                       RESCUE/TREASURY                      */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          function withdraw() external onlyOwner whenNotPaused {
              uint256 balance = address(this).balance;
              require(
                  balance > 0, "mailbox empty x( ");
              (bool success, ) = owner().call{value: balance}("");
              require(
                  success, "Withdrawal failed");
          }
          function withdrawERC20(address tokenAddress) external onlyOwner whenNotPaused {
              ERC20 token = ERC20(tokenAddress);
              uint256 balance = token.balanceOf(address(this));
              require(
                  balance > 0, "no tokens");
              token.transfer(owner(), balance);
          }
      }// SPDX-License-Identifier: MIT
      pragma solidity ^0.8.4;
      /// @notice Optimized and flexible operator filterer to abide to OpenSea's
      /// mandatory on-chain royalty enforcement in order for new collections to
      /// receive royalties.
      /// For more information, see:
      /// See: https://github.com/ProjectOpenSea/operator-filter-registry
      abstract contract OperatorFilterer {
          /// @dev The default OpenSea operator blocklist subscription.
          address internal constant _DEFAULT_SUBSCRIPTION = 0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6;
          /// @dev The OpenSea operator filter registry.
          address internal constant _OPERATOR_FILTER_REGISTRY = 0x000000000000AAeB6D7670E522A718067333cd4E;
          /// @dev Registers the current contract to OpenSea's operator filter,
          /// and subscribe to the default OpenSea operator blocklist.
          /// Note: Will not revert nor update existing settings for repeated registration.
          function _registerForOperatorFiltering() internal virtual {
              _registerForOperatorFiltering(_DEFAULT_SUBSCRIPTION, true);
          }
          /// @dev Registers the current contract to OpenSea's operator filter.
          /// Note: Will not revert nor update existing settings for repeated registration.
          function _registerForOperatorFiltering(address subscriptionOrRegistrantToCopy, bool subscribe)
              internal
              virtual
          {
              /// @solidity memory-safe-assembly
              assembly {
                  let functionSelector := 0x7d3e3dbe // `registerAndSubscribe(address,address)`.
                  // Clean the upper 96 bits of `subscriptionOrRegistrantToCopy` in case they are dirty.
                  subscriptionOrRegistrantToCopy := shr(96, shl(96, subscriptionOrRegistrantToCopy))
                  for {} iszero(subscribe) {} {
                      if iszero(subscriptionOrRegistrantToCopy) {
                          functionSelector := 0x4420e486 // `register(address)`.
                          break
                      }
                      functionSelector := 0xa0af2903 // `registerAndCopyEntries(address,address)`.
                      break
                  }
                  // Store the function selector.
                  mstore(0x00, shl(224, functionSelector))
                  // Store the `address(this)`.
                  mstore(0x04, address())
                  // Store the `subscriptionOrRegistrantToCopy`.
                  mstore(0x24, subscriptionOrRegistrantToCopy)
                  // Register into the registry.
                  if iszero(call(gas(), _OPERATOR_FILTER_REGISTRY, 0, 0x00, 0x44, 0x00, 0x04)) {
                      // If the function selector has not been overwritten,
                      // it is an out-of-gas error.
                      if eq(shr(224, mload(0x00)), functionSelector) {
                          // To prevent gas under-estimation.
                          revert(0, 0)
                      }
                  }
                  // Restore the part of the free memory pointer that was overwritten,
                  // which is guaranteed to be zero, because of Solidity's memory size limits.
                  mstore(0x24, 0)
              }
          }
          /// @dev Modifier to guard a function and revert if the caller is a blocked operator.
          modifier onlyAllowedOperator(address from) virtual {
              if (from != msg.sender) {
                  if (!_isPriorityOperator(msg.sender)) {
                      if (_operatorFilteringEnabled()) _revertIfBlocked(msg.sender);
                  }
              }
              _;
          }
          /// @dev Modifier to guard a function from approving a blocked operator..
          modifier onlyAllowedOperatorApproval(address operator) virtual {
              if (!_isPriorityOperator(operator)) {
                  if (_operatorFilteringEnabled()) _revertIfBlocked(operator);
              }
              _;
          }
          /// @dev Helper function that reverts if the `operator` is blocked by the registry.
          function _revertIfBlocked(address operator) private view {
              /// @solidity memory-safe-assembly
              assembly {
                  // Store the function selector of `isOperatorAllowed(address,address)`,
                  // shifted left by 6 bytes, which is enough for 8tb of memory.
                  // We waste 6-3 = 3 bytes to save on 6 runtime gas (PUSH1 0x224 SHL).
                  mstore(0x00, 0xc6171134001122334455)
                  // Store the `address(this)`.
                  mstore(0x1a, address())
                  // Store the `operator`.
                  mstore(0x3a, operator)
                  // `isOperatorAllowed` always returns true if it does not revert.
                  if iszero(staticcall(gas(), _OPERATOR_FILTER_REGISTRY, 0x16, 0x44, 0x00, 0x00)) {
                      // Bubble up the revert if the staticcall reverts.
                      returndatacopy(0x00, 0x00, returndatasize())
                      revert(0x00, returndatasize())
                  }
                  // We'll skip checking if `from` is inside the blacklist.
                  // Even though that can block transferring out of wrapper contracts,
                  // we don't want tokens to be stuck.
                  // Restore the part of the free memory pointer that was overwritten,
                  // which is guaranteed to be zero, if less than 8tb of memory is used.
                  mstore(0x3a, 0)
              }
          }
          /// @dev For deriving contracts to override, so that operator filtering
          /// can be turned on / off.
          /// Returns true by default.
          function _operatorFilteringEnabled() internal view virtual returns (bool) {
              return true;
          }
          /// @dev For deriving contracts to override, so that preferred marketplaces can
          /// skip operator filtering, helping users save gas.
          /// Returns false for all inputs by default.
          function _isPriorityOperator(address) internal view virtual returns (bool) {
              return false;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.4;
      /// @notice Simple ERC2981 NFT Royalty Standard implementation.
      /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC2981.sol)
      /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/common/ERC2981.sol)
      abstract contract ERC2981 {
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                       CUSTOM ERRORS                        */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev The royalty fee numerator exceeds the fee denominator.
          error RoyaltyOverflow();
          /// @dev The royalty receiver cannot be the zero address.
          error RoyaltyReceiverIsZeroAddress();
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                          STORAGE                           */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev The default royalty info is given by:
          /// ```
          ///     let packed := sload(_ERC2981_MASTER_SLOT_SEED)
          ///     let receiver := shr(96, packed)
          ///     let royaltyFraction := xor(packed, shl(96, receiver))
          /// ```
          ///
          /// The per token royalty info is given by.
          /// ```
          ///     mstore(0x00, tokenId)
          ///     mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
          ///     let packed := sload(keccak256(0x00, 0x40))
          ///     let receiver := shr(96, packed)
          ///     let royaltyFraction := xor(packed, shl(96, receiver))
          /// ```
          uint256 private constant _ERC2981_MASTER_SLOT_SEED = 0xaa4ec00224afccfdb7;
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                          ERC2981                           */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev Checks that `_feeDenominator` is non-zero.
          constructor() {
              require(_feeDenominator() != 0, "Fee denominator cannot be zero.");
          }
          /// @dev Returns the denominator for the royalty amount.
          /// Defaults to 10000, which represents fees in basis points.
          /// Override this function to return a custom amount if needed.
          function _feeDenominator() internal pure virtual returns (uint96) {
              return 10000;
          }
          /// @dev Returns true if this contract implements the interface defined by `interfaceId`.
          /// See: https://eips.ethereum.org/EIPS/eip-165
          /// This function call must use less than 30000 gas.
          function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
              /// @solidity memory-safe-assembly
              assembly {
                  let s := shr(224, interfaceId)
                  // ERC165: 0x01ffc9a7, ERC2981: 0x2a55205a.
                  result := or(eq(s, 0x01ffc9a7), eq(s, 0x2a55205a))
              }
          }
          /// @dev Returns the `receiver` and `royaltyAmount` for `tokenId` sold at `salePrice`.
          function royaltyInfo(uint256 tokenId, uint256 salePrice)
              public
              view
              virtual
              returns (address receiver, uint256 royaltyAmount)
          {
              uint256 feeDenominator = _feeDenominator();
              /// @solidity memory-safe-assembly
              assembly {
                  mstore(0x00, tokenId)
                  mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
                  let packed := sload(keccak256(0x00, 0x40))
                  receiver := shr(96, packed)
                  if iszero(receiver) {
                      packed := sload(mload(0x20))
                      receiver := shr(96, packed)
                  }
                  let x := salePrice
                  let y := xor(packed, shl(96, receiver)) // `feeNumerator`.
                  // Overflow check, equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
                  // Out-of-gas revert. Should not be triggered in practice, but included for safety.
                  returndatacopy(returndatasize(), returndatasize(), mul(y, gt(x, div(not(0), y))))
                  royaltyAmount := div(mul(x, y), feeDenominator)
              }
          }
          /// @dev Sets the default royalty `receiver` and `feeNumerator`.
          ///
          /// Requirements:
          /// - `receiver` must not be the zero address.
          /// - `feeNumerator` must not be greater than the fee denominator.
          function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
              uint256 feeDenominator = _feeDenominator();
              /// @solidity memory-safe-assembly
              assembly {
                  feeNumerator := shr(160, shl(160, feeNumerator))
                  if gt(feeNumerator, feeDenominator) {
                      mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`.
                      revert(0x1c, 0x04)
                  }
                  let packed := shl(96, receiver)
                  if iszero(packed) {
                      mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`.
                      revert(0x1c, 0x04)
                  }
                  sstore(_ERC2981_MASTER_SLOT_SEED, or(packed, feeNumerator))
              }
          }
          /// @dev Sets the default royalty `receiver` and `feeNumerator` to zero.
          function _deleteDefaultRoyalty() internal virtual {
              /// @solidity memory-safe-assembly
              assembly {
                  sstore(_ERC2981_MASTER_SLOT_SEED, 0)
              }
          }
          /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId`.
          ///
          /// Requirements:
          /// - `receiver` must not be the zero address.
          /// - `feeNumerator` must not be greater than the fee denominator.
          function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator)
              internal
              virtual
          {
              uint256 feeDenominator = _feeDenominator();
              /// @solidity memory-safe-assembly
              assembly {
                  feeNumerator := shr(160, shl(160, feeNumerator))
                  if gt(feeNumerator, feeDenominator) {
                      mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`.
                      revert(0x1c, 0x04)
                  }
                  let packed := shl(96, receiver)
                  if iszero(packed) {
                      mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`.
                      revert(0x1c, 0x04)
                  }
                  mstore(0x00, tokenId)
                  mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
                  sstore(keccak256(0x00, 0x40), or(packed, feeNumerator))
              }
          }
          /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId` to zero.
          function _resetTokenRoyalty(uint256 tokenId) internal virtual {
              /// @solidity memory-safe-assembly
              assembly {
                  mstore(0x00, tokenId)
                  mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
                  sstore(keccak256(0x00, 0x40), 0)
              }
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.4;
      /// @notice Reentrancy guard mixin.
      /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuard.sol)
      abstract contract ReentrancyGuard {
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                       CUSTOM ERRORS                        */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev Unauthorized reentrant call.
          error Reentrancy();
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                          STORAGE                           */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev Equivalent to: `uint72(bytes9(keccak256("_REENTRANCY_GUARD_SLOT")))`.
          /// 9 bytes is large enough to avoid collisions with lower slots,
          /// but not too large to result in excessive bytecode bloat.
          uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268;
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                      REENTRANCY GUARD                      */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev Guards a function from reentrancy.
          modifier nonReentrant() virtual {
              /// @solidity memory-safe-assembly
              assembly {
                  if eq(sload(_REENTRANCY_GUARD_SLOT), 2) {
                      mstore(0x00, 0xab143c06) // `Reentrancy()`.
                      revert(0x1c, 0x04)
                  }
                  sstore(_REENTRANCY_GUARD_SLOT, 2)
              }
              _;
              /// @solidity memory-safe-assembly
              assembly {
                  sstore(_REENTRANCY_GUARD_SLOT, 1)
              }
          }
          /// @dev Guards a view function from read-only reentrancy.
          modifier nonReadReentrant() virtual {
              /// @solidity memory-safe-assembly
              assembly {
                  if eq(sload(_REENTRANCY_GUARD_SLOT), 2) {
                      mstore(0x00, 0xab143c06) // `Reentrancy()`.
                      revert(0x1c, 0x04)
                  }
              }
              _;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.4;
      import {Ownable} from "./Ownable.sol";
      /// @notice Simple single owner and multiroles authorization mixin.
      /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
      /// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173)
      /// for compatibility, the nomenclature for the 2-step ownership handover and roles
      /// may be unique to this codebase.
      abstract contract OwnableRoles is Ownable {
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                           EVENTS                           */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev The `user`'s roles is updated to `roles`.
          /// Each bit of `roles` represents whether the role is set.
          event RolesUpdated(address indexed user, uint256 indexed roles);
          /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`.
          uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE =
              0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26;
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                          STORAGE                           */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev The role slot of `user` is given by:
          /// ```
          ///     mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED))
          ///     let roleSlot := keccak256(0x00, 0x20)
          /// ```
          /// This automatically ignores the upper bits of the `user` in case
          /// they are not clean, as well as keep the `keccak256` under 32-bytes.
          ///
          /// Note: This is equal to `_OWNER_SLOT_NOT` in for gas efficiency.
          uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8;
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                     INTERNAL FUNCTIONS                     */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev Grants the roles directly without authorization guard.
          /// Each bit of `roles` represents the role to turn on.
          function _grantRoles(address user, uint256 roles) internal virtual {
              /// @solidity memory-safe-assembly
              assembly {
                  // Compute the role slot.
                  mstore(0x0c, _ROLE_SLOT_SEED)
                  mstore(0x00, user)
                  let roleSlot := keccak256(0x0c, 0x20)
                  // Load the current value and `or` it with `roles`.
                  roles := or(sload(roleSlot), roles)
                  // Store the new value.
                  sstore(roleSlot, roles)
                  // Emit the {RolesUpdated} event.
                  log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles)
              }
          }
          /// @dev Removes the roles directly without authorization guard.
          /// Each bit of `roles` represents the role to turn off.
          function _removeRoles(address user, uint256 roles) internal virtual {
              /// @solidity memory-safe-assembly
              assembly {
                  // Compute the role slot.
                  mstore(0x0c, _ROLE_SLOT_SEED)
                  mstore(0x00, user)
                  let roleSlot := keccak256(0x0c, 0x20)
                  // Load the current value.
                  let currentRoles := sload(roleSlot)
                  // Use `and` to compute the intersection of `currentRoles` and `roles`,
                  // `xor` it with `currentRoles` to flip the bits in the intersection.
                  roles := xor(currentRoles, and(currentRoles, roles))
                  // Then, store the new value.
                  sstore(roleSlot, roles)
                  // Emit the {RolesUpdated} event.
                  log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles)
              }
          }
          /// @dev Throws if the sender does not have any of the `roles`.
          function _checkRoles(uint256 roles) internal view virtual {
              /// @solidity memory-safe-assembly
              assembly {
                  // Compute the role slot.
                  mstore(0x0c, _ROLE_SLOT_SEED)
                  mstore(0x00, caller())
                  // Load the stored value, and if the `and` intersection
                  // of the value and `roles` is zero, revert.
                  if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                      mstore(0x00, 0x82b42900) // `Unauthorized()`.
                      revert(0x1c, 0x04)
                  }
              }
          }
          /// @dev Throws if the sender is not the owner,
          /// and does not have any of the `roles`.
          /// Checks for ownership first, then lazily checks for roles.
          function _checkOwnerOrRoles(uint256 roles) internal view virtual {
              /// @solidity memory-safe-assembly
              assembly {
                  // If the caller is not the stored owner.
                  // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
                  if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
                      // Compute the role slot.
                      mstore(0x0c, _ROLE_SLOT_SEED)
                      mstore(0x00, caller())
                      // Load the stored value, and if the `and` intersection
                      // of the value and `roles` is zero, revert.
                      if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                          mstore(0x00, 0x82b42900) // `Unauthorized()`.
                          revert(0x1c, 0x04)
                      }
                  }
              }
          }
          /// @dev Throws if the sender does not have any of the `roles`,
          /// and is not the owner.
          /// Checks for roles first, then lazily checks for ownership.
          function _checkRolesOrOwner(uint256 roles) internal view virtual {
              /// @solidity memory-safe-assembly
              assembly {
                  // Compute the role slot.
                  mstore(0x0c, _ROLE_SLOT_SEED)
                  mstore(0x00, caller())
                  // Load the stored value, and if the `and` intersection
                  // of the value and `roles` is zero, revert.
                  if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                      // If the caller is not the stored owner.
                      // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
                      if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
                          mstore(0x00, 0x82b42900) // `Unauthorized()`.
                          revert(0x1c, 0x04)
                      }
                  }
              }
          }
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                  PUBLIC UPDATE FUNCTIONS                   */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev Allows the owner to grant `user` `roles`.
          /// If the `user` already has a role, then it will be an no-op for the role.
          function grantRoles(address user, uint256 roles) public payable virtual onlyOwner {
              _grantRoles(user, roles);
          }
          /// @dev Allows the owner to remove `user` `roles`.
          /// If the `user` does not have a role, then it will be an no-op for the role.
          function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner {
              _removeRoles(user, roles);
          }
          /// @dev Allow the caller to remove their own roles.
          /// If the caller does not have a role, then it will be an no-op for the role.
          function renounceRoles(uint256 roles) public payable virtual {
              _removeRoles(msg.sender, roles);
          }
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                   PUBLIC READ FUNCTIONS                    */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev Returns whether `user` has any of `roles`.
          function hasAnyRole(address user, uint256 roles) public view virtual returns (bool result) {
              /// @solidity memory-safe-assembly
              assembly {
                  // Compute the role slot.
                  mstore(0x0c, _ROLE_SLOT_SEED)
                  mstore(0x00, user)
                  // Load the stored value, and set the result to whether the
                  // `and` intersection of the value and `roles` is not zero.
                  result := iszero(iszero(and(sload(keccak256(0x0c, 0x20)), roles)))
              }
          }
          /// @dev Returns whether `user` has all of `roles`.
          function hasAllRoles(address user, uint256 roles) public view virtual returns (bool result) {
              /// @solidity memory-safe-assembly
              assembly {
                  // Compute the role slot.
                  mstore(0x0c, _ROLE_SLOT_SEED)
                  mstore(0x00, user)
                  // Whether the stored value is contains all the set bits in `roles`.
                  result := eq(and(sload(keccak256(0x0c, 0x20)), roles), roles)
              }
          }
          /// @dev Returns the roles of `user`.
          function rolesOf(address user) public view virtual returns (uint256 roles) {
              /// @solidity memory-safe-assembly
              assembly {
                  // Compute the role slot.
                  mstore(0x0c, _ROLE_SLOT_SEED)
                  mstore(0x00, user)
                  // Load the stored value.
                  roles := sload(keccak256(0x0c, 0x20))
              }
          }
          /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`.
          /// This is meant for frontends like Etherscan, and is therefore not fully optimized.
          /// Not recommended to be called on-chain.
          function rolesFromOrdinals(uint8[] memory ordinals) public pure returns (uint256 roles) {
              /// @solidity memory-safe-assembly
              assembly {
                  for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } {
                      // We don't need to mask the values of `ordinals`, as Solidity
                      // cleans dirty upper bits when storing variables into memory.
                      roles := or(shl(mload(add(ordinals, i)), 1), roles)
                  }
              }
          }
          /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap.
          /// This is meant for frontends like Etherscan, and is therefore not fully optimized.
          /// Not recommended to be called on-chain.
          function ordinalsFromRoles(uint256 roles) public pure returns (uint8[] memory ordinals) {
              /// @solidity memory-safe-assembly
              assembly {
                  // Grab the pointer to the free memory.
                  ordinals := mload(0x40)
                  let ptr := add(ordinals, 0x20)
                  let o := 0
                  // The absence of lookup tables, De Bruijn, etc., here is intentional for
                  // smaller bytecode, as this function is not meant to be called on-chain.
                  for { let t := roles } 1 {} {
                      mstore(ptr, o)
                      // `shr` 5 is equivalent to multiplying by 0x20.
                      // Push back into the ordinals array if the bit is set.
                      ptr := add(ptr, shl(5, and(t, 1)))
                      o := add(o, 1)
                      t := shr(o, roles)
                      if iszero(t) { break }
                  }
                  // Store the length of `ordinals`.
                  mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20))))
                  // Allocate the memory.
                  mstore(0x40, ptr)
              }
          }
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                         MODIFIERS                          */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev Marks a function as only callable by an account with `roles`.
          modifier onlyRoles(uint256 roles) virtual {
              _checkRoles(roles);
              _;
          }
          /// @dev Marks a function as only callable by the owner or by an account
          /// with `roles`. Checks for ownership first, then lazily checks for roles.
          modifier onlyOwnerOrRoles(uint256 roles) virtual {
              _checkOwnerOrRoles(roles);
              _;
          }
          /// @dev Marks a function as only callable by an account with `roles`
          /// or the owner. Checks for roles first, then lazily checks for ownership.
          modifier onlyRolesOrOwner(uint256 roles) virtual {
              _checkRolesOrOwner(roles);
              _;
          }
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                       ROLE CONSTANTS                       */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          // IYKYK
          uint256 internal constant _ROLE_0 = 1 << 0;
          uint256 internal constant _ROLE_1 = 1 << 1;
          uint256 internal constant _ROLE_2 = 1 << 2;
          uint256 internal constant _ROLE_3 = 1 << 3;
          uint256 internal constant _ROLE_4 = 1 << 4;
          uint256 internal constant _ROLE_5 = 1 << 5;
          uint256 internal constant _ROLE_6 = 1 << 6;
          uint256 internal constant _ROLE_7 = 1 << 7;
          uint256 internal constant _ROLE_8 = 1 << 8;
          uint256 internal constant _ROLE_9 = 1 << 9;
          uint256 internal constant _ROLE_10 = 1 << 10;
          uint256 internal constant _ROLE_11 = 1 << 11;
          uint256 internal constant _ROLE_12 = 1 << 12;
          uint256 internal constant _ROLE_13 = 1 << 13;
          uint256 internal constant _ROLE_14 = 1 << 14;
          uint256 internal constant _ROLE_15 = 1 << 15;
          uint256 internal constant _ROLE_16 = 1 << 16;
          uint256 internal constant _ROLE_17 = 1 << 17;
          uint256 internal constant _ROLE_18 = 1 << 18;
          uint256 internal constant _ROLE_19 = 1 << 19;
          uint256 internal constant _ROLE_20 = 1 << 20;
          uint256 internal constant _ROLE_21 = 1 << 21;
          uint256 internal constant _ROLE_22 = 1 << 22;
          uint256 internal constant _ROLE_23 = 1 << 23;
          uint256 internal constant _ROLE_24 = 1 << 24;
          uint256 internal constant _ROLE_25 = 1 << 25;
          uint256 internal constant _ROLE_26 = 1 << 26;
          uint256 internal constant _ROLE_27 = 1 << 27;
          uint256 internal constant _ROLE_28 = 1 << 28;
          uint256 internal constant _ROLE_29 = 1 << 29;
          uint256 internal constant _ROLE_30 = 1 << 30;
          uint256 internal constant _ROLE_31 = 1 << 31;
          uint256 internal constant _ROLE_32 = 1 << 32;
          uint256 internal constant _ROLE_33 = 1 << 33;
          uint256 internal constant _ROLE_34 = 1 << 34;
          uint256 internal constant _ROLE_35 = 1 << 35;
          uint256 internal constant _ROLE_36 = 1 << 36;
          uint256 internal constant _ROLE_37 = 1 << 37;
          uint256 internal constant _ROLE_38 = 1 << 38;
          uint256 internal constant _ROLE_39 = 1 << 39;
          uint256 internal constant _ROLE_40 = 1 << 40;
          uint256 internal constant _ROLE_41 = 1 << 41;
          uint256 internal constant _ROLE_42 = 1 << 42;
          uint256 internal constant _ROLE_43 = 1 << 43;
          uint256 internal constant _ROLE_44 = 1 << 44;
          uint256 internal constant _ROLE_45 = 1 << 45;
          uint256 internal constant _ROLE_46 = 1 << 46;
          uint256 internal constant _ROLE_47 = 1 << 47;
          uint256 internal constant _ROLE_48 = 1 << 48;
          uint256 internal constant _ROLE_49 = 1 << 49;
          uint256 internal constant _ROLE_50 = 1 << 50;
          uint256 internal constant _ROLE_51 = 1 << 51;
          uint256 internal constant _ROLE_52 = 1 << 52;
          uint256 internal constant _ROLE_53 = 1 << 53;
          uint256 internal constant _ROLE_54 = 1 << 54;
          uint256 internal constant _ROLE_55 = 1 << 55;
          uint256 internal constant _ROLE_56 = 1 << 56;
          uint256 internal constant _ROLE_57 = 1 << 57;
          uint256 internal constant _ROLE_58 = 1 << 58;
          uint256 internal constant _ROLE_59 = 1 << 59;
          uint256 internal constant _ROLE_60 = 1 << 60;
          uint256 internal constant _ROLE_61 = 1 << 61;
          uint256 internal constant _ROLE_62 = 1 << 62;
          uint256 internal constant _ROLE_63 = 1 << 63;
          uint256 internal constant _ROLE_64 = 1 << 64;
          uint256 internal constant _ROLE_65 = 1 << 65;
          uint256 internal constant _ROLE_66 = 1 << 66;
          uint256 internal constant _ROLE_67 = 1 << 67;
          uint256 internal constant _ROLE_68 = 1 << 68;
          uint256 internal constant _ROLE_69 = 1 << 69;
          uint256 internal constant _ROLE_70 = 1 << 70;
          uint256 internal constant _ROLE_71 = 1 << 71;
          uint256 internal constant _ROLE_72 = 1 << 72;
          uint256 internal constant _ROLE_73 = 1 << 73;
          uint256 internal constant _ROLE_74 = 1 << 74;
          uint256 internal constant _ROLE_75 = 1 << 75;
          uint256 internal constant _ROLE_76 = 1 << 76;
          uint256 internal constant _ROLE_77 = 1 << 77;
          uint256 internal constant _ROLE_78 = 1 << 78;
          uint256 internal constant _ROLE_79 = 1 << 79;
          uint256 internal constant _ROLE_80 = 1 << 80;
          uint256 internal constant _ROLE_81 = 1 << 81;
          uint256 internal constant _ROLE_82 = 1 << 82;
          uint256 internal constant _ROLE_83 = 1 << 83;
          uint256 internal constant _ROLE_84 = 1 << 84;
          uint256 internal constant _ROLE_85 = 1 << 85;
          uint256 internal constant _ROLE_86 = 1 << 86;
          uint256 internal constant _ROLE_87 = 1 << 87;
          uint256 internal constant _ROLE_88 = 1 << 88;
          uint256 internal constant _ROLE_89 = 1 << 89;
          uint256 internal constant _ROLE_90 = 1 << 90;
          uint256 internal constant _ROLE_91 = 1 << 91;
          uint256 internal constant _ROLE_92 = 1 << 92;
          uint256 internal constant _ROLE_93 = 1 << 93;
          uint256 internal constant _ROLE_94 = 1 << 94;
          uint256 internal constant _ROLE_95 = 1 << 95;
          uint256 internal constant _ROLE_96 = 1 << 96;
          uint256 internal constant _ROLE_97 = 1 << 97;
          uint256 internal constant _ROLE_98 = 1 << 98;
          uint256 internal constant _ROLE_99 = 1 << 99;
          uint256 internal constant _ROLE_100 = 1 << 100;
          uint256 internal constant _ROLE_101 = 1 << 101;
          uint256 internal constant _ROLE_102 = 1 << 102;
          uint256 internal constant _ROLE_103 = 1 << 103;
          uint256 internal constant _ROLE_104 = 1 << 104;
          uint256 internal constant _ROLE_105 = 1 << 105;
          uint256 internal constant _ROLE_106 = 1 << 106;
          uint256 internal constant _ROLE_107 = 1 << 107;
          uint256 internal constant _ROLE_108 = 1 << 108;
          uint256 internal constant _ROLE_109 = 1 << 109;
          uint256 internal constant _ROLE_110 = 1 << 110;
          uint256 internal constant _ROLE_111 = 1 << 111;
          uint256 internal constant _ROLE_112 = 1 << 112;
          uint256 internal constant _ROLE_113 = 1 << 113;
          uint256 internal constant _ROLE_114 = 1 << 114;
          uint256 internal constant _ROLE_115 = 1 << 115;
          uint256 internal constant _ROLE_116 = 1 << 116;
          uint256 internal constant _ROLE_117 = 1 << 117;
          uint256 internal constant _ROLE_118 = 1 << 118;
          uint256 internal constant _ROLE_119 = 1 << 119;
          uint256 internal constant _ROLE_120 = 1 << 120;
          uint256 internal constant _ROLE_121 = 1 << 121;
          uint256 internal constant _ROLE_122 = 1 << 122;
          uint256 internal constant _ROLE_123 = 1 << 123;
          uint256 internal constant _ROLE_124 = 1 << 124;
          uint256 internal constant _ROLE_125 = 1 << 125;
          uint256 internal constant _ROLE_126 = 1 << 126;
          uint256 internal constant _ROLE_127 = 1 << 127;
          uint256 internal constant _ROLE_128 = 1 << 128;
          uint256 internal constant _ROLE_129 = 1 << 129;
          uint256 internal constant _ROLE_130 = 1 << 130;
          uint256 internal constant _ROLE_131 = 1 << 131;
          uint256 internal constant _ROLE_132 = 1 << 132;
          uint256 internal constant _ROLE_133 = 1 << 133;
          uint256 internal constant _ROLE_134 = 1 << 134;
          uint256 internal constant _ROLE_135 = 1 << 135;
          uint256 internal constant _ROLE_136 = 1 << 136;
          uint256 internal constant _ROLE_137 = 1 << 137;
          uint256 internal constant _ROLE_138 = 1 << 138;
          uint256 internal constant _ROLE_139 = 1 << 139;
          uint256 internal constant _ROLE_140 = 1 << 140;
          uint256 internal constant _ROLE_141 = 1 << 141;
          uint256 internal constant _ROLE_142 = 1 << 142;
          uint256 internal constant _ROLE_143 = 1 << 143;
          uint256 internal constant _ROLE_144 = 1 << 144;
          uint256 internal constant _ROLE_145 = 1 << 145;
          uint256 internal constant _ROLE_146 = 1 << 146;
          uint256 internal constant _ROLE_147 = 1 << 147;
          uint256 internal constant _ROLE_148 = 1 << 148;
          uint256 internal constant _ROLE_149 = 1 << 149;
          uint256 internal constant _ROLE_150 = 1 << 150;
          uint256 internal constant _ROLE_151 = 1 << 151;
          uint256 internal constant _ROLE_152 = 1 << 152;
          uint256 internal constant _ROLE_153 = 1 << 153;
          uint256 internal constant _ROLE_154 = 1 << 154;
          uint256 internal constant _ROLE_155 = 1 << 155;
          uint256 internal constant _ROLE_156 = 1 << 156;
          uint256 internal constant _ROLE_157 = 1 << 157;
          uint256 internal constant _ROLE_158 = 1 << 158;
          uint256 internal constant _ROLE_159 = 1 << 159;
          uint256 internal constant _ROLE_160 = 1 << 160;
          uint256 internal constant _ROLE_161 = 1 << 161;
          uint256 internal constant _ROLE_162 = 1 << 162;
          uint256 internal constant _ROLE_163 = 1 << 163;
          uint256 internal constant _ROLE_164 = 1 << 164;
          uint256 internal constant _ROLE_165 = 1 << 165;
          uint256 internal constant _ROLE_166 = 1 << 166;
          uint256 internal constant _ROLE_167 = 1 << 167;
          uint256 internal constant _ROLE_168 = 1 << 168;
          uint256 internal constant _ROLE_169 = 1 << 169;
          uint256 internal constant _ROLE_170 = 1 << 170;
          uint256 internal constant _ROLE_171 = 1 << 171;
          uint256 internal constant _ROLE_172 = 1 << 172;
          uint256 internal constant _ROLE_173 = 1 << 173;
          uint256 internal constant _ROLE_174 = 1 << 174;
          uint256 internal constant _ROLE_175 = 1 << 175;
          uint256 internal constant _ROLE_176 = 1 << 176;
          uint256 internal constant _ROLE_177 = 1 << 177;
          uint256 internal constant _ROLE_178 = 1 << 178;
          uint256 internal constant _ROLE_179 = 1 << 179;
          uint256 internal constant _ROLE_180 = 1 << 180;
          uint256 internal constant _ROLE_181 = 1 << 181;
          uint256 internal constant _ROLE_182 = 1 << 182;
          uint256 internal constant _ROLE_183 = 1 << 183;
          uint256 internal constant _ROLE_184 = 1 << 184;
          uint256 internal constant _ROLE_185 = 1 << 185;
          uint256 internal constant _ROLE_186 = 1 << 186;
          uint256 internal constant _ROLE_187 = 1 << 187;
          uint256 internal constant _ROLE_188 = 1 << 188;
          uint256 internal constant _ROLE_189 = 1 << 189;
          uint256 internal constant _ROLE_190 = 1 << 190;
          uint256 internal constant _ROLE_191 = 1 << 191;
          uint256 internal constant _ROLE_192 = 1 << 192;
          uint256 internal constant _ROLE_193 = 1 << 193;
          uint256 internal constant _ROLE_194 = 1 << 194;
          uint256 internal constant _ROLE_195 = 1 << 195;
          uint256 internal constant _ROLE_196 = 1 << 196;
          uint256 internal constant _ROLE_197 = 1 << 197;
          uint256 internal constant _ROLE_198 = 1 << 198;
          uint256 internal constant _ROLE_199 = 1 << 199;
          uint256 internal constant _ROLE_200 = 1 << 200;
          uint256 internal constant _ROLE_201 = 1 << 201;
          uint256 internal constant _ROLE_202 = 1 << 202;
          uint256 internal constant _ROLE_203 = 1 << 203;
          uint256 internal constant _ROLE_204 = 1 << 204;
          uint256 internal constant _ROLE_205 = 1 << 205;
          uint256 internal constant _ROLE_206 = 1 << 206;
          uint256 internal constant _ROLE_207 = 1 << 207;
          uint256 internal constant _ROLE_208 = 1 << 208;
          uint256 internal constant _ROLE_209 = 1 << 209;
          uint256 internal constant _ROLE_210 = 1 << 210;
          uint256 internal constant _ROLE_211 = 1 << 211;
          uint256 internal constant _ROLE_212 = 1 << 212;
          uint256 internal constant _ROLE_213 = 1 << 213;
          uint256 internal constant _ROLE_214 = 1 << 214;
          uint256 internal constant _ROLE_215 = 1 << 215;
          uint256 internal constant _ROLE_216 = 1 << 216;
          uint256 internal constant _ROLE_217 = 1 << 217;
          uint256 internal constant _ROLE_218 = 1 << 218;
          uint256 internal constant _ROLE_219 = 1 << 219;
          uint256 internal constant _ROLE_220 = 1 << 220;
          uint256 internal constant _ROLE_221 = 1 << 221;
          uint256 internal constant _ROLE_222 = 1 << 222;
          uint256 internal constant _ROLE_223 = 1 << 223;
          uint256 internal constant _ROLE_224 = 1 << 224;
          uint256 internal constant _ROLE_225 = 1 << 225;
          uint256 internal constant _ROLE_226 = 1 << 226;
          uint256 internal constant _ROLE_227 = 1 << 227;
          uint256 internal constant _ROLE_228 = 1 << 228;
          uint256 internal constant _ROLE_229 = 1 << 229;
          uint256 internal constant _ROLE_230 = 1 << 230;
          uint256 internal constant _ROLE_231 = 1 << 231;
          uint256 internal constant _ROLE_232 = 1 << 232;
          uint256 internal constant _ROLE_233 = 1 << 233;
          uint256 internal constant _ROLE_234 = 1 << 234;
          uint256 internal constant _ROLE_235 = 1 << 235;
          uint256 internal constant _ROLE_236 = 1 << 236;
          uint256 internal constant _ROLE_237 = 1 << 237;
          uint256 internal constant _ROLE_238 = 1 << 238;
          uint256 internal constant _ROLE_239 = 1 << 239;
          uint256 internal constant _ROLE_240 = 1 << 240;
          uint256 internal constant _ROLE_241 = 1 << 241;
          uint256 internal constant _ROLE_242 = 1 << 242;
          uint256 internal constant _ROLE_243 = 1 << 243;
          uint256 internal constant _ROLE_244 = 1 << 244;
          uint256 internal constant _ROLE_245 = 1 << 245;
          uint256 internal constant _ROLE_246 = 1 << 246;
          uint256 internal constant _ROLE_247 = 1 << 247;
          uint256 internal constant _ROLE_248 = 1 << 248;
          uint256 internal constant _ROLE_249 = 1 << 249;
          uint256 internal constant _ROLE_250 = 1 << 250;
          uint256 internal constant _ROLE_251 = 1 << 251;
          uint256 internal constant _ROLE_252 = 1 << 252;
          uint256 internal constant _ROLE_253 = 1 << 253;
          uint256 internal constant _ROLE_254 = 1 << 254;
          uint256 internal constant _ROLE_255 = 1 << 255;
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.4;
      /// @notice Simple single owner authorization mixin.
      /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
      /// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173)
      /// for compatibility, the nomenclature for the 2-step ownership handover
      /// may be unique to this codebase.
      abstract contract Ownable {
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                       CUSTOM ERRORS                        */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev The caller is not authorized to call the function.
          error Unauthorized();
          /// @dev The `newOwner` cannot be the zero address.
          error NewOwnerIsZeroAddress();
          /// @dev The `pendingOwner` does not have a valid handover request.
          error NoHandoverRequest();
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                           EVENTS                           */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
          /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
          /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
          /// despite it not being as lightweight as a single argument event.
          event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
          /// @dev An ownership handover to `pendingOwner` has been requested.
          event OwnershipHandoverRequested(address indexed pendingOwner);
          /// @dev The ownership handover to `pendingOwner` has been canceled.
          event OwnershipHandoverCanceled(address indexed pendingOwner);
          /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
          uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
              0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
          /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
          uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
              0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
          /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
          uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
              0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                          STORAGE                           */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`.
          /// It is intentionally choosen to be a high value
          /// to avoid collision with lower slots.
          /// The choice of manual storage layout is to enable compatibility
          /// with both regular and upgradeable contracts.
          uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8;
          /// The ownership handover slot of `newOwner` is given by:
          /// ```
          ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
          ///     let handoverSlot := keccak256(0x00, 0x20)
          /// ```
          /// It stores the expiry timestamp of the two-step ownership handover.
          uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                     INTERNAL FUNCTIONS                     */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev Initializes the owner directly without authorization guard.
          /// This function must be called upon initialization,
          /// regardless of whether the contract is upgradeable or not.
          /// This is to enable generalization to both regular and upgradeable contracts,
          /// and to save gas in case the initial owner is not the caller.
          /// For performance reasons, this function will not check if there
          /// is an existing owner.
          function _initializeOwner(address newOwner) internal virtual {
              /// @solidity memory-safe-assembly
              assembly {
                  // Clean the upper 96 bits.
                  newOwner := shr(96, shl(96, newOwner))
                  // Store the new value.
                  sstore(not(_OWNER_SLOT_NOT), newOwner)
                  // Emit the {OwnershipTransferred} event.
                  log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
              }
          }
          /// @dev Sets the owner directly without authorization guard.
          function _setOwner(address newOwner) internal virtual {
              /// @solidity memory-safe-assembly
              assembly {
                  let ownerSlot := not(_OWNER_SLOT_NOT)
                  // Clean the upper 96 bits.
                  newOwner := shr(96, shl(96, newOwner))
                  // Emit the {OwnershipTransferred} event.
                  log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                  // Store the new value.
                  sstore(ownerSlot, newOwner)
              }
          }
          /// @dev Throws if the sender is not the owner.
          function _checkOwner() internal view virtual {
              /// @solidity memory-safe-assembly
              assembly {
                  // If the caller is not the stored owner, revert.
                  if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) {
                      mstore(0x00, 0x82b42900) // `Unauthorized()`.
                      revert(0x1c, 0x04)
                  }
              }
          }
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                  PUBLIC UPDATE FUNCTIONS                   */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev Allows the owner to transfer the ownership to `newOwner`.
          function transferOwnership(address newOwner) public payable virtual onlyOwner {
              /// @solidity memory-safe-assembly
              assembly {
                  if iszero(shl(96, newOwner)) {
                      mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                      revert(0x1c, 0x04)
                  }
              }
              _setOwner(newOwner);
          }
          /// @dev Allows the owner to renounce their ownership.
          function renounceOwnership() public payable virtual onlyOwner {
              _setOwner(address(0));
          }
          /// @dev Request a two-step ownership handover to the caller.
          /// The request will be automatically expire in 48 hours (172800 seconds) by default.
          function requestOwnershipHandover() public payable virtual {
              unchecked {
                  uint256 expires = block.timestamp + ownershipHandoverValidFor();
                  /// @solidity memory-safe-assembly
                  assembly {
                      // Compute and set the handover slot to `expires`.
                      mstore(0x0c, _HANDOVER_SLOT_SEED)
                      mstore(0x00, caller())
                      sstore(keccak256(0x0c, 0x20), expires)
                      // Emit the {OwnershipHandoverRequested} event.
                      log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
                  }
              }
          }
          /// @dev Cancels the two-step ownership handover to the caller, if any.
          function cancelOwnershipHandover() public payable virtual {
              /// @solidity memory-safe-assembly
              assembly {
                  // Compute and set the handover slot to 0.
                  mstore(0x0c, _HANDOVER_SLOT_SEED)
                  mstore(0x00, caller())
                  sstore(keccak256(0x0c, 0x20), 0)
                  // Emit the {OwnershipHandoverCanceled} event.
                  log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
              }
          }
          /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
          /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
          function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
              /// @solidity memory-safe-assembly
              assembly {
                  // Compute and set the handover slot to 0.
                  mstore(0x0c, _HANDOVER_SLOT_SEED)
                  mstore(0x00, pendingOwner)
                  let handoverSlot := keccak256(0x0c, 0x20)
                  // If the handover does not exist, or has expired.
                  if gt(timestamp(), sload(handoverSlot)) {
                      mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                      revert(0x1c, 0x04)
                  }
                  // Set the handover slot to 0.
                  sstore(handoverSlot, 0)
              }
              _setOwner(pendingOwner);
          }
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                   PUBLIC READ FUNCTIONS                    */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev Returns the owner of the contract.
          function owner() public view virtual returns (address result) {
              /// @solidity memory-safe-assembly
              assembly {
                  result := sload(not(_OWNER_SLOT_NOT))
              }
          }
          /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
          function ownershipHandoverExpiresAt(address pendingOwner)
              public
              view
              virtual
              returns (uint256 result)
          {
              /// @solidity memory-safe-assembly
              assembly {
                  // Compute the handover slot.
                  mstore(0x0c, _HANDOVER_SLOT_SEED)
                  mstore(0x00, pendingOwner)
                  // Load the handover slot.
                  result := sload(keccak256(0x0c, 0x20))
              }
          }
          /// @dev Returns how long a two-step ownership handover is valid for in seconds.
          function ownershipHandoverValidFor() public view virtual returns (uint64) {
              return 48 * 3600;
          }
          /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
          /*                         MODIFIERS                          */
          /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
          /// @dev Marks a function as only callable by the owner.
          modifier onlyOwner() virtual {
              _checkOwner();
              _;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
      pragma solidity ^0.8.0;
      import "../utils/Context.sol";
      /**
       * @dev Contract module which allows children to implement an emergency stop
       * mechanism that can be triggered by an authorized account.
       *
       * This module is used through inheritance. It will make available the
       * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
       * the functions of your contract. Note that they will not be pausable by
       * simply including this module, only once the modifiers are put in place.
       */
      abstract contract Pausable is Context {
          /**
           * @dev Emitted when the pause is triggered by `account`.
           */
          event Paused(address account);
          /**
           * @dev Emitted when the pause is lifted by `account`.
           */
          event Unpaused(address account);
          bool private _paused;
          /**
           * @dev Initializes the contract in unpaused state.
           */
          constructor() {
              _paused = false;
          }
          /**
           * @dev Modifier to make a function callable only when the contract is not paused.
           *
           * Requirements:
           *
           * - The contract must not be paused.
           */
          modifier whenNotPaused() {
              _requireNotPaused();
              _;
          }
          /**
           * @dev Modifier to make a function callable only when the contract is paused.
           *
           * Requirements:
           *
           * - The contract must be paused.
           */
          modifier whenPaused() {
              _requirePaused();
              _;
          }
          /**
           * @dev Returns true if the contract is paused, and false otherwise.
           */
          function paused() public view virtual returns (bool) {
              return _paused;
          }
          /**
           * @dev Throws if the contract is paused.
           */
          function _requireNotPaused() internal view virtual {
              require(!paused(), "Pausable: paused");
          }
          /**
           * @dev Throws if the contract is not paused.
           */
          function _requirePaused() internal view virtual {
              require(paused(), "Pausable: not paused");
          }
          /**
           * @dev Triggers stopped state.
           *
           * Requirements:
           *
           * - The contract must not be paused.
           */
          function _pause() internal virtual whenNotPaused {
              _paused = true;
              emit Paused(_msgSender());
          }
          /**
           * @dev Returns to normal state.
           *
           * Requirements:
           *
           * - The contract must be paused.
           */
          function _unpause() internal virtual whenPaused {
              _paused = false;
              emit Unpaused(_msgSender());
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
      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
      // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
      pragma solidity ^0.8.20;
      import {Math} from "./math/Math.sol";
      import {SignedMath} from "./math/SignedMath.sol";
      /**
       * @dev String operations.
       */
      library Strings {
          bytes16 private constant HEX_DIGITS = "0123456789abcdef";
          uint8 private constant ADDRESS_LENGTH = 20;
          /**
           * @dev The `value` string doesn't fit in the specified `length`.
           */
          error StringsInsufficientHexLength(uint256 value, uint256 length);
          /**
           * @dev Converts a `uint256` to its ASCII `string` decimal representation.
           */
          function toString(uint256 value) internal pure returns (string memory) {
              unchecked {
                  uint256 length = Math.log10(value) + 1;
                  string memory buffer = new string(length);
                  uint256 ptr;
                  /// @solidity memory-safe-assembly
                  assembly {
                      ptr := add(buffer, add(32, length))
                  }
                  while (true) {
                      ptr--;
                      /// @solidity memory-safe-assembly
                      assembly {
                          mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                      }
                      value /= 10;
                      if (value == 0) break;
                  }
                  return buffer;
              }
          }
          /**
           * @dev Converts a `int256` to its ASCII `string` decimal representation.
           */
          function toStringSigned(int256 value) internal pure returns (string memory) {
              return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
          }
          /**
           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
           */
          function toHexString(uint256 value) internal pure returns (string memory) {
              unchecked {
                  return toHexString(value, Math.log256(value) + 1);
              }
          }
          /**
           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
           */
          function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
              uint256 localValue = value;
              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_DIGITS[localValue & 0xf];
                  localValue >>= 4;
              }
              if (localValue != 0) {
                  revert StringsInsufficientHexLength(value, length);
              }
              return string(buffer);
          }
          /**
           * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
           * representation.
           */
          function toHexString(address addr) internal pure returns (string memory) {
              return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
          }
          /**
           * @dev Returns true if the two strings are equal.
           */
          function equal(string memory a, string memory b) internal pure returns (bool) {
              return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/IERC1155MetadataURI.sol)
      pragma solidity ^0.8.20;
      import {IERC1155} from "../IERC1155.sol";
      /**
       * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
       * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
       */
      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: AGPL-3.0-only
      pragma solidity >=0.8.0;
      /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
      /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)
      /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
      /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
      abstract contract ERC20 {
          /*//////////////////////////////////////////////////////////////
                                       EVENTS
          //////////////////////////////////////////////////////////////*/
          event Transfer(address indexed from, address indexed to, uint256 amount);
          event Approval(address indexed owner, address indexed spender, uint256 amount);
          /*//////////////////////////////////////////////////////////////
                                  METADATA STORAGE
          //////////////////////////////////////////////////////////////*/
          string public name;
          string public symbol;
          uint8 public immutable decimals;
          /*//////////////////////////////////////////////////////////////
                                    ERC20 STORAGE
          //////////////////////////////////////////////////////////////*/
          uint256 public totalSupply;
          mapping(address => uint256) public balanceOf;
          mapping(address => mapping(address => uint256)) public allowance;
          /*//////////////////////////////////////////////////////////////
                                  EIP-2612 STORAGE
          //////////////////////////////////////////////////////////////*/
          uint256 internal immutable INITIAL_CHAIN_ID;
          bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
          mapping(address => uint256) public nonces;
          /*//////////////////////////////////////////////////////////////
                                     CONSTRUCTOR
          //////////////////////////////////////////////////////////////*/
          constructor(
              string memory _name,
              string memory _symbol,
              uint8 _decimals
          ) {
              name = _name;
              symbol = _symbol;
              decimals = _decimals;
              INITIAL_CHAIN_ID = block.chainid;
              INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
          }
          /*//////////////////////////////////////////////////////////////
                                     ERC20 LOGIC
          //////////////////////////////////////////////////////////////*/
          function approve(address spender, uint256 amount) public virtual returns (bool) {
              allowance[msg.sender][spender] = amount;
              emit Approval(msg.sender, spender, amount);
              return true;
          }
          function transfer(address to, uint256 amount) public virtual returns (bool) {
              balanceOf[msg.sender] -= amount;
              // Cannot overflow because the sum of all user
              // balances can't exceed the max uint256 value.
              unchecked {
                  balanceOf[to] += amount;
              }
              emit Transfer(msg.sender, to, amount);
              return true;
          }
          function transferFrom(
              address from,
              address to,
              uint256 amount
          ) public virtual returns (bool) {
              uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
              if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
              balanceOf[from] -= amount;
              // Cannot overflow because the sum of all user
              // balances can't exceed the max uint256 value.
              unchecked {
                  balanceOf[to] += amount;
              }
              emit Transfer(from, to, amount);
              return true;
          }
          /*//////////////////////////////////////////////////////////////
                                   EIP-2612 LOGIC
          //////////////////////////////////////////////////////////////*/
          function permit(
              address owner,
              address spender,
              uint256 value,
              uint256 deadline,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) public virtual {
              require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
              // Unchecked because the only math done is incrementing
              // the owner's nonce which cannot realistically overflow.
              unchecked {
                  address recoveredAddress = ecrecover(
                      keccak256(
                          abi.encodePacked(
                              "\\x19\\x01",
                              DOMAIN_SEPARATOR(),
                              keccak256(
                                  abi.encode(
                                      keccak256(
                                          "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                      ),
                                      owner,
                                      spender,
                                      value,
                                      nonces[owner]++,
                                      deadline
                                  )
                              )
                          )
                      ),
                      v,
                      r,
                      s
                  );
                  require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
                  allowance[recoveredAddress][spender] = value;
              }
              emit Approval(owner, spender, value);
          }
          function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
              return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
          }
          function computeDomainSeparator() internal view virtual returns (bytes32) {
              return
                  keccak256(
                      abi.encode(
                          keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                          keccak256(bytes(name)),
                          keccak256("1"),
                          block.chainid,
                          address(this)
                      )
                  );
          }
          /*//////////////////////////////////////////////////////////////
                              INTERNAL MINT/BURN LOGIC
          //////////////////////////////////////////////////////////////*/
          function _mint(address to, uint256 amount) internal virtual {
              totalSupply += amount;
              // Cannot overflow because the sum of all user
              // balances can't exceed the max uint256 value.
              unchecked {
                  balanceOf[to] += amount;
              }
              emit Transfer(address(0), to, amount);
          }
          function _burn(address from, uint256 amount) internal virtual {
              balanceOf[from] -= amount;
              // Cannot underflow because a user's balance
              // will never be larger than the total supply.
              unchecked {
                  totalSupply -= amount;
              }
              emit Transfer(from, address(0), amount);
          }
      }
      // SPDX-License-Identifier: AGPL-3.0-only
      pragma solidity >=0.8.0;
      /// @notice Minimalist and gas efficient standard ERC1155 implementation.
      /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC1155.sol)
      abstract contract ERC1155 {
          /*//////////////////////////////////////////////////////////////
                                       EVENTS
          //////////////////////////////////////////////////////////////*/
          event TransferSingle(
              address indexed operator,
              address indexed from,
              address indexed to,
              uint256 id,
              uint256 amount
          );
          event TransferBatch(
              address indexed operator,
              address indexed from,
              address indexed to,
              uint256[] ids,
              uint256[] amounts
          );
          event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
          event URI(string value, uint256 indexed id);
          /*//////////////////////////////////////////////////////////////
                                   ERC1155 STORAGE
          //////////////////////////////////////////////////////////////*/
          mapping(address => mapping(uint256 => uint256)) public balanceOf;
          mapping(address => mapping(address => bool)) public isApprovedForAll;
          /*//////////////////////////////////////////////////////////////
                                   METADATA LOGIC
          //////////////////////////////////////////////////////////////*/
          function uri(uint256 id) public view virtual returns (string memory);
          /*//////////////////////////////////////////////////////////////
                                    ERC1155 LOGIC
          //////////////////////////////////////////////////////////////*/
          function setApprovalForAll(address operator, bool approved) public virtual {
              isApprovedForAll[msg.sender][operator] = approved;
              emit ApprovalForAll(msg.sender, operator, approved);
          }
          function safeTransferFrom(
              address from,
              address to,
              uint256 id,
              uint256 amount,
              bytes calldata data
          ) public virtual {
              require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");
              balanceOf[from][id] -= amount;
              balanceOf[to][id] += amount;
              emit TransferSingle(msg.sender, from, to, id, amount);
              require(
                  to.code.length == 0
                      ? to != address(0)
                      : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, from, id, amount, data) ==
                          ERC1155TokenReceiver.onERC1155Received.selector,
                  "UNSAFE_RECIPIENT"
              );
          }
          function safeBatchTransferFrom(
              address from,
              address to,
              uint256[] calldata ids,
              uint256[] calldata amounts,
              bytes calldata data
          ) public virtual {
              require(ids.length == amounts.length, "LENGTH_MISMATCH");
              require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");
              // Storing these outside the loop saves ~15 gas per iteration.
              uint256 id;
              uint256 amount;
              for (uint256 i = 0; i < ids.length; ) {
                  id = ids[i];
                  amount = amounts[i];
                  balanceOf[from][id] -= amount;
                  balanceOf[to][id] += amount;
                  // An array can't have a total length
                  // larger than the max uint256 value.
                  unchecked {
                      ++i;
                  }
              }
              emit TransferBatch(msg.sender, from, to, ids, amounts);
              require(
                  to.code.length == 0
                      ? to != address(0)
                      : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) ==
                          ERC1155TokenReceiver.onERC1155BatchReceived.selector,
                  "UNSAFE_RECIPIENT"
              );
          }
          function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
              public
              view
              virtual
              returns (uint256[] memory balances)
          {
              require(owners.length == ids.length, "LENGTH_MISMATCH");
              balances = new uint256[](owners.length);
              // Unchecked because the only math done is incrementing
              // the array index counter which cannot possibly overflow.
              unchecked {
                  for (uint256 i = 0; i < owners.length; ++i) {
                      balances[i] = balanceOf[owners[i]][ids[i]];
                  }
              }
          }
          /*//////////////////////////////////////////////////////////////
                                    ERC165 LOGIC
          //////////////////////////////////////////////////////////////*/
          function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
              return
                  interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
                  interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155
                  interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI
          }
          /*//////////////////////////////////////////////////////////////
                              INTERNAL MINT/BURN LOGIC
          //////////////////////////////////////////////////////////////*/
          function _mint(
              address to,
              uint256 id,
              uint256 amount,
              bytes memory data
          ) internal virtual {
              balanceOf[to][id] += amount;
              emit TransferSingle(msg.sender, address(0), to, id, amount);
              require(
                  to.code.length == 0
                      ? to != address(0)
                      : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, address(0), id, amount, data) ==
                          ERC1155TokenReceiver.onERC1155Received.selector,
                  "UNSAFE_RECIPIENT"
              );
          }
          function _batchMint(
              address to,
              uint256[] memory ids,
              uint256[] memory amounts,
              bytes memory data
          ) internal virtual {
              uint256 idsLength = ids.length; // Saves MLOADs.
              require(idsLength == amounts.length, "LENGTH_MISMATCH");
              for (uint256 i = 0; i < idsLength; ) {
                  balanceOf[to][ids[i]] += amounts[i];
                  // An array can't have a total length
                  // larger than the max uint256 value.
                  unchecked {
                      ++i;
                  }
              }
              emit TransferBatch(msg.sender, address(0), to, ids, amounts);
              require(
                  to.code.length == 0
                      ? to != address(0)
                      : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) ==
                          ERC1155TokenReceiver.onERC1155BatchReceived.selector,
                  "UNSAFE_RECIPIENT"
              );
          }
          function _batchBurn(
              address from,
              uint256[] memory ids,
              uint256[] memory amounts
          ) internal virtual {
              uint256 idsLength = ids.length; // Saves MLOADs.
              require(idsLength == amounts.length, "LENGTH_MISMATCH");
              for (uint256 i = 0; i < idsLength; ) {
                  balanceOf[from][ids[i]] -= amounts[i];
                  // An array can't have a total length
                  // larger than the max uint256 value.
                  unchecked {
                      ++i;
                  }
              }
              emit TransferBatch(msg.sender, from, address(0), ids, amounts);
          }
          function _burn(
              address from,
              uint256 id,
              uint256 amount
          ) internal virtual {
              balanceOf[from][id] -= amount;
              emit TransferSingle(msg.sender, from, address(0), id, amount);
          }
      }
      /// @notice A generic interface for a contract which properly accepts ERC1155 tokens.
      /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC1155.sol)
      abstract contract ERC1155TokenReceiver {
          function onERC1155Received(
              address,
              address,
              uint256,
              uint256,
              bytes calldata
          ) external virtual returns (bytes4) {
              return ERC1155TokenReceiver.onERC1155Received.selector;
          }
          function onERC1155BatchReceived(
              address,
              address,
              uint256[] calldata,
              uint256[] calldata,
              bytes calldata
          ) external virtual returns (bytes4) {
              return ERC1155TokenReceiver.onERC1155BatchReceived.selector;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Standard signed math utilities missing in the Solidity language.
       */
      library SignedMath {
          /**
           * @dev Returns the largest of two signed numbers.
           */
          function max(int256 a, int256 b) internal pure returns (int256) {
              return a > b ? a : b;
          }
          /**
           * @dev Returns the smallest of two signed numbers.
           */
          function min(int256 a, int256 b) internal pure returns (int256) {
              return a < b ? a : b;
          }
          /**
           * @dev Returns the average of two signed numbers without overflow.
           * The result is rounded towards zero.
           */
          function average(int256 a, int256 b) internal pure returns (int256) {
              // Formula from the book "Hacker's Delight"
              int256 x = (a & b) + ((a ^ b) >> 1);
              return x + (int256(uint256(x) >> 255) & (a ^ b));
          }
          /**
           * @dev Returns the absolute unsigned value of a signed value.
           */
          function abs(int256 n) internal pure returns (uint256) {
              unchecked {
                  // must be unchecked in order to support `n = type(int256).min`
                  return uint256(n >= 0 ? n : -n);
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Standard math utilities missing in the Solidity language.
       */
      library Math {
          /**
           * @dev Muldiv operation overflow.
           */
          error MathOverflowedMulDiv();
          enum Rounding {
              Floor, // Toward negative infinity
              Ceil, // Toward positive infinity
              Trunc, // Toward zero
              Expand // Away from zero
          }
          /**
           * @dev Returns the addition of two unsigned integers, with an overflow flag.
           */
          function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  uint256 c = a + b;
                  if (c < a) return (false, 0);
                  return (true, c);
              }
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
           */
          function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  if (b > a) return (false, 0);
                  return (true, a - b);
              }
          }
          /**
           * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
           */
          function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  // 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.
           */
          function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  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.
           */
          function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              unchecked {
                  if (b == 0) return (false, 0);
                  return (true, a % b);
              }
          }
          /**
           * @dev Returns the largest of two numbers.
           */
          function max(uint256 a, uint256 b) internal pure returns (uint256) {
              return a > b ? a : b;
          }
          /**
           * @dev Returns the smallest of two numbers.
           */
          function min(uint256 a, uint256 b) internal pure returns (uint256) {
              return a < b ? a : b;
          }
          /**
           * @dev Returns the average of two numbers. The result is rounded towards
           * zero.
           */
          function average(uint256 a, uint256 b) internal pure returns (uint256) {
              // (a + b) / 2 can overflow.
              return (a & b) + (a ^ b) / 2;
          }
          /**
           * @dev Returns the ceiling of the division of two numbers.
           *
           * This differs from standard division with `/` in that it rounds towards infinity instead
           * of rounding towards zero.
           */
          function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
              if (b == 0) {
                  // Guarantee the same behavior as in a regular Solidity division.
                  return a / b;
              }
              // (a + b - 1) / b can overflow on addition, so we distribute.
              return a == 0 ? 0 : (a - 1) / b + 1;
          }
          /**
           * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
           * denominator == 0.
           * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
           * Uniswap Labs also under MIT license.
           */
          function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
              unchecked {
                  // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                  // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                  // variables such that product = prod1 * 2^256 + prod0.
                  uint256 prod0 = x * y; // Least significant 256 bits of the product
                  uint256 prod1; // Most significant 256 bits of the product
                  assembly {
                      let mm := mulmod(x, y, not(0))
                      prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                  }
                  // Handle non-overflow cases, 256 by 256 division.
                  if (prod1 == 0) {
                      // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                      // The surrounding unchecked block does not change this fact.
                      // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                      return prod0 / denominator;
                  }
                  // Make sure the result is less than 2^256. Also prevents denominator == 0.
                  if (denominator <= prod1) {
                      revert MathOverflowedMulDiv();
                  }
                  ///////////////////////////////////////////////
                  // 512 by 256 division.
                  ///////////////////////////////////////////////
                  // Make division exact by subtracting the remainder from [prod1 prod0].
                  uint256 remainder;
                  assembly {
                      // Compute remainder using mulmod.
                      remainder := mulmod(x, y, denominator)
                      // Subtract 256 bit number from 512 bit number.
                      prod1 := sub(prod1, gt(remainder, prod0))
                      prod0 := sub(prod0, remainder)
                  }
                  // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
                  // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
                  uint256 twos = denominator & (0 - denominator);
                  assembly {
                      // Divide denominator by twos.
                      denominator := div(denominator, twos)
                      // Divide [prod1 prod0] by twos.
                      prod0 := div(prod0, twos)
                      // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                      twos := add(div(sub(0, twos), twos), 1)
                  }
                  // Shift in bits from prod1 into prod0.
                  prod0 |= prod1 * twos;
                  // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                  // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                  // four bits. That is, denominator * inv = 1 mod 2^4.
                  uint256 inverse = (3 * denominator) ^ 2;
                  // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
                  // works in modular arithmetic, doubling the correct bits in each step.
                  inverse *= 2 - denominator * inverse; // inverse mod 2^8
                  inverse *= 2 - denominator * inverse; // inverse mod 2^16
                  inverse *= 2 - denominator * inverse; // inverse mod 2^32
                  inverse *= 2 - denominator * inverse; // inverse mod 2^64
                  inverse *= 2 - denominator * inverse; // inverse mod 2^128
                  inverse *= 2 - denominator * inverse; // inverse mod 2^256
                  // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                  // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                  // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                  // is no longer required.
                  result = prod0 * inverse;
                  return result;
              }
          }
          /**
           * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
           */
          function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
              uint256 result = mulDiv(x, y, denominator);
              if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
                  result += 1;
              }
              return result;
          }
          /**
           * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
           * towards zero.
           *
           * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
           */
          function sqrt(uint256 a) internal pure returns (uint256) {
              if (a == 0) {
                  return 0;
              }
              // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
              //
              // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
              // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
              //
              // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
              // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
              // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
              //
              // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
              uint256 result = 1 << (log2(a) >> 1);
              // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
              // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
              // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
              // into the expected uint128 result.
              unchecked {
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  result = (result + a / result) >> 1;
                  return min(result, a / result);
              }
          }
          /**
           * @notice Calculates sqrt(a), following the selected rounding direction.
           */
          function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
              unchecked {
                  uint256 result = sqrt(a);
                  return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
              }
          }
          /**
           * @dev Return the log in base 2 of a positive value rounded towards zero.
           * Returns 0 if given 0.
           */
          function log2(uint256 value) internal pure returns (uint256) {
              uint256 result = 0;
              unchecked {
                  if (value >> 128 > 0) {
                      value >>= 128;
                      result += 128;
                  }
                  if (value >> 64 > 0) {
                      value >>= 64;
                      result += 64;
                  }
                  if (value >> 32 > 0) {
                      value >>= 32;
                      result += 32;
                  }
                  if (value >> 16 > 0) {
                      value >>= 16;
                      result += 16;
                  }
                  if (value >> 8 > 0) {
                      value >>= 8;
                      result += 8;
                  }
                  if (value >> 4 > 0) {
                      value >>= 4;
                      result += 4;
                  }
                  if (value >> 2 > 0) {
                      value >>= 2;
                      result += 2;
                  }
                  if (value >> 1 > 0) {
                      result += 1;
                  }
              }
              return result;
          }
          /**
           * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
           * Returns 0 if given 0.
           */
          function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
              unchecked {
                  uint256 result = log2(value);
                  return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
              }
          }
          /**
           * @dev Return the log in base 10 of a positive value rounded towards zero.
           * Returns 0 if given 0.
           */
          function log10(uint256 value) internal pure returns (uint256) {
              uint256 result = 0;
              unchecked {
                  if (value >= 10 ** 64) {
                      value /= 10 ** 64;
                      result += 64;
                  }
                  if (value >= 10 ** 32) {
                      value /= 10 ** 32;
                      result += 32;
                  }
                  if (value >= 10 ** 16) {
                      value /= 10 ** 16;
                      result += 16;
                  }
                  if (value >= 10 ** 8) {
                      value /= 10 ** 8;
                      result += 8;
                  }
                  if (value >= 10 ** 4) {
                      value /= 10 ** 4;
                      result += 4;
                  }
                  if (value >= 10 ** 2) {
                      value /= 10 ** 2;
                      result += 2;
                  }
                  if (value >= 10 ** 1) {
                      result += 1;
                  }
              }
              return result;
          }
          /**
           * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
           * Returns 0 if given 0.
           */
          function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
              unchecked {
                  uint256 result = log10(value);
                  return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
              }
          }
          /**
           * @dev Return the log in base 256 of a positive value rounded towards zero.
           * Returns 0 if given 0.
           *
           * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
           */
          function log256(uint256 value) internal pure returns (uint256) {
              uint256 result = 0;
              unchecked {
                  if (value >> 128 > 0) {
                      value >>= 128;
                      result += 16;
                  }
                  if (value >> 64 > 0) {
                      value >>= 64;
                      result += 8;
                  }
                  if (value >> 32 > 0) {
                      value >>= 32;
                      result += 4;
                  }
                  if (value >> 16 > 0) {
                      value >>= 16;
                      result += 2;
                  }
                  if (value >> 8 > 0) {
                      result += 1;
                  }
              }
              return result;
          }
          /**
           * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
           * Returns 0 if given 0.
           */
          function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
              unchecked {
                  uint256 result = log256(value);
                  return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
              }
          }
          /**
           * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
           */
          function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
              return uint8(rounding) % 2 == 1;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.1) (token/ERC1155/IERC1155.sol)
      pragma solidity ^0.8.20;
      import {IERC165} from "../../utils/introspection/IERC165.sol";
      /**
       * @dev Required interface of an ERC1155 compliant contract, as defined in the
       * https://eips.ethereum.org/EIPS/eip-1155[EIP].
       */
      interface IERC1155 is IERC165 {
          /**
           * @dev Emitted when `value` amount of tokens of 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 value 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 a `value` amount of tokens of type `id` from `from` to `to`.
           *
           * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
           * to an untrusted contract, when invoking {onERC1155Received} on the receiver.
           * Ensure to follow the checks-effects-interactions pattern and consider employing
           * reentrancy guards when interacting with untrusted contracts.
           *
           * Emits a {TransferSingle} event.
           *
           * Requirements:
           *
           * - `to` cannot be the zero address.
           * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
           * - `from` must have a balance of tokens of type `id` of at least `value` 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 value, bytes calldata data) external;
          /**
           * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
           *
           * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
           * to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver.
           * Ensure to follow the checks-effects-interactions pattern and consider employing
           * reentrancy guards when interacting with untrusted contracts.
           *
           * Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments.
           *
           * Requirements:
           *
           * - `ids` and `values` 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 values,
              bytes calldata data
          ) external;
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
      pragma solidity ^0.8.20;
      /**
       * @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;
          }
          function _contextSuffixLength() internal view virtual returns (uint256) {
              return 0;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
      pragma solidity ^0.8.20;
      /**
       * @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);
      }