MegaBadgeImplV1

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/MegaBadgeImplV1.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {ERC1155Upgradeable} from "@openzeppelin-upgradeable/contracts/token/ERC1155/ERC1155Upgradeable.sol";
import {Initializable} from "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol";
import {UUPSUpgradeable} from "@openzeppelin-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/PausableUpgradeable.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {MegaBadgeManagement} from "./MegaBadgeManagement.sol";

/*
                                 ##########################################
                               #############################################
                            #################################################
                          ##########                                    #####
                       ############                                     #####
                   ################                                     #####
              #####################                                     #####
       ############################                                     #####
   ################################                                     #####
  #################################                                     #####
  #################################                                     #####
  #################################           ######     ######         #####
  #################################           ######     #######        #####
  #################################           ######     #######        #####
  #################################           ######     #######        #####
  #################################            ####       #####         #####
  #################################                                     #####
  #################################                                     #####
  #################################                                     #####
   ################################                                     #####
       ############################                                     #####
       ######  ####################                                     #####
       ######    ##################                                     #####
       ################  ####################################################
       ###############       ###############################################
        #############            ##########################################
*/

/**
 * @title MegaBadgeImplV1
 * @notice Implementation contract for Megaphone Registration Badges.
 */
/// @custom:oz-upgrades-from src/MegaBadgeImplV1.sol:MegaBadgeImplV1
contract MegaBadgeImplV1 is
    Initializable,
    ERC1155Upgradeable,
    UUPSUpgradeable,
    PausableUpgradeable,
    MegaBadgeManagement
{
    // Events
    event ContractInitialized(
        address indexed owner,
        address indexed platform,
        address platformTreasury,
        uint256 defaultPlatformFee,
        string uri
    );
    event CustomPlatformFeeSet(uint256 indexed tokenId, uint256 fee);
    event DefaultPlatformFeeSet(uint256 fee);
    event MaxMintCountForTokenIdSet(uint256 indexed tokenId, uint256 maxMintCount);
    event MaxMintCountPerAddressSet(uint256 indexed tokenId, uint256 maxMintsAllowed);
    event MintLaunched(
        uint256 indexed tokenId,
        address indexed mintPriceRecipient,
        uint256 mintPrice,
        uint256 customPlatformFee,
        bool isSoulbound
    );
    event MintPriceSet(uint256 indexed tokenId, uint256 price);
    event MintPriceRecipientSet(uint256 indexed tokenId, address recipient);
    event PlatformTreasurySet(address indexed platformTreasury);
    event SoulboundStatusSet(uint256 indexed tokenId, bool status);
    event StartTimeSet(uint256 indexed tokenId, uint256 _startTime);
    event EndTimeSet(uint256 indexed tokenId, uint256 _endTime);
    event PlatformOwnershipTransferred(address indexed previousPlatform, address indexed newPlatform);

    /**
     * @notice Initializes the contract setting the platformTreasury, defaultPlatformFee and the URI for the ERC1155 token.
     * @param _owner The address to set as the owner. If zero address, defaults to _msgSender().
     * @param _platform The address to set as the Megaphone backend admin.
     * @param _platformTreasury The address of the Megaphone treasury.
     * @param _defaultPlatformFee The default Megaphone service fee.
     * @param _uri The URI for the ERC1155 token.
     */
    function initialize(
        address _owner,
        address _platform,
        address _platformTreasury,
        uint256 _defaultPlatformFee,
        string memory _uri
    ) public initializer {
        require(_platformTreasury != address(0), "Platform treasury cannot be zero address");

        __ERC1155_init(_uri);
        address _o = _owner != address(0) ? _owner : _msgSender();
        __Ownable_init(_o);
        __UUPSUpgradeable_init();
        __Pausable_init();

        PlatformManagementStorage storage $P = _getPlatformManagementStorage();
        $P.platform = _platform;
        $P.platformTreasury = _platformTreasury;
        $P.defaultPlatformFee = _defaultPlatformFee;

        emit ContractInitialized(_owner, _platform, _platformTreasury, _defaultPlatformFee, _uri);
    }

    /**
     * @notice Throws if the proxy upgrade is called by any account other than the owner.
     */
    function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}

    /**
     * @notice Transfer Megaphone Platform address to a new address.
     * @param newPlatformAddress The new address to transfer the Megaphone platform admin to.
     */
    function transferPlatformOwnership(address newPlatformAddress) public onlyOwner {
        PlatformManagementStorage storage $P = _getPlatformManagementStorage();
        address oldPlatformAddress = $P.platform;
        $P.platform = newPlatformAddress;
        emit PlatformOwnershipTransferred(oldPlatformAddress, newPlatformAddress);
    }

    function _processPayment(uint256 _tokenId, uint256 _amount) internal {
        require(msg.value >= _totalFee(_tokenId) * _amount, "Wrong amount of ETH sent");

        // Transfer mintprice.
        uint256 mintprice = mintPrice(_tokenId);
        address recipient = mintPriceRecipient(_tokenId);
        address platformTreasury = platformTreasury();
        uint256 remaining = msg.value;
        if (mintprice > 0 && recipient != address(0)) {
            remaining -= mintprice;
            (bool sent,) = recipient.call{value: mintprice}("");
            require(sent, "Failed to send Ether");
        }

        if (remaining > 0) {
            (bool sent,) = platformTreasury.call{value: remaining}("");
            require(sent, "Failed to send Ether");
        }
    }

    function _mintTokens(address _to, uint256 _tokenId, uint256 _amount, bytes calldata _data) private {
        // Check mint status.
        uint256 s = startTime(_tokenId);
        require(s != 0 && block.timestamp >= s, "Minting not started");
        uint256 e = endTime(_tokenId);
        require(e == 0 || block.timestamp <= e, "Minting ended");

        // Check max supply per tokenId.
        uint256 maxPerToken = maxMintCountPerTokenId(_tokenId);
        uint256 currentSupply = totalSupply(_tokenId);
        require(maxPerToken == 0 || currentSupply + _amount <= maxPerToken, "Reached max supply for tokenId");

        // Check max mints per address.
        uint256 currentMintCount = mintCount(_tokenId, _to);
        uint256 maxPerAddress = maxMintCountPerAddress(_tokenId);
        require(maxPerAddress == 0 || currentMintCount + _amount <= maxPerAddress, "Reached max mints for address");

        // Process the mint fee payment.
        _processPayment(_tokenId, _amount);

        // Increment total supply and mint count.
        MintStatusStorage storage $MS = _getMintStatusStorage();
        $MS.totalSupply[_tokenId] = currentSupply + _amount;
        $MS.mintCount[_tokenId][_to] = currentMintCount + _amount;

        // Mint the tokens.
        _mint(_to, _tokenId, _amount, _data);
    }

    /**
     * @notice Mints a new token to the caller of the mint function.
     * @param _tokenId The ID of the token to mint.
     * @param _amount The number of tokens to mint.
     * @param _data Additional data with no specified format.
     */
    function mint(uint256 _tokenId, uint256 _amount, bytes calldata _data) public payable whenNotPaused {
        _mintTokens(_msgSender(), _tokenId, _amount, _data);
    }

    /**
     * @notice Configure an optional max limit on the number of possible mints per
     * tokenId. If 0 (default), then we assume no cap.
     * @param tokenId The ID of the token to set the max mint count for.
     * @param maxMintCount The max mint count to set.
     */
    function setMaxMintCountForTokenId(uint256 tokenId, uint256 maxMintCount) public onlyPlatformOrOwner {
        MintStatusStorage storage $MS = _getMintStatusStorage();
        require(
            maxMintCount == 0 || maxMintCount >= $MS.totalSupply[tokenId],
            "Max mint count cannot be less than totalSupply"
        );
        $MS.maxMintCountPerTokenId[tokenId] = maxMintCount;
        emit MaxMintCountForTokenIdSet(tokenId, maxMintCount);
    }

    /**
     * @notice Update the max mints allowed for any given address on a token id.
     * @param tokenId The ID of the token to set the max mint count for.
     * @param maxMintsAllowed The max mint count to set.
     */
    function setMaxMintCountForAddress(uint256 tokenId, uint256 maxMintsAllowed) public onlyPlatformOrOwner {
        MintStatusStorage storage $MS = _getMintStatusStorage();
        if ($MS.totalSupply[tokenId] > 0) {
            require(
                maxMintsAllowed >= $MS.maxMintCountPerAddress[tokenId],
                "Only increases are supported once minting has begun"
            );
        }
        $MS.maxMintCountPerAddress[tokenId] = maxMintsAllowed;
        emit MaxMintCountPerAddressSet(tokenId, maxMintsAllowed);
    }

    /**
     * @notice Returns the next tokenId to be launched, and then increments the pointer.
     * @return The tokenId to be launched.
     */
    function _useNextTokenId() internal returns (uint256) {
        MintStatusStorage storage $MS = _getMintStatusStorage();
        uint256 currentId = $MS.nextTokenId;
        $MS.nextTokenId++;
        return currentId;
    }

    /**
     * @notice Launches a new mint.
     * @param mintPrice The price of the mint.
     * @param mintPriceRecipient The address to receive the mint price.
     * @param startTime The start time of the mint.
     * @param endTime The end time of the mint.
     * @param customPlatformFee The custom platform fee.
     * @param isSoulbound The soulbound status of the mint.
     * @return The tokenId of the newly launched token.
     */
    function launchMint(
        uint256 mintPrice,
        address mintPriceRecipient,
        uint256 startTime,
        uint256 endTime,
        uint256 customPlatformFee,
        bool isSoulbound
    ) public onlyPlatformOrOwner returns (uint256) {
        require(startTime > 0, "startTime must be non-zero");
        return _launchMint(mintPrice, mintPriceRecipient, startTime, endTime, customPlatformFee, isSoulbound);
    }

    function _launchMint(
        uint256 mintPrice,
        address mintPriceRecipient,
        uint256 startTime,
        uint256 endTime,
        uint256 customPlatformFee,
        bool isSoulbound
    ) internal returns (uint256) {
        require(startTime > 0, "startTime must be non-zero");
        uint256 id = _useNextTokenId();
        // Additional price to charge for the mint beyond the platform fee.
        if (mintPrice > 0) _setMintPrice(id, mintPrice);
        // Address to receive the mintPrice.
        if (mintPriceRecipient != address(0)) _setMintPriceRecipient(id, mintPriceRecipient);
        // Start time of the mint.
        _setStartTime(id, startTime);
        // End time of the mint.
        if (endTime > 0) _setEndTime(id, endTime);
        // Custom platform fee to charge for the mint.
        if (customPlatformFee > 0) _setCustomPlatformFee(id, customPlatformFee);
        // Soulbound status of the mint.
        if (isSoulbound) _setSoulbound(id, isSoulbound);
        emit MintLaunched(id, mintPriceRecipient, mintPrice, customPlatformFee, isSoulbound);
        return id;
    }

    /**
     * @notice Sets the mint price for a token ID.
     * @param id The ID of the token to set the mint price for.
     * @param price The price to set.
     */
    function setMintPrice(uint256 id, uint256 price) public onlyPlatformOrOwner {
        _setMintPrice(id, price);
    }

    function _setMintPrice(uint256 id, uint256 price) internal {
        MintPriceStorage storage $MP = _getMintPriceStorage();
        $MP.mintPrice[id] = price;
        emit MintPriceSet(id, price);
    }

    /**
     * @notice Sets the mint price recipient for a token ID.
     * @param id The ID of the token to set the mint price recipient for.
     * @param recipient The address to set as the mint price recipient.
     */
    function setMintPriceRecipient(uint256 id, address recipient) public onlyPlatformOrOwner {
        _setMintPriceRecipient(id, recipient);
    }

    function _setMintPriceRecipient(uint256 id, address recipient) internal {
        MintPriceStorage storage $MP = _getMintPriceStorage();
        $MP.mintPriceRecipient[id] = recipient;
        emit MintPriceRecipientSet(id, recipient);
    }

    /**
     * @notice Returns the platform fee for a token ID. If customPlatformFee is 0, then use default fee.
     * @param tokenId The ID of the token to return the platform fee for.
     * @return uint256 representing the platform fee.
     */
    function getPlatformFee(uint256 tokenId) public view returns (uint256) {
        MintPriceStorage storage $MP = _getMintPriceStorage();
        return $MP.customPlatformFee[tokenId] != 0 ? $MP.customPlatformFee[tokenId] : defaultPlatformFee();
    }

    /**
     * @notice Sets the platform fee for a token ID.
     * @param tokenId The ID of the token to set the platform fee for.
     * @param fee The platform fee to set.
     */
    function setCustomPlatformFee(uint256 tokenId, uint256 fee) public onlyPlatformOrOwner {
        _setCustomPlatformFee(tokenId, fee);
    }

    function _setCustomPlatformFee(uint256 id, uint256 fee) internal {
        MintPriceStorage storage $MP = _getMintPriceStorage();
        $MP.customPlatformFee[id] = fee;
        emit CustomPlatformFeeSet(id, fee);
    }

    /**
     * @notice Updates the default platform fee for all token IDs.
     * @param fee The new default platform fee.
     */
    function setDefaultPlatformFee(uint256 fee) public onlyPlatformOrOwner {
        PlatformManagementStorage storage $P = _getPlatformManagementStorage();
        $P.defaultPlatformFee = fee;
        emit DefaultPlatformFeeSet(fee);
    }

    /**
     * @notice Returns the total fee for a token ID.
     * @param _id The ID of the token to return the total fee for.
     * @param _amount The amount of tokens to return the total fee for.
     * @return uint256 representing the total fee.
     */
    function totalFee(uint256 _id, uint256 _amount) public view returns (uint256) {
        return _totalFee(_id) * _amount;
    }

    function _totalFee(uint256 _tokenId) internal view returns (uint256) {
        MintPriceStorage storage $MP = _getMintPriceStorage();
        uint256 _mintPrice = $MP.mintPrice[_tokenId];
        uint256 _customPlatformFee = $MP.customPlatformFee[_tokenId];

        if (_customPlatformFee == 0) {
            return _mintPrice + defaultPlatformFee();
        }
        return _mintPrice + _customPlatformFee;
    }

    /**
     * @notice Sets the platform treasury address.
     * @param _platformTreasury The address to set as the platform treasury payout address.
     */
    function setPlatformTreasury(address _platformTreasury) public onlyOwner {
        require(_platformTreasury != address(0), "Platform treasury cannot be zero address");
        PlatformManagementStorage storage $P = _getPlatformManagementStorage();
        $P.platformTreasury = _platformTreasury;
        emit PlatformTreasurySet(_platformTreasury);
    }

    function setStartTime(uint256 id, uint256 _startTime) public onlyPlatformOrOwner {
        _setStartTime(id, _startTime);
    }

    function _setStartTime(uint256 id, uint256 _startTime) internal {
        MintTimingStorage storage $MT = _getMintTimingStorage();
        $MT.startTime[id] = _startTime;
        emit StartTimeSet(id, _startTime);
    }

    function setEndTime(uint256 id, uint256 _endTime) public onlyPlatformOrOwner {
        _setEndTime(id, _endTime);
    }

    function _setEndTime(uint256 id, uint256 _endTime) internal {
        MintTimingStorage storage $MT = _getMintTimingStorage();
        $MT.endTime[id] = _endTime;
        emit EndTimeSet(id, _endTime);
    }

    /**
     * @notice Sets the base URI for the metadata.
     *
     * We expect base uri to be in a format like this: https://badges.megaphone.xyz/v1/chain/:chainId
     * Note: no trailing backslash
     *
     * @param newuri The new base URI.
     */
    function setBaseURI(string memory newuri) public onlyOwner {
        _setURI(newuri);
    }

    /**
     * @notice Returns the URI for the contract's metadata: https://badges.megaphone.xyz/v1/chain/:chainId
     * @return A string representing the URI.
     */
    function contractURI() public view returns (string memory) {
        return super.uri(0);
    }

    /**
     * @notice Returns the URI for a token ID: https://badges.megaphone.xyz/v1/chain/:chainId/token/:tokenId
     *
     * We expect base uri to be in a format like this: https://badges.megaphone.xyz/v1/chain/:chainId
     * Note: no trailing backslash
     *
     * @param id The ID of the token to return the URI for.
     * @return A string representing the URI.
     */
    function uri(uint256 id) public view override returns (string memory) {
        require(id < nextTokenId(), "Unlaunched tokenId");
        return string(abi.encodePacked(super.uri(id), "/token/", Strings.toString(id)));
    }

    /**
     * @notice Burns a token. The sender must have enough tokens to burn.
     * @param id The ID of the token to burn.
     * @param amount The amount of tokens to burn.
     */
    function burn(uint256 id, uint256 amount) public {
        address account = _msgSender();

        // Call the inherited _burn function
        super._burn(account, id, amount);
    }

    /**
     * @notice Sets the soulbound status of a token ID.
     * @param tokenId The ID of the token to set the soulbound status for.
     * @param status The soulbound status to set.
     */
    function setSoulbound(uint256 tokenId, bool status) public onlyPlatformOrOwner {
        _setSoulbound(tokenId, status);
    }

    function _setSoulbound(uint256 tokenId, bool status) internal {
        MintStatusStorage storage $MS = _getMintStatusStorage();
        $MS.isSoulbound[tokenId] = status;
        emit SoulboundStatusSet(tokenId, status);
    }

    /**
     * @notice Override the _update function to implement soulbound check based on isSoulbound status per tokenId.
     */
    function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal override {
        MintStatusStorage storage $MS = _getMintStatusStorage();
        for (uint256 i = 0; i < ids.length; ++i) {
            uint256 id = ids[i];
            if ($MS.isSoulbound[id]) {
                require(from == address(0) || to == address(0), "Soulbound token id cannot be transferred.");
            }
        }
        super._update(from, to, ids, values);
    }

    /**
     * @notice Triggers stop state on the contract. The main thing we care about
     * pausing is all mints across all tokenIds. Useful for emergency situations.
     */
    function pause() public onlyOwner {
        _pause();
    }

    /**
     * @notice Triggers start state on the contract. The main thing we care about
     * unpausing is all mints across all tokenIds.
     */
    function unpause() public onlyOwner {
        _unpause();
    }

    struct TokenInfo {
        // Minting
        uint256 mintPrice;
        address mintPriceRecipient;
        uint256 customPlatformFee;
        uint256 totalFee;
        // Timing
        uint256 startTime;
        uint256 endTime;
        // Supply & limits
        uint256 totalSupply;
        uint256 maxMintCountPerTokenId;
        uint256 maxMintCountPerAddress;
        // Status
        bool isSoulbound;
        // computed: tokenId < nextTokenId
        bool isLaunched;
    }

    /**
     * @notice Convenience helper to return token info for a single tokenId.
     * @param tokenId The ID of the token to return the info for.
     * @return TokenInfo struct containing the token info.
     */
    function getTokenInfo(uint256 tokenId) external view returns (TokenInfo memory) {
        return _getTokenInfo(tokenId);
    }

    /**
     * @notice Convenience helper to return token info for a batch of tokenIds.
     * @param tokenIds The IDs of the tokens to return the info for.
     * @return TokenInfo[] array of TokenInfo structs containing the token info.
     */
    function getTokenInfo(uint256[] calldata tokenIds) external view returns (TokenInfo[] memory) {
        TokenInfo[] memory infos = new TokenInfo[](tokenIds.length);
        for (uint256 i = 0; i < tokenIds.length; i++) {
            infos[i] = _getTokenInfo(tokenIds[i]);
        }
        return infos;
    }

    function _getTokenInfo(uint256 tokenId) internal view returns (TokenInfo memory) {
        MintPriceStorage storage $MP = _getMintPriceStorage();
        MintTimingStorage storage $MT = _getMintTimingStorage();
        MintStatusStorage storage $MS = _getMintStatusStorage();

        uint256 start = $MT.startTime[tokenId];
        uint256 end = $MT.endTime[tokenId];

        return TokenInfo({
            mintPrice: $MP.mintPrice[tokenId],
            mintPriceRecipient: $MP.mintPriceRecipient[tokenId],
            customPlatformFee: $MP.customPlatformFee[tokenId],
            totalFee: _totalFee(tokenId),
            startTime: start,
            endTime: end,
            totalSupply: $MS.totalSupply[tokenId],
            maxMintCountPerTokenId: $MS.maxMintCountPerTokenId[tokenId],
            maxMintCountPerAddress: $MS.maxMintCountPerAddress[tokenId],
            isSoulbound: $MS.isSoulbound[tokenId],
            isLaunched: tokenId < $MS.nextTokenId
        });
    }

    struct UserInfo {
        // how many tokens the user currently has for this tokenId
        uint256 userCurrentBalance;
        // how many times the user has minted this tokenId
        uint256 userMintCount;
    }

    /**
     * @notice Convenience helper to return user info for a single tokenId.
     * @param tokenId The ID of the token to return the user info for.
     * @param user The address of the user to return the info for.
     * @return UserInfo struct containing the user info.
     */
    function getUserInfo(uint256 tokenId, address user) external view returns (UserInfo memory) {
        return _getUserInfo(tokenId, user);
    }

    function _getUserInfo(uint256 tokenId, address user) internal view returns (UserInfo memory) {
        uint256 userMintCount = mintCount(tokenId, user);
        uint256 userBalance = balanceOf(user, tokenId);
        return UserInfo({userCurrentBalance: userBalance, userMintCount: userMintCount});
    }

    /**
     * @notice Returns the contract name.
     */
    function name() public pure returns (string memory) {
        return "Megaphone Registration Badge";
    }

    /**
     * @notice Returns the contract symbol.
     */
    function symbol() public pure returns (string memory) {
        return "MB";
    }
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC1155/ERC1155Upgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/ERC1155.sol)

