ETH Price: $2,599.20 (+3.14%)

Transaction Decoder

Block:
22853881 at Jul-05-2025 03:21:59 PM +UTC
Transaction Fee:
0.00003269981601978 ETH $0.08
Gas Used:
87,510 Gas / 0.373669478 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x230CCbAa...06d15f502 From: 0 To: 22892026365094219175075457891378177040480732125407136429
0x713D83Cb...435bb3392
0x72785D42...e1a5238df
3.04678711356505825 Eth
Nonce: 1270
3.04675441374903847 Eth
Nonce: 1271
0.00003269981601978
2.358492297932791141 Eth2.358495146874659791 Eth0.00000284894186865

Execution Trace

0x230ccbaaac59bcc7a50a2f526598e7b06d15f502.174dea71( )
  • MoonRaptors.transferFrom( from=0x230CCbAaaC59BcC7A50a2f526598E7b06d15f502, to=0x72785D42874E965086829eA789a703fe1a5238df, tokenId=6347 )
    • OperatorFilterRegistry.isOperatorAllowed( registrant=0x713D83Cb05aA0d48Cd162eA2DCA44a3435bb3392, operator=0x230CCbAaaC59BcC7A50a2f526598E7b06d15f502 ) => ( True )
      File 1 of 2: MoonRaptors
      // SPDX-License-Identifier: MIT      
      
      /**
      
       ███▄ ▄███▓ ▒█████   ▒█████   ███▄    █                         
      ▓██▒▀█▀ ██▒▒██▒  ██▒▒██▒  ██▒ ██ ▀█   █                         
      ▓██    ▓██░▒██░  ██▒▒██░  ██▒▓██  ▀█ ██▒                        
      ▒██    ▒██ ▒██   ██░▒██   ██░▓██▒  ▐▌██▒                        
      ▒██▒   ░██▒░ ████▓▒░░ ████▓▒░▒██░   ▓██░                        
      ░ ▒░   ░  ░░ ▒░▒░▒░ ░ ▒░▒░▒░ ░ ▒░   ▒ ▒                         
      ░  ░      ░  ░ ▒ ▒░   ░ ▒ ▒░ ░ ░░   ░ ▒░                        
      ░      ░   ░ ░ ░ ▒  ░ ░ ░ ▒     ░   ░ ░                         
             ░       ░ ░      ░ ░           ░                         
                                                                      
       ██▀███   ▄▄▄       ██▓███  ▄▄▄█████▓ ▒█████   ██▀███    ██████ 
      ▓██ ▒ ██▒▒████▄    ▓██░  ██▒▓  ██▒ ▓▒▒██▒  ██▒▓██ ▒ ██▒▒██    ▒ 
      ▓██ ░▄█ ▒▒██  ▀█▄  ▓██░ ██▓▒▒ ▓██░ ▒░▒██░  ██▒▓██ ░▄█ ▒░ ▓██▄   
      ▒██▀▀█▄  ░██▄▄▄▄██ ▒██▄█▓▒ ▒░ ▓██▓ ░ ▒██   ██░▒██▀▀█▄    ▒   ██▒
      ░██▓ ▒██▒ ▓█   ▓██▒▒██▒ ░  ░  ▒██▒ ░ ░ ████▓▒░░██▓ ▒██▒▒██████▒▒
      ░ ▒▓ ░▒▓░ ▒▒   ▓▒█░▒▓▒░ ░  ░  ▒ ░░   ░ ▒░▒░▒░ ░ ▒▓ ░▒▓░▒ ▒▓▒ ▒ ░
        ░▒ ░ ▒░  ▒   ▒▒ ░░▒ ░         ░      ░ ▒ ▒░   ░▒ ░ ▒░░ ░▒  ░ ░
        ░░   ░   ░   ▒   ░░         ░      ░ ░ ░ ▒    ░░   ░ ░  ░  ░  
         ░           ░  ░                      ░ ░     ░           ░  
                                                                      
      */                                    
      
      pragma solidity ^0.8.0;
      abstract contract Context {
          function _msgSender() internal view virtual returns (address) {
              return msg.sender;
          }
      
          function _msgData() internal view virtual returns (bytes calldata) {
              return msg.data;
          }
      }
      
      pragma solidity ^0.8.0;
      abstract contract Ownable is Context {
          address private _owner;
      
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
          constructor() {
              _transferOwnership(_msgSender());
          }
      
          modifier onlyOwner() {
              _checkOwner();
              _;
          }
      
          function owner() public view virtual returns (address) {
              return _owner;
          }
      
          function _checkOwner() internal view virtual {
              require(owner() == _msgSender(), "Ownable: caller is not the owner");
          }
      
          function renounceOwnership() public virtual onlyOwner {
              _transferOwnership(address(0));
          }
      
      
          function transferOwnership(address newOwner) public virtual onlyOwner {
              require(newOwner != address(0), "Ownable: new owner is the zero address");
              _transferOwnership(newOwner);
          }
      
          function _transferOwnership(address newOwner) internal virtual {
              address oldOwner = _owner;
              _owner = newOwner;
              emit OwnershipTransferred(oldOwner, newOwner);
          }
      }
      
      pragma solidity ^0.8.0;
      
      abstract contract ReentrancyGuard {
      
          uint256 private constant _NOT_ENTERED = 1;
          uint256 private constant _ENTERED = 2;
      
          uint256 private _status;
      
          constructor() {
              _status = _NOT_ENTERED;
          }
      
          modifier nonReentrant() {
              // On the first call to nonReentrant, _notEntered will be true
              require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
      
              // Any calls to nonReentrant after this point will fail
              _status = _ENTERED;
      
              _;
      
              _status = _NOT_ENTERED;
          }
      }
      
      pragma solidity ^0.8.0;
      
      library Strings {
          bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
          uint8 private constant _ADDRESS_LENGTH = 20;
      
          function toString(uint256 value) internal pure returns (string memory) {
      
              if (value == 0) {
                  return "0";
              }
              uint256 temp = value;
              uint256 digits;
              while (temp != 0) {
                  digits++;
                  temp /= 10;
              }
              bytes memory buffer = new bytes(digits);
              while (value != 0) {
                  digits -= 1;
                  buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                  value /= 10;
              }
              return string(buffer);
          }
      
          function toHexString(uint256 value) internal pure returns (string memory) {
              if (value == 0) {
                  return "0x00";
              }
              uint256 temp = value;
              uint256 length = 0;
              while (temp != 0) {
                  length++;
                  temp >>= 8;
              }
              return toHexString(value, length);
          }
      
          function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
              bytes memory buffer = new bytes(2 * length + 2);
              buffer[0] = "0";
              buffer[1] = "x";
              for (uint256 i = 2 * length + 1; i > 1; --i) {
                  buffer[i] = _HEX_SYMBOLS[value & 0xf];
                  value >>= 4;
              }
              require(value == 0, "Strings: hex length insufficient");
              return string(buffer);
          }
      
          function toHexString(address addr) internal pure returns (string memory) {
              return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
          }
      }
      
      pragma solidity ^0.8.0;
      
      
      library EnumerableSet {
      
      
          struct Set {
              // Storage of set values
              bytes32[] _values;
      
              mapping(bytes32 => uint256) _indexes;
          }
      
          function _add(Set storage set, bytes32 value) private returns (bool) {
              if (!_contains(set, value)) {
                  set._values.push(value);
      
                  set._indexes[value] = set._values.length;
                  return true;
              } else {
                  return false;
              }
          }
      
          function _remove(Set storage set, bytes32 value) private returns (bool) {
      
              uint256 valueIndex = set._indexes[value];
      
              if (valueIndex != 0) {
      
                  uint256 toDeleteIndex = valueIndex - 1;
                  uint256 lastIndex = set._values.length - 1;
      
                  if (lastIndex != toDeleteIndex) {
                      bytes32 lastValue = set._values[lastIndex];
      
                      set._values[toDeleteIndex] = lastValue;
                      
                      set._indexes[lastValue] = valueIndex; 
                  }
      
                  // Delete the slot where the moved value was stored
                  set._values.pop();
      
                  // Delete the index for the deleted slot
                  delete set._indexes[value];
      
                  return true;
              } else {
                  return false;
              }
          }
      
          function _contains(Set storage set, bytes32 value) private view returns (bool) {
              return set._indexes[value] != 0;
          }
      
          function _length(Set storage set) private view returns (uint256) {
              return set._values.length;
          }
      
          function _at(Set storage set, uint256 index) private view returns (bytes32) {
              return set._values[index];
          }
      
          function _values(Set storage set) private view returns (bytes32[] memory) {
              return set._values;
          }
      
          struct Bytes32Set {
              Set _inner;
          }
      
          function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
              return _add(set._inner, value);
          }
      
          function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
              return _remove(set._inner, value);
          }
      
          function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
              return _contains(set._inner, value);
          }
      
          function length(Bytes32Set storage set) internal view returns (uint256) {
              return _length(set._inner);
          }
      
          function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
              return _at(set._inner, index);
          }
      
          function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
              return _values(set._inner);
          }
      
          struct AddressSet {
              Set _inner;
          }
      
          function add(AddressSet storage set, address value) internal returns (bool) {
              return _add(set._inner, bytes32(uint256(uint160(value))));
          }
      
          function remove(AddressSet storage set, address value) internal returns (bool) {
              return _remove(set._inner, bytes32(uint256(uint160(value))));
          }
      
          function contains(AddressSet storage set, address value) internal view returns (bool) {
              return _contains(set._inner, bytes32(uint256(uint160(value))));
          }
      
          function length(AddressSet storage set) internal view returns (uint256) {
              return _length(set._inner);
          }
      
          function at(AddressSet storage set, uint256 index) internal view returns (address) {
              return address(uint160(uint256(_at(set._inner, index))));
          }
      
          function values(AddressSet storage set) internal view returns (address[] memory) {
              bytes32[] memory store = _values(set._inner);
              address[] memory result;
      
              assembly {
                  result := store
              }
      
              return result;
          }
      
          struct UintSet {
              Set _inner;
          }
      
          function add(UintSet storage set, uint256 value) internal returns (bool) {
              return _add(set._inner, bytes32(value));
          }
      
          function remove(UintSet storage set, uint256 value) internal returns (bool) {
              return _remove(set._inner, bytes32(value));
          }
      
          function contains(UintSet storage set, uint256 value) internal view returns (bool) {
              return _contains(set._inner, bytes32(value));
          }
      
          function length(UintSet storage set) internal view returns (uint256) {
              return _length(set._inner);
          }
      
          function at(UintSet storage set, uint256 index) internal view returns (uint256) {
              return uint256(_at(set._inner, index));
          }
      
          function values(UintSet storage set) internal view returns (uint256[] memory) {
              bytes32[] memory store = _values(set._inner);
              uint256[] memory result;
      
              /// @solidity memory-safe-assembly
              assembly {
                  result := store
              }
      
              return result;
          }
      }
      
      pragma solidity ^0.8.4;
      
      interface IERC721A {
      
          error ApprovalCallerNotOwnerNorApproved();
      
          error ApprovalQueryForNonexistentToken();
      
          error BalanceQueryForZeroAddress();
      
          error MintToZeroAddress();
      
          error MintZeroQuantity();
      
          error OwnerQueryForNonexistentToken();
      
          error TransferCallerNotOwnerNorApproved();
      
          error TransferFromIncorrectOwner();
      
          error TransferToNonERC721ReceiverImplementer();
      
          error TransferToZeroAddress();
      
          error URIQueryForNonexistentToken();
      
          error MintERC2309QuantityExceedsLimit();
      
          error OwnershipNotInitializedForExtraData();
      
          struct TokenOwnership {
      
              address addr;
      
              uint64 startTimestamp;
      
              bool burned;
      
              uint24 extraData;
          }
      
          function totalSupply() external view returns (uint256);
      
          function supportsInterface(bytes4 interfaceId) external view returns (bool);
      
          event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
      
          event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
      
          event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
      
          function balanceOf(address owner) external view returns (uint256 balance);
      
          function ownerOf(uint256 tokenId) external view returns (address owner);
      
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId,
              bytes calldata data
          ) external payable;
      
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId
          ) external payable;
      
          function transferFrom(
              address from,
              address to,
              uint256 tokenId
          ) external payable;
      
          function approve(address to, uint256 tokenId) external payable;
      
          function setApprovalForAll(address operator, bool _approved) external;
      
          function getApproved(uint256 tokenId) external view returns (address operator);
      
          function isApprovedForAll(address owner, address operator) external view returns (bool);
      
          function name() external view returns (string memory);
      
          function symbol() external view returns (string memory);
      
          function tokenURI(uint256 tokenId) external view returns (string memory);
      
          event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
      }
      
      pragma solidity ^0.8.4;
      
      interface ERC721A__IERC721Receiver {
          function onERC721Received(
              address operator,
              address from,
              uint256 tokenId,
              bytes calldata data
          ) external returns (bytes4);
      }
      
      contract ERC721A is IERC721A {
      
          struct TokenApprovalRef {
              address value;
          }
      
          uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
      
          uint256 private constant _BITPOS_NUMBER_MINTED = 64;
      
          uint256 private constant _BITPOS_NUMBER_BURNED = 128;
      
          uint256 private constant _BITPOS_AUX = 192;
      
          uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
      
          uint256 private constant _BITPOS_START_TIMESTAMP = 160;
      
          uint256 private constant _BITMASK_BURNED = 1 << 224;
      
          uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
      
          uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
      
          uint256 private constant _BITPOS_EXTRA_DATA = 232;
      
          uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
      
          uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
      
          uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
      
          bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
              0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
      
          uint256 private _currentIndex;
      
          uint256 private _burnCounter;
      
          string private _name;
      
          string private _symbol;
      
          mapping(uint256 => uint256) private _packedOwnerships;
      
          mapping(address => uint256) private _packedAddressData;
      
          mapping(uint256 => TokenApprovalRef) private _tokenApprovals;
      
          mapping(address => mapping(address => bool)) private _operatorApprovals;
      
          constructor(string memory name_, string memory symbol_) {
              _name = name_;
              _symbol = symbol_;
              _currentIndex = _startTokenId();
          }
      
          function _startTokenId() internal view virtual returns (uint256) {
              return 0;
          }
      
          function _nextTokenId() internal view virtual returns (uint256) {
              return _currentIndex;
          }
      
          function totalSupply() public view virtual override returns (uint256) {
      
              unchecked {
                  return _currentIndex - _burnCounter - _startTokenId();
              }
          }
      
          function _totalMinted() internal view virtual returns (uint256) {
      
              unchecked {
                  return _currentIndex - _startTokenId();
              }
          }
      
          function _totalBurned() internal view virtual returns (uint256) {
              return _burnCounter;
          }
      
          function balanceOf(address owner) public view virtual override returns (uint256) {
              if (owner == address(0)) revert BalanceQueryForZeroAddress();
              return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
          }
      
          function _numberMinted(address owner) internal view returns (uint256) {
              return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
          }
      
          function _numberBurned(address owner) internal view returns (uint256) {
              return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
          }
      
          function _getAux(address owner) internal view returns (uint64) {
              return uint64(_packedAddressData[owner] >> _BITPOS_AUX);
          }
      
          function _setAux(address owner, uint64 aux) internal virtual {
              uint256 packed = _packedAddressData[owner];
              uint256 auxCasted;
              // Cast `aux` with assembly to avoid redundant masking.
              assembly {
                  auxCasted := aux
              }
              packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
              _packedAddressData[owner] = packed;
          }
      
      
          function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
      
              return
                  interfaceId == 0x01ffc9a7 || 
                  interfaceId == 0x80ac58cd || 
                  interfaceId == 0x5b5e139f; 
          }
      
          function name() public view virtual override returns (string memory) {
              return _name;
          }
      
          function symbol() public view virtual override returns (string memory) {
              return _symbol;
          }
      
          function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
              if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
      
              string memory baseURI = _baseURI();
              return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
          }
      
          function _baseURI() internal view virtual returns (string memory) {
              return '';
          }
      
          function ownerOf(uint256 tokenId) public view virtual override returns (address) {
              return address(uint160(_packedOwnershipOf(tokenId)));
          }
      
          function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
              return _unpackedOwnership(_packedOwnershipOf(tokenId));
          }
      
          function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
              return _unpackedOwnership(_packedOwnerships[index]);
          }
      
          function _initializeOwnershipAt(uint256 index) internal virtual {
              if (_packedOwnerships[index] == 0) {
                  _packedOwnerships[index] = _packedOwnershipOf(index);
              }
          }
      
          function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) {
              uint256 curr = tokenId;
      
              unchecked {
                  if (_startTokenId() <= curr)
                      if (curr < _currentIndex) {
                          uint256 packed = _packedOwnerships[curr];
      
                          if (packed & _BITMASK_BURNED == 0) {
      
                              while (packed == 0) {
                                  packed = _packedOwnerships[--curr];
                              }
                              return packed;
                          }
                      }
              }
              revert OwnerQueryForNonexistentToken();
          }
      
          function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
              ownership.addr = address(uint160(packed));
              ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
              ownership.burned = packed & _BITMASK_BURNED != 0;
              ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
          }
      
          function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
              assembly {
                  // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
                  owner := and(owner, _BITMASK_ADDRESS)
                  // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
                  result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
              }
          }
      
          function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
              // For branchless setting of the `nextInitialized` flag.
              assembly {
                  // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
                  result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
              }
          }
      
          function approve(address to, uint256 tokenId) public payable virtual override {
              address owner = ownerOf(tokenId);
      
              if (_msgSenderERC721A() != owner)
                  if (!isApprovedForAll(owner, _msgSenderERC721A())) {
                      revert ApprovalCallerNotOwnerNorApproved();
                  }
      
              _tokenApprovals[tokenId].value = to;
              emit Approval(owner, to, tokenId);
          }
      
          function getApproved(uint256 tokenId) public view virtual override returns (address) {
              if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
      
              return _tokenApprovals[tokenId].value;
          }
      
          function setApprovalForAll(address operator, bool approved) public virtual override {
              _operatorApprovals[_msgSenderERC721A()][operator] = approved;
              emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
          }
      
          function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
              return _operatorApprovals[owner][operator];
          }
      
          function _exists(uint256 tokenId) internal view virtual returns (bool) {
              return
                  _startTokenId() <= tokenId &&
                  tokenId < _currentIndex && // If within bounds,
                  _packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.
          }
      
          function _isSenderApprovedOrOwner(
              address approvedAddress,
              address owner,
              address msgSender
          ) private pure returns (bool result) {
              assembly {
      
                  owner := and(owner, _BITMASK_ADDRESS)
      
                  msgSender := and(msgSender, _BITMASK_ADDRESS)
      
                  result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
              }
          }
      
          function _getApprovedSlotAndAddress(uint256 tokenId)
              private
              view
              returns (uint256 approvedAddressSlot, address approvedAddress)
          {
              TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
      
              assembly {
                  approvedAddressSlot := tokenApproval.slot
                  approvedAddress := sload(approvedAddressSlot)
              }
          }
      
          function transferFrom(
              address from,
              address to,
              uint256 tokenId
          ) public payable virtual override {
              uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
      
              if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();
      
              (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
      
              if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                  if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
      
              if (to == address(0)) revert TransferToZeroAddress();
      
              _beforeTokenTransfers(from, to, tokenId, 1);
      
              assembly {
                  if approvedAddress {
      
                      sstore(approvedAddressSlot, 0)
                  }
              }
      
              unchecked {
      
                  --_packedAddressData[from]; 
                  ++_packedAddressData[to]; 
      
                  _packedOwnerships[tokenId] = _packOwnershipData(
                      to,
                      _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
                  );
      
                  if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                      uint256 nextTokenId = tokenId + 1;
      
                      if (_packedOwnerships[nextTokenId] == 0) {
      
                          if (nextTokenId != _currentIndex) {
      
                              _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                          }
                      }
                  }
              }
      
              emit Transfer(from, to, tokenId);
              _afterTokenTransfers(from, to, tokenId, 1);
          }
      
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId
          ) public payable virtual override {
              safeTransferFrom(from, to, tokenId, '');
          }
      
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId,
              bytes memory _data
          ) public payable virtual override {
              transferFrom(from, to, tokenId);
              if (to.code.length != 0)
                  if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
                      revert TransferToNonERC721ReceiverImplementer();
                  }
          }
      
          function _beforeTokenTransfers(
              address from,
              address to,
              uint256 startTokenId,
              uint256 quantity
          ) internal virtual {}
      
          function _afterTokenTransfers(
              address from,
              address to,
              uint256 startTokenId,
              uint256 quantity
          ) internal virtual {}
      
          function _checkContractOnERC721Received(
              address from,
              address to,
              uint256 tokenId,
              bytes memory _data
          ) private returns (bool) {
              try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (
                  bytes4 retval
              ) {
                  return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;
              } catch (bytes memory reason) {
                  if (reason.length == 0) {
                      revert TransferToNonERC721ReceiverImplementer();
                  } else {
                      assembly {
                          revert(add(32, reason), mload(reason))
                      }
                  }
              }
          }
      
          function _mint(address to, uint256 quantity) internal virtual {
              uint256 startTokenId = _currentIndex;
              if (quantity == 0) revert MintZeroQuantity();
      
              _beforeTokenTransfers(address(0), to, startTokenId, quantity);
      
              unchecked {
      
                  _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
      
                  _packedOwnerships[startTokenId] = _packOwnershipData(
                      to,
                      _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
                  );
      
                  uint256 toMasked;
                  uint256 end = startTokenId + quantity;
      
                  assembly {
      
                      toMasked := and(to, _BITMASK_ADDRESS)
      
                      log4(
                          0, 
                          0, 
                          _TRANSFER_EVENT_SIGNATURE, 
                          0, 
                          toMasked, 
                          startTokenId 
                      )
      
                      for {
                          let tokenId := add(startTokenId, 1)
                      } iszero(eq(tokenId, end)) {
                          tokenId := add(tokenId, 1)
                      } {
      
                          log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
                      }
                  }
                  if (toMasked == 0) revert MintToZeroAddress();
      
                  _currentIndex = end;
              }
              _afterTokenTransfers(address(0), to, startTokenId, quantity);
          }
      
          function _mintERC2309(address to, uint256 quantity) internal virtual {
              uint256 startTokenId = _currentIndex;
              if (to == address(0)) revert MintToZeroAddress();
              if (quantity == 0) revert MintZeroQuantity();
              if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit();
      
              _beforeTokenTransfers(address(0), to, startTokenId, quantity);
      
              unchecked {
      
                  _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
      
                  _packedOwnerships[startTokenId] = _packOwnershipData(
                      to,
                      _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
                  );
      
                  emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);
      
                  _currentIndex = startTokenId + quantity;
              }
              _afterTokenTransfers(address(0), to, startTokenId, quantity);
          }
      
          function _safeMint(
              address to,
              uint256 quantity,
              bytes memory _data
          ) internal virtual {
              _mint(to, quantity);
      
              unchecked {
                  if (to.code.length != 0) {
                      uint256 end = _currentIndex;
                      uint256 index = end - quantity;
                      do {
                          if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
                              revert TransferToNonERC721ReceiverImplementer();
                          }
                      } while (index < end);
                      // Reentrancy protection.
                      if (_currentIndex != end) revert();
                  }
              }
          }
      
          function _safeMint(address to, uint256 quantity) internal virtual {
              _safeMint(to, quantity, '');
          }
      
          function _burn(uint256 tokenId) internal virtual {
              _burn(tokenId, false);
          }
      
          function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
              uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
      
              address from = address(uint160(prevOwnershipPacked));
      
              (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
      
              if (approvalCheck) {
                  
                  if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                      if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
              }
      
              _beforeTokenTransfers(from, address(0), tokenId, 1);
      
              assembly {
                  if approvedAddress {
                      
                      sstore(approvedAddressSlot, 0)
                  }
              }
      
              unchecked {
      
                  _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
      
                  _packedOwnerships[tokenId] = _packOwnershipData(
                      from,
                      (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
                  );
      
                  if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                      uint256 nextTokenId = tokenId + 1;
      
                      if (_packedOwnerships[nextTokenId] == 0) {
      
                          if (nextTokenId != _currentIndex) {
      
                              _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                          }
                      }
                  }
              }
      
              emit Transfer(from, address(0), tokenId);
              _afterTokenTransfers(from, address(0), tokenId, 1);
      
              unchecked {
                  _burnCounter++;
              }
          }
      
          function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
              uint256 packed = _packedOwnerships[index];
              if (packed == 0) revert OwnershipNotInitializedForExtraData();
              uint256 extraDataCasted;
              assembly {
                  extraDataCasted := extraData
              }
              packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
              _packedOwnerships[index] = packed;
          }
      
          function _extraData(
              address from,
              address to,
              uint24 previousExtraData
          ) internal view virtual returns (uint24) {}
      
          function _nextExtraData(
              address from,
              address to,
              uint256 prevOwnershipPacked
          ) private view returns (uint256) {
              uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
              return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
          }
      
          function _msgSenderERC721A() internal view virtual returns (address) {
              return msg.sender;
          }
      
          function _toString(uint256 value) internal pure virtual returns (string memory str) {
              assembly {
      
                  let m := add(mload(0x40), 0xa0)
      
                  mstore(0x40, m)
      
                  str := sub(m, 0x20)
      
                  mstore(str, 0)
      
                  let end := str
      
                  for { let temp := value } 1 {} {
                      str := sub(str, 1)
      
                      mstore8(str, add(48, mod(temp, 10)))
      
                      temp := div(temp, 10)
      
                      if iszero(temp) { break }
                  }
      
                  let length := sub(end, str)
      
                  str := sub(str, 0x20)
      
                  mstore(str, length)
              }
          }
      }
      
      pragma solidity ^0.8.13;
      
      contract OperatorFilterer {
          error OperatorNotAllowed(address operator);
      
          IOperatorFilterRegistry constant operatorFilterRegistry =
              IOperatorFilterRegistry(0x000000000000AAeB6D7670E522A718067333cd4E);
      
          constructor(address subscriptionOrRegistrantToCopy, bool subscribe) {
      
              if (address(operatorFilterRegistry).code.length > 0) {
                  if (subscribe) {
                      operatorFilterRegistry.registerAndSubscribe(address(this), subscriptionOrRegistrantToCopy);
                  } else {
                      if (subscriptionOrRegistrantToCopy != address(0)) {
                          operatorFilterRegistry.registerAndCopyEntries(address(this), subscriptionOrRegistrantToCopy);
                      } else {
                          operatorFilterRegistry.register(address(this));
                      }
                  }
              }
          }
      
          modifier onlyAllowedOperator() virtual {
      
              if (address(operatorFilterRegistry).code.length > 0) {
                  if (!operatorFilterRegistry.isOperatorAllowed(address(this), msg.sender)) {
                      revert OperatorNotAllowed(msg.sender);
                  }
              }
              _;
          }
      }
      
      pragma solidity ^0.8.13;
      
      contract DefaultOperatorFilterer is OperatorFilterer {
          address constant DEFAULT_SUBSCRIPTION = address(0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6);
      
          constructor() OperatorFilterer(DEFAULT_SUBSCRIPTION, true) {}
      }
      
      pragma solidity ^0.8.13;
      
      interface IOperatorFilterRegistry {
          function isOperatorAllowed(address registrant, address operator) external returns (bool);
          function register(address registrant) external;
          function registerAndSubscribe(address registrant, address subscription) external;
          function registerAndCopyEntries(address registrant, address registrantToCopy) external;
          function updateOperator(address registrant, address operator, bool filtered) external;
          function updateOperators(address registrant, address[] calldata operators, bool filtered) external;
          function updateCodeHash(address registrant, bytes32 codehash, bool filtered) external;
          function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) external;
          function subscribe(address registrant, address registrantToSubscribe) external;
          function unsubscribe(address registrant, bool copyExistingEntries) external;
          function subscriptionOf(address addr) external returns (address registrant);
          function subscribers(address registrant) external returns (address[] memory);
          function subscriberAt(address registrant, uint256 index) external returns (address);
          function copyEntriesOf(address registrant, address registrantToCopy) external;
          function isOperatorFiltered(address registrant, address operator) external returns (bool);
          function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool);
          function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool);
          function filteredOperators(address addr) external returns (address[] memory);
          function filteredCodeHashes(address addr) external returns (bytes32[] memory);
          function filteredOperatorAt(address registrant, uint256 index) external returns (address);
          function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32);
          function isRegistered(address addr) external returns (bool);
          function codeHashOf(address addr) external returns (bytes32);
      }
      
      pragma solidity ^0.8.4;
      
      interface IERC721ABurnable is IERC721A {
      
          function burn(uint256 tokenId) external;
      }
      
      pragma solidity ^0.8.4;
      abstract contract ERC721ABurnable is ERC721A, IERC721ABurnable {
          function burn(uint256 tokenId) public virtual override {
              _burn(tokenId, true);
          }
      }
      
      pragma solidity ^0.8.16;
      contract MoonRaptors is Ownable, ERC721A, ReentrancyGuard, ERC721ABurnable, DefaultOperatorFilterer{
      string public CONTRACT_URI = "";
      mapping(address => uint) public userHasMinted;
      bool public REVEALED;
      string public UNREVEALED_URI = "";
      string public BASE_URI = "";
      bool public isPublicMintEnabled = false;
      
      uint public COLLECTION_SIZE = 10000;
      uint public MINT_PRICE = 0.0005 ether;
      uint public MAX_BATCH_SIZE = 30;
      uint public SUPPLY_PER_WALLET = 50;
      uint public FREE_SUPPLY_PER_WALLET = 5;
      
      constructor() ERC721A("Moon Raptors", "$RAPTOR") {}
      
      
          function MintVIP(uint256 quantity, address receiver) public onlyOwner {
              require(
                  totalSupply() + quantity <= COLLECTION_SIZE,
                  "No more Raptors in stock!"
              );
              
              _safeMint(receiver, quantity);
          }
      
          modifier callerIsUser() {
              require(tx.origin == msg.sender, "The caller is another contract");
              _;
          }
      
          function getPrice(uint quantity) public view returns(uint){
              uint price;
              uint free = FREE_SUPPLY_PER_WALLET - userHasMinted[msg.sender];
              if (quantity >= free) {
                  price = (MINT_PRICE) * (quantity - free);
              } else {
                  price = 0;
              }
              return price;
          }
      
      
          function mint(uint quantity)
              external
              payable
              callerIsUser 
              nonReentrant
          {
              uint price;
              uint free = FREE_SUPPLY_PER_WALLET - userHasMinted[msg.sender];
              if (quantity >= free) {
                  price = (MINT_PRICE) * (quantity - free);
                  userHasMinted[msg.sender] = userHasMinted[msg.sender] + free;
              } else {
                  price = 0;
                  userHasMinted[msg.sender] = userHasMinted[msg.sender] + quantity;
              }
      
              require(isPublicMintEnabled, "Raptors not ready yet!");
              require(totalSupply() + quantity <= COLLECTION_SIZE, "No more Raptors!");
      
              require(balanceOf(msg.sender) + quantity <= SUPPLY_PER_WALLET, "Tried to total mint Raptors per wallet over limit");
      
              require(quantity <= MAX_BATCH_SIZE, "Tried to mint Raptors over limit, retry with reduced quantity");
              require(msg.value >= price, "Must send enough eth");
      
              _safeMint(msg.sender, quantity);
      
              if (msg.value > price) {
                  payable(msg.sender).transfer(msg.value - price);
              }
          }
      
          function withdrawFunds() external onlyOwner nonReentrant {
              (bool success, ) = msg.sender.call{value: address(this).balance}("");
              require(success, "Transfer failed.");
          }
      
          function setPublicMintEnabled() public onlyOwner {
              isPublicMintEnabled = !isPublicMintEnabled;
          }
      
          function setBaseURI(bool _revealed, string memory _baseURI) public onlyOwner {
              BASE_URI = _baseURI;
              REVEALED = _revealed;
          }
      
          function contractURI() public view returns (string memory) {
              return CONTRACT_URI;
          }
      
          function setContractURI(string memory _contractURI) public onlyOwner {
              CONTRACT_URI = _contractURI;
          }
      
          function setCOLLECTIONsIZE(uint256 _new) external onlyOwner {
              COLLECTION_SIZE = _new;
          }
      
          function setPrice(uint256 _newPrice) external onlyOwner {
              MINT_PRICE = _newPrice;
          }
      
          function set_FREE_SUPPLY_PER_WALLET(uint256 _new) external onlyOwner {
              FREE_SUPPLY_PER_WALLET = _new;
          }
      
          function set_SUPPLY_PER_WALLET(uint256 _new) external onlyOwner {
              SUPPLY_PER_WALLET = _new;
          }
      
          function set_MAX_BATCH_SIZE(uint256 _new) external onlyOwner {
              MAX_BATCH_SIZE = _new;
          }
      
          function transferFrom(address from, address to, uint256 tokenId) public payable override (ERC721A, IERC721A) onlyAllowedOperator {
              super.transferFrom(from, to, tokenId);
          }
      
          function safeTransferFrom(address from, address to, uint256 tokenId) public payable override (ERC721A, IERC721A) onlyAllowedOperator {
              super.safeTransferFrom(from, to, tokenId);
          }
      
          function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data)
              public payable
              override (ERC721A, IERC721A)
              onlyAllowedOperator
          {
              super.safeTransferFrom(from, to, tokenId, data);
          }
      
          function tokenURI(uint256 _tokenId)
              public
              view
              override (ERC721A, IERC721A)
              returns (string memory)
          {
              if (REVEALED) {
                  return
                      string(abi.encodePacked(BASE_URI, Strings.toString(_tokenId)));
              } else {
                  return UNREVEALED_URI;
              }
          }
      
      }

      File 2 of 2: OperatorFilterRegistry
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
      pragma solidity ^0.8.0;
      import "../utils/Context.sol";
      /**
       * @dev Contract module which provides a basic access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * By default, the owner account will be the one that deploys the contract. This
       * can later be changed with {transferOwnership}.
       *
       * This module is used through inheritance. It will make available the modifier
       * `onlyOwner`, which can be applied to your functions to restrict their use to
       * the owner.
       */
      abstract contract Ownable is Context {
          address private _owner;
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
          /**
           * @dev Initializes the contract setting the deployer as the initial owner.
           */
          constructor() {
              _transferOwnership(_msgSender());
          }
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              _checkOwner();
              _;
          }
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view virtual returns (address) {
              return _owner;
          }
          /**
           * @dev Throws if the sender is not the owner.
           */
          function _checkOwner() internal view virtual {
              require(owner() == _msgSender(), "Ownable: caller is not the owner");
          }
          /**
           * @dev Leaves the contract without owner. It will not be possible to call
           * `onlyOwner` functions anymore. Can only be called by the current owner.
           *
           * NOTE: Renouncing ownership will leave the contract without an owner,
           * thereby removing any functionality that is only available to the owner.
           */
          function renounceOwnership() public virtual onlyOwner {
              _transferOwnership(address(0));
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public virtual onlyOwner {
              require(newOwner != address(0), "Ownable: new owner is the zero address");
              _transferOwnership(newOwner);
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Internal function without access restriction.
           */
          function _transferOwnership(address newOwner) internal virtual {
              address oldOwner = _owner;
              _owner = newOwner;
              emit OwnershipTransferred(oldOwner, newOwner);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
      pragma solidity ^0.8.0;
      /**
       * @dev Provides information about the current execution context, including the
       * sender of the transaction and its data. While these are generally available
       * via msg.sender and msg.data, they should not be accessed in such a direct
       * manner, since when dealing with meta-transactions the account sending and
       * paying for execution may not be the actual sender (as far as an application
       * is concerned).
       *
       * This contract is only required for intermediate, library-like contracts.
       */
      abstract contract Context {
          function _msgSender() internal view virtual returns (address) {
              return msg.sender;
          }
          function _msgData() internal view virtual returns (bytes calldata) {
              return msg.data;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol)
      // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
      pragma solidity ^0.8.0;
      /**
       * @dev Library for managing
       * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
       * types.
       *
       * Sets have the following properties:
       *
       * - Elements are added, removed, and checked for existence in constant time
       * (O(1)).
       * - Elements are enumerated in O(n). No guarantees are made on the ordering.
       *
       * ```
       * contract Example {
       *     // Add the library methods
       *     using EnumerableSet for EnumerableSet.AddressSet;
       *
       *     // Declare a set state variable
       *     EnumerableSet.AddressSet private mySet;
       * }
       * ```
       *
       * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
       * and `uint256` (`UintSet`) are supported.
       *
       * [WARNING]
       * ====
       * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
       * unusable.
       * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
       *
       * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
       * array of EnumerableSet.
       * ====
       */
      library EnumerableSet {
          // To implement this library for multiple types with as little code
          // repetition as possible, we write it in terms of a generic Set type with
          // bytes32 values.
          // The Set implementation uses private functions, and user-facing
          // implementations (such as AddressSet) are just wrappers around the
          // underlying Set.
          // This means that we can only create new EnumerableSets for types that fit
          // in bytes32.
          struct Set {
              // Storage of set values
              bytes32[] _values;
              // Position of the value in the `values` array, plus 1 because index 0
              // means a value is not in the set.
              mapping(bytes32 => uint256) _indexes;
          }
          /**
           * @dev Add a value to a set. O(1).
           *
           * Returns true if the value was added to the set, that is if it was not
           * already present.
           */
          function _add(Set storage set, bytes32 value) private returns (bool) {
              if (!_contains(set, value)) {
                  set._values.push(value);
                  // The value is stored at length-1, but we add 1 to all indexes
                  // and use 0 as a sentinel value
                  set._indexes[value] = set._values.length;
                  return true;
              } else {
                  return false;
              }
          }
          /**
           * @dev Removes a value from a set. O(1).
           *
           * Returns true if the value was removed from the set, that is if it was
           * present.
           */
          function _remove(Set storage set, bytes32 value) private returns (bool) {
              // We read and store the value's index to prevent multiple reads from the same storage slot
              uint256 valueIndex = set._indexes[value];
              if (valueIndex != 0) {
                  // Equivalent to contains(set, value)
                  // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                  // the array, and then remove the last element (sometimes called as 'swap and pop').
                  // This modifies the order of the array, as noted in {at}.
                  uint256 toDeleteIndex = valueIndex - 1;
                  uint256 lastIndex = set._values.length - 1;
                  if (lastIndex != toDeleteIndex) {
                      bytes32 lastValue = set._values[lastIndex];
                      // Move the last value to the index where the value to delete is
                      set._values[toDeleteIndex] = lastValue;
                      // Update the index for the moved value
                      set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
                  }
                  // Delete the slot where the moved value was stored
                  set._values.pop();
                  // Delete the index for the deleted slot
                  delete set._indexes[value];
                  return true;
              } else {
                  return false;
              }
          }
          /**
           * @dev Returns true if the value is in the set. O(1).
           */
          function _contains(Set storage set, bytes32 value) private view returns (bool) {
              return set._indexes[value] != 0;
          }
          /**
           * @dev Returns the number of values on the set. O(1).
           */
          function _length(Set storage set) private view returns (uint256) {
              return set._values.length;
          }
          /**
           * @dev Returns the value stored at position `index` in the set. O(1).
           *
           * Note that there are no guarantees on the ordering of values inside the
           * array, and it may change when more values are added or removed.
           *
           * Requirements:
           *
           * - `index` must be strictly less than {length}.
           */
          function _at(Set storage set, uint256 index) private view returns (bytes32) {
              return set._values[index];
          }
          /**
           * @dev Return the entire set in an array
           *
           * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
           * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
           * this function has an unbounded cost, and using it as part of a state-changing function may render the function
           * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
           */
          function _values(Set storage set) private view returns (bytes32[] memory) {
              return set._values;
          }
          // Bytes32Set
          struct Bytes32Set {
              Set _inner;
          }
          /**
           * @dev Add a value to a set. O(1).
           *
           * Returns true if the value was added to the set, that is if it was not
           * already present.
           */
          function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
              return _add(set._inner, value);
          }
          /**
           * @dev Removes a value from a set. O(1).
           *
           * Returns true if the value was removed from the set, that is if it was
           * present.
           */
          function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
              return _remove(set._inner, value);
          }
          /**
           * @dev Returns true if the value is in the set. O(1).
           */
          function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
              return _contains(set._inner, value);
          }
          /**
           * @dev Returns the number of values in the set. O(1).
           */
          function length(Bytes32Set storage set) internal view returns (uint256) {
              return _length(set._inner);
          }
          /**
           * @dev Returns the value stored at position `index` in the set. O(1).
           *
           * Note that there are no guarantees on the ordering of values inside the
           * array, and it may change when more values are added or removed.
           *
           * Requirements:
           *
           * - `index` must be strictly less than {length}.
           */
          function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
              return _at(set._inner, index);
          }
          /**
           * @dev Return the entire set in an array
           *
           * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
           * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
           * this function has an unbounded cost, and using it as part of a state-changing function may render the function
           * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
           */
          function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
              bytes32[] memory store = _values(set._inner);
              bytes32[] memory result;
              /// @solidity memory-safe-assembly
              assembly {
                  result := store
              }
              return result;
          }
          // AddressSet
          struct AddressSet {
              Set _inner;
          }
          /**
           * @dev Add a value to a set. O(1).
           *
           * Returns true if the value was added to the set, that is if it was not
           * already present.
           */
          function add(AddressSet storage set, address value) internal returns (bool) {
              return _add(set._inner, bytes32(uint256(uint160(value))));
          }
          /**
           * @dev Removes a value from a set. O(1).
           *
           * Returns true if the value was removed from the set, that is if it was
           * present.
           */
          function remove(AddressSet storage set, address value) internal returns (bool) {
              return _remove(set._inner, bytes32(uint256(uint160(value))));
          }
          /**
           * @dev Returns true if the value is in the set. O(1).
           */
          function contains(AddressSet storage set, address value) internal view returns (bool) {
              return _contains(set._inner, bytes32(uint256(uint160(value))));
          }
          /**
           * @dev Returns the number of values in the set. O(1).
           */
          function length(AddressSet storage set) internal view returns (uint256) {
              return _length(set._inner);
          }
          /**
           * @dev Returns the value stored at position `index` in the set. O(1).
           *
           * Note that there are no guarantees on the ordering of values inside the
           * array, and it may change when more values are added or removed.
           *
           * Requirements:
           *
           * - `index` must be strictly less than {length}.
           */
          function at(AddressSet storage set, uint256 index) internal view returns (address) {
              return address(uint160(uint256(_at(set._inner, index))));
          }
          /**
           * @dev Return the entire set in an array
           *
           * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
           * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
           * this function has an unbounded cost, and using it as part of a state-changing function may render the function
           * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
           */
          function values(AddressSet storage set) internal view returns (address[] memory) {
              bytes32[] memory store = _values(set._inner);
              address[] memory result;
              /// @solidity memory-safe-assembly
              assembly {
                  result := store
              }
              return result;
          }
          // UintSet
          struct UintSet {
              Set _inner;
          }
          /**
           * @dev Add a value to a set. O(1).
           *
           * Returns true if the value was added to the set, that is if it was not
           * already present.
           */
          function add(UintSet storage set, uint256 value) internal returns (bool) {
              return _add(set._inner, bytes32(value));
          }
          /**
           * @dev Removes a value from a set. O(1).
           *
           * Returns true if the value was removed from the set, that is if it was
           * present.
           */
          function remove(UintSet storage set, uint256 value) internal returns (bool) {
              return _remove(set._inner, bytes32(value));
          }
          /**
           * @dev Returns true if the value is in the set. O(1).
           */
          function contains(UintSet storage set, uint256 value) internal view returns (bool) {
              return _contains(set._inner, bytes32(value));
          }
          /**
           * @dev Returns the number of values in the set. O(1).
           */
          function length(UintSet storage set) internal view returns (uint256) {
              return _length(set._inner);
          }
          /**
           * @dev Returns the value stored at position `index` in the set. O(1).
           *
           * Note that there are no guarantees on the ordering of values inside the
           * array, and it may change when more values are added or removed.
           *
           * Requirements:
           *
           * - `index` must be strictly less than {length}.
           */
          function at(UintSet storage set, uint256 index) internal view returns (uint256) {
              return uint256(_at(set._inner, index));
          }
          /**
           * @dev Return the entire set in an array
           *
           * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
           * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
           * this function has an unbounded cost, and using it as part of a state-changing function may render the function
           * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
           */
          function values(UintSet storage set) internal view returns (uint256[] memory) {
              bytes32[] memory store = _values(set._inner);
              uint256[] memory result;
              /// @solidity memory-safe-assembly
              assembly {
                  result := store
              }
              return result;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.13;
      import {EnumerableSet} from "openzeppelin-contracts/utils/structs/EnumerableSet.sol";
      interface IOperatorFilterRegistry {
          function isOperatorAllowed(address registrant, address operator) external returns (bool);
          function register(address registrant) external;
          function registerAndSubscribe(address registrant, address subscription) external;
          function registerAndCopyEntries(address registrant, address registrantToCopy) external;
          function updateOperator(address registrant, address operator, bool filtered) external;
          function updateOperators(address registrant, address[] calldata operators, bool filtered) external;
          function updateCodeHash(address registrant, bytes32 codehash, bool filtered) external;
          function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) external;
          function subscribe(address registrant, address registrantToSubscribe) external;
          function unsubscribe(address registrant, bool copyExistingEntries) external;
          function subscriptionOf(address addr) external returns (address registrant);
          function subscribers(address registrant) external returns (address[] memory);
          function subscriberAt(address registrant, uint256 index) external returns (address);
          function copyEntriesOf(address registrant, address registrantToCopy) external;
          function isOperatorFiltered(address registrant, address operator) external returns (bool);
          function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool);
          function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool);
          function filteredOperators(address addr) external returns (address[] memory);
          function filteredCodeHashes(address addr) external returns (bytes32[] memory);
          function filteredOperatorAt(address registrant, uint256 index) external returns (address);
          function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32);
          function isRegistered(address addr) external returns (bool);
          function codeHashOf(address addr) external returns (bytes32);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.13;
      import {IOperatorFilterRegistry} from "./IOperatorFilterRegistry.sol";
      import {Ownable} from "openzeppelin-contracts/access/Ownable.sol";
      import {EnumerableSet} from "openzeppelin-contracts/utils/structs/EnumerableSet.sol";
      import {OperatorFilterRegistryErrorsAndEvents} from "./OperatorFilterRegistryErrorsAndEvents.sol";
      /**
       * @title  OperatorFilterRegistry
       * @notice Borrows heavily from the QQL BlacklistOperatorFilter contract:
       *         https://github.com/qql-art/contracts/blob/main/contracts/BlacklistOperatorFilter.sol
       * @notice This contracts allows tokens or token owners to register specific addresses or codeHashes that may be
       * *       restricted according to the isOperatorAllowed function.
       */
      contract OperatorFilterRegistry is IOperatorFilterRegistry, OperatorFilterRegistryErrorsAndEvents {
          using EnumerableSet for EnumerableSet.AddressSet;
          using EnumerableSet for EnumerableSet.Bytes32Set;
          /// @dev initialized accounts have a nonzero codehash (see https://eips.ethereum.org/EIPS/eip-1052)
          /// Note that this will also be a smart contract's codehash when making calls from its constructor.
          bytes32 constant EOA_CODEHASH = keccak256("");
          mapping(address => EnumerableSet.AddressSet) private _filteredOperators;
          mapping(address => EnumerableSet.Bytes32Set) private _filteredCodeHashes;
          mapping(address => address) private _registrations;
          mapping(address => EnumerableSet.AddressSet) private _subscribers;
          /**
           * @notice restricts method caller to the address or EIP-173 "owner()"
           */
          modifier onlyAddressOrOwner(address addr) {
              if (msg.sender != addr) {
                  try Ownable(addr).owner() returns (address owner) {
                      if (msg.sender != owner) {
                          revert OnlyAddressOrOwner();
                      }
                  } catch (bytes memory reason) {
                      if (reason.length == 0) {
                          revert NotOwnable();
                      } else {
                          /// @solidity memory-safe-assembly
                          assembly {
                              revert(add(32, reason), mload(reason))
                          }
                      }
                  }
              }
              _;
          }
          /**
           * @notice Returns true if operator is not filtered for a given token, either by address or codeHash. Also returns
           *         true if supplied registrant address is not registered.
           */
          function isOperatorAllowed(address registrant, address operator) external view returns (bool) {
              address registration = _registrations[registrant];
              if (registration != address(0)) {
                  EnumerableSet.AddressSet storage filteredOperatorsRef;
                  EnumerableSet.Bytes32Set storage filteredCodeHashesRef;
                  filteredOperatorsRef = _filteredOperators[registration];
                  filteredCodeHashesRef = _filteredCodeHashes[registration];
                  if (filteredOperatorsRef.contains(operator)) {
                      revert AddressFiltered(operator);
                  }
                  if (operator.code.length > 0) {
                      bytes32 codeHash = operator.codehash;
                      if (filteredCodeHashesRef.contains(codeHash)) {
                          revert CodeHashFiltered(operator, codeHash);
                      }
                  }
              }
              return true;
          }
          //////////////////
          // AUTH METHODS //
          //////////////////
          /**
           * @notice Registers an address with the registry. May be called by address itself or by EIP-173 owner.
           */
          function register(address registrant) external onlyAddressOrOwner(registrant) {
              if (_registrations[registrant] != address(0)) {
                  revert AlreadyRegistered();
              }
              _registrations[registrant] = registrant;
              emit RegistrationUpdated(registrant, true);
          }
          /**
           * @notice Unregisters an address with the registry and removes its subscription. May be called by address itself or by EIP-173 owner.
           *         Note that this does not remove any filtered addresses or codeHashes.
           *         Also note that any subscriptions to this registrant will still be active and follow the existing filtered addresses and codehashes.
           */
          function unregister(address registrant) external onlyAddressOrOwner(registrant) {
              address registration = _registrations[registrant];
              if (registration == address(0)) {
                  revert NotRegistered(registrant);
              }
              if (registration != registrant) {
                  _subscribers[registration].remove(registrant);
                  emit SubscriptionUpdated(registrant, registration, false);
              }
              _registrations[registrant] = address(0);
              emit RegistrationUpdated(registrant, false);
          }
          /**
           * @notice Registers an address with the registry and "subscribes" to another address's filtered operators and codeHashes.
           */
          function registerAndSubscribe(address registrant, address subscription) external onlyAddressOrOwner(registrant) {
              address registration = _registrations[registrant];
              if (registration != address(0)) {
                  revert AlreadyRegistered();
              }
              if (registrant == subscription) {
                  revert CannotSubscribeToSelf();
              }
              address subscriptionRegistration = _registrations[subscription];
              if (subscriptionRegistration == address(0)) {
                  revert NotRegistered(subscription);
              }
              if (subscriptionRegistration != subscription) {
                  revert CannotSubscribeToRegistrantWithSubscription(subscription);
              }
              _registrations[registrant] = subscription;
              _subscribers[subscription].add(registrant);
              emit RegistrationUpdated(registrant, true);
              emit SubscriptionUpdated(registrant, subscription, true);
          }
          /**
           * @notice Registers an address with the registry and copies the filtered operators and codeHashes from another
           *         address without subscribing.
           */
          function registerAndCopyEntries(address registrant, address registrantToCopy)
              external
              onlyAddressOrOwner(registrant)
          {
              if (registrantToCopy == registrant) {
                  revert CannotCopyFromSelf();
              }
              address registration = _registrations[registrant];
              if (registration != address(0)) {
                  revert AlreadyRegistered();
              }
              address registrantRegistration = _registrations[registrantToCopy];
              if (registrantRegistration == address(0)) {
                  revert NotRegistered(registrantToCopy);
              }
              _registrations[registrant] = registrant;
              emit RegistrationUpdated(registrant, true);
              _copyEntries(registrant, registrantToCopy);
          }
          /**
           * @notice Update an operator address for a registered address - when filtered is true, the operator is filtered.
           */
          function updateOperator(address registrant, address operator, bool filtered)
              external
              onlyAddressOrOwner(registrant)
          {
              address registration = _registrations[registrant];
              if (registration == address(0)) {
                  revert NotRegistered(registrant);
              }
              if (registration != registrant) {
                  revert CannotUpdateWhileSubscribed(registration);
              }
              EnumerableSet.AddressSet storage filteredOperatorsRef = _filteredOperators[registrant];
              if (!filtered) {
                  bool removed = filteredOperatorsRef.remove(operator);
                  if (!removed) {
                      revert AddressNotFiltered(operator);
                  }
              } else {
                  bool added = filteredOperatorsRef.add(operator);
                  if (!added) {
                      revert AddressAlreadyFiltered(operator);
                  }
              }
              emit OperatorUpdated(registrant, operator, filtered);
          }
          /**
           * @notice Update a codeHash for a registered address - when filtered is true, the codeHash is filtered.
           */
          function updateCodeHash(address registrant, bytes32 codeHash, bool filtered)
              external
              onlyAddressOrOwner(registrant)
          {
              if (codeHash == EOA_CODEHASH) {
                  revert CannotFilterEOAs();
              }
              address registration = _registrations[registrant];
              if (registration == address(0)) {
                  revert NotRegistered(registrant);
              }
              if (registration != registrant) {
                  revert CannotUpdateWhileSubscribed(registration);
              }
              EnumerableSet.Bytes32Set storage filteredCodeHashesRef = _filteredCodeHashes[registrant];
              if (!filtered) {
                  bool removed = filteredCodeHashesRef.remove(codeHash);
                  if (!removed) {
                      revert CodeHashNotFiltered(codeHash);
                  }
              } else {
                  bool added = filteredCodeHashesRef.add(codeHash);
                  if (!added) {
                      revert CodeHashAlreadyFiltered(codeHash);
                  }
              }
              emit CodeHashUpdated(registrant, codeHash, filtered);
          }
          /**
           * @notice Update multiple operators for a registered address - when filtered is true, the operators will be filtered. Reverts on duplicates.
           */
          function updateOperators(address registrant, address[] calldata operators, bool filtered)
              external
              onlyAddressOrOwner(registrant)
          {
              address registration = _registrations[registrant];
              if (registration == address(0)) {
                  revert NotRegistered(registrant);
              }
              if (registration != registrant) {
                  revert CannotUpdateWhileSubscribed(registration);
              }
              EnumerableSet.AddressSet storage filteredOperatorsRef = _filteredOperators[registrant];
              uint256 operatorsLength = operators.length;
              unchecked {
                  if (!filtered) {
                      for (uint256 i = 0; i < operatorsLength; ++i) {
                          address operator = operators[i];
                          bool removed = filteredOperatorsRef.remove(operator);
                          if (!removed) {
                              revert AddressNotFiltered(operator);
                          }
                      }
                  } else {
                      for (uint256 i = 0; i < operatorsLength; ++i) {
                          address operator = operators[i];
                          bool added = filteredOperatorsRef.add(operator);
                          if (!added) {
                              revert AddressAlreadyFiltered(operator);
                          }
                      }
                  }
              }
              emit OperatorsUpdated(registrant, operators, filtered);
          }
          /**
           * @notice Update multiple codeHashes for a registered address - when filtered is true, the codeHashes will be filtered. Reverts on duplicates.
           */
          function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered)
              external
              onlyAddressOrOwner(registrant)
          {
              address registration = _registrations[registrant];
              if (registration == address(0)) {
                  revert NotRegistered(registrant);
              }
              if (registration != registrant) {
                  revert CannotUpdateWhileSubscribed(registration);
              }
              EnumerableSet.Bytes32Set storage filteredCodeHashesRef = _filteredCodeHashes[registrant];
              uint256 codeHashesLength = codeHashes.length;
              unchecked {
                  if (!filtered) {
                      for (uint256 i = 0; i < codeHashesLength; ++i) {
                          bytes32 codeHash = codeHashes[i];
                          bool removed = filteredCodeHashesRef.remove(codeHash);
                          if (!removed) {
                              revert CodeHashNotFiltered(codeHash);
                          }
                      }
                  } else {
                      for (uint256 i = 0; i < codeHashesLength; ++i) {
                          bytes32 codeHash = codeHashes[i];
                          if (codeHash == EOA_CODEHASH) {
                              revert CannotFilterEOAs();
                          }
                          bool added = filteredCodeHashesRef.add(codeHash);
                          if (!added) {
                              revert CodeHashAlreadyFiltered(codeHash);
                          }
                      }
                  }
              }
              emit CodeHashesUpdated(registrant, codeHashes, filtered);
          }
          /**
           * @notice Subscribe an address to another registrant's filtered operators and codeHashes. Will remove previous
           *         subscription if present.
           *         Note that accounts with subscriptions may go on to subscribe to other accounts - in this case,
           *         subscriptions will not be forwarded. Instead the former subscription's existing entries will still be
           *         used.
           */
          function subscribe(address registrant, address newSubscription) external onlyAddressOrOwner(registrant) {
              if (registrant == newSubscription) {
                  revert CannotSubscribeToSelf();
              }
              if (newSubscription == address(0)) {
                  revert CannotSubscribeToZeroAddress();
              }
              address registration = _registrations[registrant];
              if (registration == address(0)) {
                  revert NotRegistered(registrant);
              }
              if (registration == newSubscription) {
                  revert AlreadySubscribed(newSubscription);
              }
              address newSubscriptionRegistration = _registrations[newSubscription];
              if (newSubscriptionRegistration == address(0)) {
                  revert NotRegistered(newSubscription);
              }
              if (newSubscriptionRegistration != newSubscription) {
                  revert CannotSubscribeToRegistrantWithSubscription(newSubscription);
              }
              if (registration != registrant) {
                  _subscribers[registration].remove(registrant);
                  emit SubscriptionUpdated(registrant, registration, false);
              }
              _registrations[registrant] = newSubscription;
              _subscribers[newSubscription].add(registrant);
              emit SubscriptionUpdated(registrant, newSubscription, true);
          }
          /**
           * @notice Unsubscribe an address from its current subscribed registrant, and optionally copy its filtered operators and codeHashes.
           */
          function unsubscribe(address registrant, bool copyExistingEntries) external onlyAddressOrOwner(registrant) {
              address registration = _registrations[registrant];
              if (registration == address(0)) {
                  revert NotRegistered(registrant);
              }
              if (registration == registrant) {
                  revert NotSubscribed();
              }
              _subscribers[registration].remove(registrant);
              _registrations[registrant] = registrant;
              emit SubscriptionUpdated(registrant, registration, false);
              if (copyExistingEntries) {
                  _copyEntries(registrant, registration);
              }
          }
          /**
           * @notice Copy filtered operators and codeHashes from a different registrantToCopy to addr.
           */
          function copyEntriesOf(address registrant, address registrantToCopy) external onlyAddressOrOwner(registrant) {
              if (registrant == registrantToCopy) {
                  revert CannotCopyFromSelf();
              }
              address registration = _registrations[registrant];
              if (registration == address(0)) {
                  revert NotRegistered(registrant);
              }
              if (registration != registrant) {
                  revert CannotUpdateWhileSubscribed(registration);
              }
              address registrantRegistration = _registrations[registrantToCopy];
              if (registrantRegistration == address(0)) {
                  revert NotRegistered(registrantToCopy);
              }
              _copyEntries(registrant, registrantToCopy);
          }
          /// @dev helper to copy entries from registrantToCopy to registrant and emit events
          function _copyEntries(address registrant, address registrantToCopy) private {
              EnumerableSet.AddressSet storage filteredOperatorsRef = _filteredOperators[registrantToCopy];
              EnumerableSet.Bytes32Set storage filteredCodeHashesRef = _filteredCodeHashes[registrantToCopy];
              uint256 filteredOperatorsLength = filteredOperatorsRef.length();
              uint256 filteredCodeHashesLength = filteredCodeHashesRef.length();
              unchecked {
                  for (uint256 i = 0; i < filteredOperatorsLength; ++i) {
                      address operator = filteredOperatorsRef.at(i);
                      bool added = _filteredOperators[registrant].add(operator);
                      if (added) {
                          emit OperatorUpdated(registrant, operator, true);
                      }
                  }
                  for (uint256 i = 0; i < filteredCodeHashesLength; ++i) {
                      bytes32 codehash = filteredCodeHashesRef.at(i);
                      bool added = _filteredCodeHashes[registrant].add(codehash);
                      if (added) {
                          emit CodeHashUpdated(registrant, codehash, true);
                      }
                  }
              }
          }
          //////////////////
          // VIEW METHODS //
          //////////////////
          /**
           * @notice Get the subscription address of a given registrant, if any.
           */
          function subscriptionOf(address registrant) external view returns (address subscription) {
              subscription = _registrations[registrant];
              if (subscription == address(0)) {
                  revert NotRegistered(registrant);
              } else if (subscription == registrant) {
                  subscription = address(0);
              }
          }
          /**
           * @notice Get the set of addresses subscribed to a given registrant.
           *         Note that order is not guaranteed as updates are made.
           */
          function subscribers(address registrant) external view returns (address[] memory) {
              return _subscribers[registrant].values();
          }
          /**
           * @notice Get the subscriber at a given index in the set of addresses subscribed to a given registrant.
           *         Note that order is not guaranteed as updates are made.
           */
          function subscriberAt(address registrant, uint256 index) external view returns (address) {
              return _subscribers[registrant].at(index);
          }
          /**
           * @notice Returns true if operator is filtered by a given address or its subscription.
           */
          function isOperatorFiltered(address registrant, address operator) external view returns (bool) {
              address registration = _registrations[registrant];
              if (registration != registrant) {
                  return _filteredOperators[registration].contains(operator);
              }
              return _filteredOperators[registrant].contains(operator);
          }
          /**
           * @notice Returns true if a codeHash is filtered by a given address or its subscription.
           */
          function isCodeHashFiltered(address registrant, bytes32 codeHash) external view returns (bool) {
              address registration = _registrations[registrant];
              if (registration != registrant) {
                  return _filteredCodeHashes[registration].contains(codeHash);
              }
              return _filteredCodeHashes[registrant].contains(codeHash);
          }
          /**
           * @notice Returns true if the hash of an address's code is filtered by a given address or its subscription.
           */
          function isCodeHashOfFiltered(address registrant, address operatorWithCode) external view returns (bool) {
              bytes32 codeHash = operatorWithCode.codehash;
              address registration = _registrations[registrant];
              if (registration != registrant) {
                  return _filteredCodeHashes[registration].contains(codeHash);
              }
              return _filteredCodeHashes[registrant].contains(codeHash);
          }
          /**
           * @notice Returns true if an address has registered
           */
          function isRegistered(address registrant) external view returns (bool) {
              return _registrations[registrant] != address(0);
          }
          /**
           * @notice Returns a list of filtered operators for a given address or its subscription.
           */
          function filteredOperators(address registrant) external view returns (address[] memory) {
              address registration = _registrations[registrant];
              if (registration != registrant) {
                  return _filteredOperators[registration].values();
              }
              return _filteredOperators[registrant].values();
          }
          /**
           * @notice Returns the set of filtered codeHashes for a given address or its subscription.
           *         Note that order is not guaranteed as updates are made.
           */
          function filteredCodeHashes(address registrant) external view returns (bytes32[] memory) {
              address registration = _registrations[registrant];
              if (registration != registrant) {
                  return _filteredCodeHashes[registration].values();
              }
              return _filteredCodeHashes[registrant].values();
          }
          /**
           * @notice Returns the filtered operator at the given index of the set of filtered operators for a given address or
           *         its subscription.
           *         Note that order is not guaranteed as updates are made.
           */
          function filteredOperatorAt(address registrant, uint256 index) external view returns (address) {
              address registration = _registrations[registrant];
              if (registration != registrant) {
                  return _filteredOperators[registration].at(index);
              }
              return _filteredOperators[registrant].at(index);
          }
          /**
           * @notice Returns the filtered codeHash at the given index of the list of filtered codeHashes for a given address or
           *         its subscription.
           *         Note that order is not guaranteed as updates are made.
           */
          function filteredCodeHashAt(address registrant, uint256 index) external view returns (bytes32) {
              address registration = _registrations[registrant];
              if (registration != registrant) {
                  return _filteredCodeHashes[registration].at(index);
              }
              return _filteredCodeHashes[registrant].at(index);
          }
          /// @dev Convenience method to compute the code hash of an arbitrary contract
          function codeHashOf(address a) external view returns (bytes32) {
              return a.codehash;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.13;
      contract OperatorFilterRegistryErrorsAndEvents {
          error CannotFilterEOAs();
          error AddressAlreadyFiltered(address operator);
          error AddressNotFiltered(address operator);
          error CodeHashAlreadyFiltered(bytes32 codeHash);
          error CodeHashNotFiltered(bytes32 codeHash);
          error OnlyAddressOrOwner();
          error NotRegistered(address registrant);
          error AlreadyRegistered();
          error AlreadySubscribed(address subscription);
          error NotSubscribed();
          error CannotUpdateWhileSubscribed(address subscription);
          error CannotSubscribeToSelf();
          error CannotSubscribeToZeroAddress();
          error NotOwnable();
          error AddressFiltered(address filtered);
          error CodeHashFiltered(address account, bytes32 codeHash);
          error CannotSubscribeToRegistrantWithSubscription(address registrant);
          error CannotCopyFromSelf();
          event RegistrationUpdated(address indexed registrant, bool indexed registered);
          event OperatorUpdated(address indexed registrant, address indexed operator, bool indexed filtered);
          event OperatorsUpdated(address indexed registrant, address[] operators, bool indexed filtered);
          event CodeHashUpdated(address indexed registrant, bytes32 indexed codeHash, bool indexed filtered);
          event CodeHashesUpdated(address indexed registrant, bytes32[] codeHashes, bool indexed filtered);
          event SubscriptionUpdated(address indexed registrant, address indexed subscription, bool indexed subscribed);
      }