pragma solidity ^0.8.20;

import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import {IERC1155MetadataURI} from "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../../utils/introspection/ERC165Upgradeable.sol";
import {Arrays} from "@openzeppelin/contracts/utils/Arrays.sol";
import {IERC1155Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the basic standard multi-token.
 * See https://eips.ethereum.org/EIPS/eip-1155
 * Originally based on code by Enjin: https://github.com/enjin/erc-1155
 */
abstract contract ERC1155Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC1155, IERC1155MetadataURI, IERC1155Errors {
    using Arrays for uint256[];
    using Arrays for address[];

    /// @custom:storage-location erc7201:openzeppelin.storage.ERC1155
    struct ERC1155Storage {
        mapping(uint256 id => mapping(address account => uint256)) _balances;

        mapping(address account => mapping(address operator => bool)) _operatorApprovals;

        // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
        string _uri;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC1155")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant ERC1155StorageLocation = 0x88be536d5240c274a3b1d3a1be54482fd9caa294f08c62a7cde569f49a3c4500;

    function _getERC1155Storage() private pure returns (ERC1155Storage storage $) {
        assembly {
            $.slot := ERC1155StorageLocation
        }
    }

    /**
     * @dev See {_setURI}.
     */
    function __ERC1155_init(string memory uri_) internal onlyInitializing {
        __ERC1155_init_unchained(uri_);
    }

    function __ERC1155_init_unchained(string memory uri_) internal onlyInitializing {
        _setURI(uri_);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165) returns (bool) {
        return
            interfaceId == type(IERC1155).interfaceId ||
            interfaceId == type(IERC1155MetadataURI).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC1155MetadataURI-uri}.
     *
     * This implementation returns the same URI for *all* token types. It relies
     * on the token type ID substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * Clients calling this function must replace the `\{id\}` substring with the
     * actual token type ID.
     */
    function uri(uint256 /* id */) public view virtual returns (string memory) {
        ERC1155Storage storage $ = _getERC1155Storage();
        return $._uri;
    }

    /**
     * @dev See {IERC1155-balanceOf}.
     */
    function balanceOf(address account, uint256 id) public view virtual returns (uint256) {
        ERC1155Storage storage $ = _getERC1155Storage();
        return $._balances[id][account];
    }

    /**
     * @dev See {IERC1155-balanceOfBatch}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] memory accounts,
        uint256[] memory ids
    ) public view virtual returns (uint256[] memory) {
        if (accounts.length != ids.length) {
            revert ERC1155InvalidArrayLength(ids.length, accounts.length);
        }

        uint256[] memory batchBalances = new uint256[](accounts.length);

        for (uint256 i = 0; i < accounts.length; ++i) {
            batchBalances[i] = balanceOf(accounts.unsafeMemoryAccess(i), ids.unsafeMemoryAccess(i));
        }

        return batchBalances;
    }

    /**
     * @dev See {IERC1155-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC1155-isApprovedForAll}.
     */
    function isApprovedForAll(address account, address operator) public view virtual returns (bool) {
        ERC1155Storage storage $ = _getERC1155Storage();
        return $._operatorApprovals[account][operator];
    }

    /**
     * @dev See {IERC1155-safeTransferFrom}.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public virtual {
        address sender = _msgSender();
        if (from != sender && !isApprovedForAll(from, sender)) {
            revert ERC1155MissingApprovalForAll(sender, from);
        }
        _safeTransferFrom(from, to, id, value, data);
    }

    /**
     * @dev See {IERC1155-safeBatchTransferFrom}.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) public virtual {
        address sender = _msgSender();
        if (from != sender && !isApprovedForAll(from, sender)) {
            revert ERC1155MissingApprovalForAll(sender, from);
        }
        _safeBatchTransferFrom(from, to, ids, values, data);
    }

    /**
     * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from`
     * (or `to`) is the zero address.
     *
     * Emits a {TransferSingle} event if the arrays contain one element, and {TransferBatch} otherwise.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement either {IERC1155Receiver-onERC1155Received}
     *   or {IERC1155Receiver-onERC1155BatchReceived} and return the acceptance magic value.
     * - `ids` and `values` must have the same length.
     *
     * NOTE: The ERC-1155 acceptance check is not performed in this function. See {_updateWithAcceptanceCheck} instead.
     */
    function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual {
        ERC1155Storage storage $ = _getERC1155Storage();
        if (ids.length != values.length) {
            revert ERC1155InvalidArrayLength(ids.length, values.length);
        }

        address operator = _msgSender();

        for (uint256 i = 0; i < ids.length; ++i) {
            uint256 id = ids.unsafeMemoryAccess(i);
            uint256 value = values.unsafeMemoryAccess(i);

            if (from != address(0)) {
                uint256 fromBalance = $._balances[id][from];
                if (fromBalance < value) {
                    revert ERC1155InsufficientBalance(from, fromBalance, value, id);
                }
                unchecked {
                    // Overflow not possible: value <= fromBalance
                    $._balances[id][from] = fromBalance - value;
                }
            }

            if (to != address(0)) {
                $._balances[id][to] += value;
            }
        }

        if (ids.length == 1) {
            uint256 id = ids.unsafeMemoryAccess(0);
            uint256 value = values.unsafeMemoryAccess(0);
            emit TransferSingle(operator, from, to, id, value);
        } else {
            emit TransferBatch(operator, from, to, ids, values);
        }
    }

    /**
     * @dev Version of {_update} that performs the token acceptance check by calling
     * {IERC1155Receiver-onERC1155Received} or {IERC1155Receiver-onERC1155BatchReceived} on the receiver address if it
     * contains code (eg. is a smart contract at the moment of execution).
     *
     * IMPORTANT: Overriding this function is discouraged because it poses a reentrancy risk from the receiver. So any
     * update to the contract state after this function would break the check-effect-interaction pattern. Consider
     * overriding {_update} instead.
     */
    function _updateWithAcceptanceCheck(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) internal virtual {
        _update(from, to, ids, values);
        if (to != address(0)) {
            address operator = _msgSender();
            if (ids.length == 1) {
                uint256 id = ids.unsafeMemoryAccess(0);
                uint256 value = values.unsafeMemoryAccess(0);
                _doSafeTransferAcceptanceCheck(operator, from, to, id, value, data);
            } else {
                _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, values, data);
            }
        }
    }

    /**
     * @dev Transfers a `value` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `from` must have a balance of tokens of type `id` of at least `value` amount.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
        _updateWithAcceptanceCheck(from, to, ids, values, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     * - `ids` and `values` must have the same length.
     */
    function _safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        _updateWithAcceptanceCheck(from, to, ids, values, data);
    }

    /**
     * @dev Sets a new URI for all token types, by relying on the token type ID
     * substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * By this mechanism, any occurrence of the `\{id\}` substring in either the
     * URI or any of the values in the JSON file at said URI will be replaced by
     * clients with the token type ID.
     *
     * For example, the `https://token-cdn-domain/\{id\}.json` URI would be
     * interpreted by clients as
     * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
     * for token type ID 0x4cce0.
     *
     * See {uri}.
     *
     * Because these URIs cannot be meaningfully represented by the {URI} event,
     * this function emits no events.
     */
    function _setURI(string memory newuri) internal virtual {
        ERC1155Storage storage $ = _getERC1155Storage();
        $._uri = newuri;
    }

    /**
     * @dev Creates a `value` amount of tokens of type `id`, and assigns them to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _mint(address to, uint256 id, uint256 value, bytes memory data) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
        _updateWithAcceptanceCheck(address(0), to, ids, values, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `values` must have the same length.
     * - `to` cannot be the zero address.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        _updateWithAcceptanceCheck(address(0), to, ids, values, data);
    }

    /**
     * @dev Destroys a `value` amount of tokens of type `id` from `from`
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have at least `value` amount of tokens of type `id`.
     */
    function _burn(address from, uint256 id, uint256 value) internal {
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
        _updateWithAcceptanceCheck(from, address(0), ids, values, "");
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have at least `value` amount of tokens of type `id`.
     * - `ids` and `values` must have the same length.
     */
    function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal {
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        _updateWithAcceptanceCheck(from, address(0), ids, values, "");
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the zero address.
     */
    function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
        ERC1155Storage storage $ = _getERC1155Storage();
        if (operator == address(0)) {
            revert ERC1155InvalidOperator(address(0));
        }
        $._operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Performs an acceptance check by calling {IERC1155-onERC1155Received} on the `to` address
     * if it contains code at the moment of execution.
     */
    function _doSafeTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256 id,
        uint256 value,
        bytes memory data
    ) private {
        if (to.code.length > 0) {
            try IERC1155Receiver(to).onERC1155Received(operator, from, id, value, data) returns (bytes4 response) {
                if (response != IERC1155Receiver.onERC1155Received.selector) {
                    // Tokens rejected
                    revert ERC1155InvalidReceiver(to);
                }
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    // non-ERC1155Receiver implementer
                    revert ERC1155InvalidReceiver(to);
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        }
    }

    /**
     * @dev Performs a batch acceptance check by calling {IERC1155-onERC1155BatchReceived} on the `to` address
     * if it contains code at the moment of execution.
     */
    function _doSafeBatchTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) private {
        if (to.code.length > 0) {
            try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, values, data) returns (
                bytes4 response
            ) {
                if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
                    // Tokens rejected
                    revert ERC1155InvalidReceiver(to);
                }
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    // non-ERC1155Receiver implementer
                    revert ERC1155InvalidReceiver(to);
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        }
    }

    /**
     * @dev Creates an array in memory with only one value for each of the elements provided.
     */
    function _asSingletonArrays(
        uint256 element1,
        uint256 element2
    ) private pure returns (uint256[] memory array1, uint256[] memory array2) {
        /// @solidity memory-safe-assembly
        assembly {
            // Load the free memory pointer
            array1 := mload(0x40)
            // Set array length to 1
            mstore(array1, 1)
            // Store the single element at the next word after the length (where content starts)
            mstore(add(array1, 0x20), element1)

            // Repeat for next array locating it right after the first array
            array2 := add(array1, 0x40)
            mstore(array2, 1)
            mstore(add(array2, 0x20), element2)

            // Update the free memory pointer by pointing after the second array
            mstore(0x40, add(array2, 0x40))
        }
    }
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.20;

import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 */
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
    address private immutable __self = address(this);

    /**
     * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
     * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
     * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
     * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
     * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
     * during an upgrade.
     */
    string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";

    /**
     * @dev The call is from an unauthorized context.
     */
    error UUPSUnauthorizedCallContext();

    /**
     * @dev The storage `slot` is unsupported as a UUID.
     */
    error UUPSUnsupportedProxiableUUID(bytes32 slot);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        _checkProxy();
        _;
    }

    /**
     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
     * callable on the implementing contract but not through proxies.
     */
    modifier notDelegated() {
        _checkNotDelegated();
        _;
    }

    function __UUPSUpgradeable_init() internal onlyInitializing {
    }

    function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
     * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
     */
    function proxiableUUID() external view virtual notDelegated returns (bytes32) {
        return ERC1967Utils.IMPLEMENTATION_SLOT;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     *
     * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, data);
    }

    /**
     * @dev Reverts if the execution is not performed via delegatecall or the execution
     * context is not of a proxy with an ERC1967-compliant implementation pointing to self.
     * See {_onlyProxy}.
     */
    function _checkProxy() internal view virtual {
        if (
            address(this) == __self || // Must be called through delegatecall
            ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
        ) {
            revert UUPSUnauthorizedCallContext();
        }
    }

    /**
     * @dev Reverts if the execution is performed via delegatecall.
     * See {notDelegated}.
     */
    function _checkNotDelegated() internal view virtual {
        if (address(this) != __self) {
            // Must not be called through delegatecall
            revert UUPSUnauthorizedCallContext();
        }
    }

    /**
     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
     * {upgradeToAndCall}.
     *
     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
     *
     * ```solidity
     * function _authorizeUpgrade(address) internal onlyOwner {}
     * ```
     */
    function _authorizeUpgrade(address newImplementation) internal virtual;

    /**
     * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
     *
     * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
     * is expected to be the implementation slot in ERC1967.
     *
     * Emits an {IERC1967-Upgraded} event.
     */
    function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
        try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
            if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
                revert UUPSUnsupportedProxiableUUID(slot);
            }
            ERC1967Utils.upgradeToAndCall(newImplementation, data);
        } catch {
            // The implementation is not UUPS
            revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
        }
    }
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/contracts/utils/PausableUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)

pragma solidity ^0.8.20;

import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
    /// @custom:storage-location erc7201:openzeppelin.storage.Pausable
    struct PausableStorage {
        bool _paused;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;

    function _getPausableStorage() private pure returns (PausableStorage storage $) {
        assembly {
            $.slot := PausableStorageLocation
        }
    }

    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

    /**
     * @dev Initializes the contract in unpaused state.
     */
    function __Pausable_init() internal onlyInitializing {
        __Pausable_init_unchained();
    }

    function __Pausable_init_unchained() internal onlyInitializing {
        PausableStorage storage $ = _getPausableStorage();
        $._paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        PausableStorage storage $ = _getPausableStorage();
        return $._paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        PausableStorage storage $ = _getPausableStorage();
        $._paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        PausableStorage storage $ = _getPausableStorage();
        $._paused = false;
        emit Unpaused(_msgSender());
    }
}
"
    },
    "lib/openzeppelin-contracts/contracts/utils/Strings.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }\

Tags:
ERC1155, ERC165, Multisig, Non-Fungible, Upgradeable, Multi-Signature, Factory|addr:0xf1ced1c0cfe7c03a10c5140287c248c009c3a06f|verified:true|block:23634697|tx:0xd2eea6e6e4e123cea5f26b1a5d65bfbec3aa602ec6dda71acbc8a65484e55e3c|first_check:1761291818

Submitted on: 2025-10-24 09:43:41

Comments

Log in to comment.

No comments yet.