ETH Price: $2,545.95 (+0.06%)

Transaction Decoder

Block:
21914821 at Feb-24-2025 07:53:59 AM +UTC
Transaction Fee:
0.0004696656228144 ETH $1.20
Gas Used:
412,128 Gas / 1.13961105 Gwei

Emitted Events:

99 Mint721.OwnershipTransferred( oldOwner=0x00000000...000000000, newOwner=[Sender] 0xe9a0dc0783f504dd71e67d3cda208856d7ba6355 )
100 Mint721.MetadataRendererUpdated( renderer=IPFSEditionRenderer )
101 Mint721.ModuleAdded( module=BasicMintModule )
102 BasicMintModule.ConfigurationUpdated( _contract=Mint721, _config=[{name:price, type:uint256, order:1, indexed:false, value:577000000000000, valueString:577000000000000}, {name:mintStart, type:uint64, order:2, indexed:false, value:0, valueString:0}, {name:mintEnd, type:uint64, order:3, indexed:false, value:1740988397, valueString:1740988397}, {name:maxPerWallet, type:uint32, order:4, indexed:false, value:0, valueString:0}, {name:maxPerTransaction, type:uint32, order:5, indexed:false, value:10, valueString:10}, {name:maxForModule, type:uint32, order:6, indexed:false, value:0, valueString:0}, {name:maxSupply, type:uint32, order:7, indexed:false, value:0, valueString:0}] )
103 IPFSEditionRenderer.ConfigurationUpdated( mintContract=Mint721, config=[{name:tokenName, type:string, order:1, indexed:false, value:test, valueString:test}, {name:tokenDescription, type:string, order:2, indexed:false, value:, valueString:}, {name:imageIPFSHash, type:string, order:3, indexed:false, value:QmcYgsENLB1nbUACbc4BFeb67vD2XzL5hanoDXyHzP9EY4, valueString:QmcYgsENLB1nbUACbc4BFeb67vD2XzL5hanoDXyHzP9EY4}, {name:animationIPFSHash, type:string, order:4, indexed:false, value:, valueString:}, {name:animationMimeType, type:string, order:5, indexed:false, value:, valueString:}] )
104 MintFactory.ContractCreated( _contract=Mint721, _creator=[Sender] 0xe9a0dc0783f504dd71e67d3cda208856d7ba6355 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...06947759C
0x00000000...b03C1F44F
0x00000000...5EA6242ac
0x7B747BAd...88b284583
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 2194563381516407626324453258647895718881490096273196743212749812227806294851905513819536846018595392412659
(beaverbuild)
12.895631273918683134 Eth12.895837337918683134 Eth0.000206064
0xE9a0Dc07...6d7bA6355
0.001636005495679916 Eth
Nonce: 4
0.001166339872865516 Eth
Nonce: 5
0.0004696656228144

Execution Trace

MintFactory.createBasicEdition_efficient_d3ea1b36( mint721Configuration=[{name:name, type:string, order:1, indexed:false, value:test, valueString:test}, {name:symbol, type:string, order:2, indexed:false, value:TES, valueString:TES}], metadataRenderer=0x000000000000771c0DF6De1451d9175b03C1F44F, metadataRendererData=0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000A000000000000000000000000000000000000000000000000000000000000000E0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000474657374000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002E516D63596773454E4C42316E62554143626334424665623637764432587A4C3568616E6F445879487A503945593400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, salt=E9A0DC0783F504DD71E67D3CDA208856D7BA6355AF82409C9D5B1E29314C632A, mintModuleAddresses=[0x000000000f30984DE6843bBC1d109c95EA6242ac], mintModuleData=[AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIMx0gJEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnxV/tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=] )
  • Mint721.602c3d81( )
  • Mint721.initialize( config=[{name:name, type:string, order:1, indexed:false, value:test, valueString:test}, {name:symbol, type:string, order:2, indexed:false, value:TES, valueString:TES}], mintModuleRegistry_=0x0000000000005f12A17E1aF428824484B97a1a82, _metadataRenderer=0x000000000000771c0DF6De1451d9175b03C1F44F, metadataRendererConfig=0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000A000000000000000000000000000000000000000000000000000000000000000E0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000474657374000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002E516D63596773454E4C42316E62554143626334424665623637764432587A4C3568616E6F445879487A503945593400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, mintModules=[0x000000000f30984DE6843bBC1d109c95EA6242ac], mintModuleData=[AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIMx0gJEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnxV/tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=], creator=0xE9a0Dc0783f504DD71e67D3CdA208856d7bA6355 )
    • Mint721.initialize( config=[{name:name, type:string, order:1, indexed:false, value:test, valueString:test}, {name:symbol, type:string, order:2, indexed:false, value:TES, valueString:TES}], mintModuleRegistry_=0x0000000000005f12A17E1aF428824484B97a1a82, _metadataRenderer=0x000000000000771c0DF6De1451d9175b03C1F44F, metadataRendererConfig=0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000A000000000000000000000000000000000000000000000000000000000000000E0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000474657374000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002E516D63596773454E4C42316E62554143626334424665623637764432587A4C3568616E6F445879487A503945593400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, mintModules=[0x000000000f30984DE6843bBC1d109c95EA6242ac], mintModuleData=[AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIMx0gJEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnxV/tAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=], creator=0xE9a0Dc0783f504DD71e67D3CdA208856d7bA6355 )
      • MintModuleRegistry.checkModule( mintModule=0x000000000f30984DE6843bBC1d109c95EA6242ac )
      • BasicMintModule.updateConfiguration( args=0x00000000000000000000000000000000000000000000000000020CC74809100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000067C55FED0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 )
      • IPFSEditionRenderer.updateConfiguration( args=0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000A000000000000000000000000000000000000000000000000000000000000000E0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000474657374000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002E516D63596773454E4C42316E62554143626334424665623637764432587A4C3568616E6F445879487A503945593400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 )
        createBasicEdition_efficient_d3ea1b36[MintFactory (ln:33)]
        File 1 of 6: MintFactory
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {IMetadataRenderer} from "create/interfaces/v1/IMetadataRenderer.sol";
        import {LibClone} from "solady/utils/LibClone.sol";
        import {Ownable} from "solady/auth/Ownable.sol";
        import {Pausable} from "openzeppelin/security/Pausable.sol";
        import {IMintFactory} from "create/interfaces/v1/IMintFactory.sol";
        import {Mint721Configuration} from "create/interfaces/v1/Mint721Configuration.sol";
        import {IMint721} from "create/interfaces/v1/IMint721.sol";
        contract MintFactory is IMintFactory, Ownable, Pausable {
            /// @notice The mint module registry.
            address public mintModuleRegistry;
            /// @notice The implementation of Mint721 to be cloned here.
            address public mint721Implementation;
            error InvalidAddress();
            constructor() {
                _initializeOwner(tx.origin);
            }
            /// @inheritdoc IMintFactory
            function createBasicEdition(
                Mint721Configuration calldata mint721Configuration,
                IMetadataRenderer metadataRenderer,
                bytes calldata metadataRendererData,
                bytes32 salt,
                address[] calldata mintModuleAddresses,
                bytes[] calldata mintModuleData
            ) external returns (address contractAddress) {
                return _createBasicEdtion(
                    mint721Configuration, metadataRenderer, metadataRendererData, salt, mintModuleAddresses, mintModuleData
                );
            }
            /// @inheritdoc IMintFactory
            function createBasicEdition_efficient_d3ea1b36(
                Mint721Configuration calldata mint721Configuration,
                IMetadataRenderer metadataRenderer,
                bytes calldata metadataRendererData,
                bytes32 salt,
                address[] calldata mintModuleAddresses,
                bytes[] calldata mintModuleData
            ) external returns (address contractAddress) {
                return _createBasicEdtion(
                    mint721Configuration, metadataRenderer, metadataRendererData, salt, mintModuleAddresses, mintModuleData
                );
            }
            function _createBasicEdtion(
                Mint721Configuration calldata mint721Configuration,
                IMetadataRenderer metadataRenderer,
                bytes calldata metadataRendererData,
                bytes32 salt,
                address[] calldata mintModuleAddresses,
                bytes[] calldata mintModuleData
            ) internal whenNotPaused returns (address contractAddress) {
                if (address(bytes20(salt)) != msg.sender) revert InvalidSalt();
                contractAddress = LibClone.cloneDeterministic(mint721Implementation, salt);
                IMint721(contractAddress).initialize(
                    mint721Configuration,
                    mintModuleRegistry,
                    metadataRenderer,
                    metadataRendererData,
                    mintModuleAddresses,
                    mintModuleData,
                    msg.sender
                );
                emit ContractCreated(contractAddress, msg.sender);
            }
            /// @inheritdoc IMintFactory
            function updateImplementations(address _mintModuleRegistry, address _mint721Implementation) external onlyOwner {
                if (_mintModuleRegistry == address(0) || _mint721Implementation == address(0)) {
                    revert InvalidAddress();
                }
                mintModuleRegistry = _mintModuleRegistry;
                mint721Implementation = _mint721Implementation;
            }
            function pause() external onlyOwner {
                _pause();
            }
            function unpause() external onlyOwner {
                _unpause();
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        interface IMetadataRenderer {
            /// @notice Retrieves the token URI for the specified token ID.
            /// @param tokenId The ID of the token.
            /// @return uri The URI of the token.
            function tokenURI(uint256 tokenId) external view returns (string memory uri);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.4;
        /// @notice Minimal proxy library.
        /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibClone.sol)
        /// @author Minimal proxy by 0age (https://github.com/0age)
        /// @author Clones with immutable args by wighawag, zefram.eth, Saw-mon & Natalie
        /// (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args)
        ///
        /// @dev Minimal proxy:
        /// Although the sw0nt pattern saves 5 gas over the erc-1167 pattern during runtime,
        /// it is not supported out-of-the-box on Etherscan. Hence, we choose to use the 0age pattern,
        /// which saves 4 gas over the erc-1167 pattern during runtime, and has the smallest bytecode.
        ///
        /// @dev Minimal proxy (PUSH0 variant):
        /// This is a new minimal proxy that uses the PUSH0 opcode introduced during Shanghai.
        /// It is optimized first for minimal runtime gas, then for minimal bytecode.
        /// The PUSH0 clone functions are intentionally postfixed with a jarring "_PUSH0" as
        /// many EVM chains may not support the PUSH0 opcode in the early months after Shanghai.
        /// Please use with caution.
        ///
        /// @dev Clones with immutable args (CWIA):
        /// The implementation of CWIA here implements a `receive()` method that emits the
        /// `ReceiveETH(uint256)` event. This skips the `DELEGATECALL` when there is no calldata,
        /// enabling us to accept hard gas-capped `sends` & `transfers` for maximum backwards
        /// composability. The minimal proxy implementation does not offer this feature.
        library LibClone {
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                       CUSTOM ERRORS                        */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Unable to deploy the clone.
            error DeploymentFailed();
            /// @dev The salt must start with either the zero address or the caller.
            error SaltDoesNotStartWithCaller();
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                  MINIMAL PROXY OPERATIONS                  */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Deploys a clone of `implementation`.
            function clone(address implementation) internal returns (address instance) {
                /// @solidity memory-safe-assembly
                assembly {
                    /**
                     * --------------------------------------------------------------------------+
                     * CREATION (9 bytes)                                                        |
                     * --------------------------------------------------------------------------|
                     * Opcode     | Mnemonic          | Stack     | Memory                       |
                     * --------------------------------------------------------------------------|
                     * 60 runSize | PUSH1 runSize     | r         |                              |
                     * 3d         | RETURNDATASIZE    | 0 r       |                              |
                     * 81         | DUP2              | r 0 r     |                              |
                     * 60 offset  | PUSH1 offset      | o r 0 r   |                              |
                     * 3d         | RETURNDATASIZE    | 0 o r 0 r |                              |
                     * 39         | CODECOPY          | 0 r       | [0..runSize): runtime code   |
                     * f3         | RETURN            |           | [0..runSize): runtime code   |
                     * --------------------------------------------------------------------------|
                     * RUNTIME (44 bytes)                                                        |
                     * --------------------------------------------------------------------------|
                     * Opcode  | Mnemonic       | Stack                  | Memory                |
                     * --------------------------------------------------------------------------|
                     *                                                                           |
                     * ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: |
                     * 3d      | RETURNDATASIZE | 0                      |                       |
                     * 3d      | RETURNDATASIZE | 0 0                    |                       |
                     * 3d      | RETURNDATASIZE | 0 0 0                  |                       |
                     * 3d      | RETURNDATASIZE | 0 0 0 0                |                       |
                     *                                                                           |
                     * ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: |
                     * 36      | CALLDATASIZE   | cds 0 0 0 0            |                       |
                     * 3d      | RETURNDATASIZE | 0 cds 0 0 0 0          |                       |
                     * 3d      | RETURNDATASIZE | 0 0 cds 0 0 0 0        |                       |
                     * 37      | CALLDATACOPY   | 0 0 0 0                | [0..cds): calldata    |
                     *                                                                           |
                     * ::: delegate call to the implementation contract :::::::::::::::::::::::: |
                     * 36      | CALLDATASIZE   | cds 0 0 0 0            | [0..cds): calldata    |
                     * 3d      | RETURNDATASIZE | 0 cds 0 0 0 0          | [0..cds): calldata    |
                     * 73 addr | PUSH20 addr    | addr 0 cds 0 0 0 0     | [0..cds): calldata    |
                     * 5a      | GAS            | gas addr 0 cds 0 0 0 0 | [0..cds): calldata    |
                     * f4      | DELEGATECALL   | success 0 0            | [0..cds): calldata    |
                     *                                                                           |
                     * ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: |
                     * 3d      | RETURNDATASIZE | rds success 0 0        | [0..cds): calldata    |
                     * 3d      | RETURNDATASIZE | rds rds success 0 0    | [0..cds): calldata    |
                     * 93      | SWAP4          | 0 rds success 0 rds    | [0..cds): calldata    |
                     * 80      | DUP1           | 0 0 rds success 0 rds  | [0..cds): calldata    |
                     * 3e      | RETURNDATACOPY | success 0 rds          | [0..rds): returndata  |
                     *                                                                           |
                     * 60 0x2a | PUSH1 0x2a     | 0x2a success 0 rds     | [0..rds): returndata  |
                     * 57      | JUMPI          | 0 rds                  | [0..rds): returndata  |
                     *                                                                           |
                     * ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
                     * fd      | REVERT         |                        | [0..rds): returndata  |
                     *                                                                           |
                     * ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
                     * 5b      | JUMPDEST       | 0 rds                  | [0..rds): returndata  |
                     * f3      | RETURN         |                        | [0..rds): returndata  |
                     * --------------------------------------------------------------------------+
                     */
                    mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
                    mstore(0x14, implementation)
                    mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
                    instance := create(0, 0x0c, 0x35)
                    // If `instance` is zero, revert.
                    if iszero(instance) {
                        // Store the function selector of `DeploymentFailed()`.
                        mstore(0x00, 0x30116425)
                        // Revert with (offset, size).
                        revert(0x1c, 0x04)
                    }
                    // Restore the part of the free memory pointer that has been overwritten.
                    mstore(0x21, 0)
                }
            }
            /// @dev Deploys a deterministic clone of `implementation` with `salt`.
            function cloneDeterministic(address implementation, bytes32 salt)
                internal
                returns (address instance)
            {
                /// @solidity memory-safe-assembly
                assembly {
                    mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
                    mstore(0x14, implementation)
                    mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
                    instance := create2(0, 0x0c, 0x35, salt)
                    // If `instance` is zero, revert.
                    if iszero(instance) {
                        // Store the function selector of `DeploymentFailed()`.
                        mstore(0x00, 0x30116425)
                        // Revert with (offset, size).
                        revert(0x1c, 0x04)
                    }
                    // Restore the part of the free memory pointer that has been overwritten.
                    mstore(0x21, 0)
                }
            }
            /// @dev Returns the initialization code hash of the clone of `implementation`.
            /// Used for mining vanity addresses with create2crunch.
            function initCodeHash(address implementation) internal pure returns (bytes32 hash) {
                /// @solidity memory-safe-assembly
                assembly {
                    mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
                    mstore(0x14, implementation)
                    mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
                    hash := keccak256(0x0c, 0x35)
                    // Restore the part of the free memory pointer that has been overwritten.
                    mstore(0x21, 0)
                }
            }
            /// @dev Returns the address of the deterministic clone of `implementation`,
            /// with `salt` by `deployer`.
            /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
            function predictDeterministicAddress(address implementation, bytes32 salt, address deployer)
                internal
                pure
                returns (address predicted)
            {
                bytes32 hash = initCodeHash(implementation);
                predicted = predictDeterministicAddress(hash, salt, deployer);
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*          MINIMAL PROXY OPERATIONS (PUSH0 VARIANT)          */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Deploys a PUSH0 clone of `implementation`.
            function clone_PUSH0(address implementation) internal returns (address instance) {
                /// @solidity memory-safe-assembly
                assembly {
                    /**
                     * --------------------------------------------------------------------------+
                     * CREATION (9 bytes)                                                        |
                     * --------------------------------------------------------------------------|
                     * Opcode     | Mnemonic          | Stack     | Memory                       |
                     * --------------------------------------------------------------------------|
                     * 60 runSize | PUSH1 runSize     | r         |                              |
                     * 5f         | PUSH0             | 0 r       |                              |
                     * 81         | DUP2              | r 0 r     |                              |
                     * 60 offset  | PUSH1 offset      | o r 0 r   |                              |
                     * 5f         | PUSH0             | 0 o r 0 r |                              |
                     * 39         | CODECOPY          | 0 r       | [0..runSize): runtime code   |
                     * f3         | RETURN            |           | [0..runSize): runtime code   |
                     * --------------------------------------------------------------------------|
                     * RUNTIME (45 bytes)                                                        |
                     * --------------------------------------------------------------------------|
                     * Opcode  | Mnemonic       | Stack                  | Memory                |
                     * --------------------------------------------------------------------------|
                     *                                                                           |
                     * ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: |
                     * 5f      | PUSH0          | 0                      |                       |
                     * 5f      | PUSH0          | 0 0                    |                       |
                     *                                                                           |
                     * ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: |
                     * 36      | CALLDATASIZE   | cds 0 0                |                       |
                     * 5f      | PUSH0          | 0 cds 0 0              |                       |
                     * 5f      | PUSH0          | 0 0 cds 0 0            |                       |
                     * 37      | CALLDATACOPY   | 0 0                    | [0..cds): calldata    |
                     *                                                                           |
                     * ::: delegate call to the implementation contract :::::::::::::::::::::::: |
                     * 36      | CALLDATASIZE   | cds 0 0                | [0..cds): calldata    |
                     * 5f      | PUSH0          | 0 cds 0 0              | [0..cds): calldata    |
                     * 73 addr | PUSH20 addr    | addr 0 cds 0 0         | [0..cds): calldata    |
                     * 5a      | GAS            | gas addr 0 cds 0 0     | [0..cds): calldata    |
                     * f4      | DELEGATECALL   | success                | [0..cds): calldata    |
                     *                                                                           |
                     * ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: |
                     * 3d      | RETURNDATASIZE | rds success            | [0..cds): calldata    |
                     * 5f      | PUSH0          | 0 rds success          | [0..cds): calldata    |
                     * 5f      | PUSH0          | 0 0 rds success        | [0..cds): calldata    |
                     * 3e      | RETURNDATACOPY | success                | [0..rds): returndata  |
                     *                                                                           |
                     * 60 0x29 | PUSH1 0x29     | 0x29 success           | [0..rds): returndata  |
                     * 57      | JUMPI          |                        | [0..rds): returndata  |
                     *                                                                           |
                     * ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
                     * 3d      | RETURNDATASIZE | rds                    | [0..rds): returndata  |
                     * 5f      | PUSH0          | 0 rds                  | [0..rds): returndata  |
                     * fd      | REVERT         |                        | [0..rds): returndata  |
                     *                                                                           |
                     * ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
                     * 5b      | JUMPDEST       |                        | [0..rds): returndata  |
                     * 3d      | RETURNDATASIZE | rds                    | [0..rds): returndata  |
                     * 5f      | PUSH0          | 0 rds                  | [0..rds): returndata  |
                     * f3      | RETURN         |                        | [0..rds): returndata  |
                     * --------------------------------------------------------------------------+
                     */
                    mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
                    mstore(0x14, implementation) // 20
                    mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
                    instance := create(0, 0x0e, 0x36)
                    // If `instance` is zero, revert.
                    if iszero(instance) {
                        // Store the function selector of `DeploymentFailed()`.
                        mstore(0x00, 0x30116425)
                        // Revert with (offset, size).
                        revert(0x1c, 0x04)
                    }
                    // Restore the part of the free memory pointer that has been overwritten.
                    mstore(0x24, 0)
                }
            }
            /// @dev Deploys a deterministic PUSH0 clone of `implementation` with `salt`.
            function cloneDeterministic_PUSH0(address implementation, bytes32 salt)
                internal
                returns (address instance)
            {
                /// @solidity memory-safe-assembly
                assembly {
                    mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
                    mstore(0x14, implementation) // 20
                    mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
                    instance := create2(0, 0x0e, 0x36, salt)
                    // If `instance` is zero, revert.
                    if iszero(instance) {
                        // Store the function selector of `DeploymentFailed()`.
                        mstore(0x00, 0x30116425)
                        // Revert with (offset, size).
                        revert(0x1c, 0x04)
                    }
                    // Restore the part of the free memory pointer that has been overwritten.
                    mstore(0x24, 0)
                }
            }
            /// @dev Returns the initialization code hash of the PUSH0 clone of `implementation`.
            /// Used for mining vanity addresses with create2crunch.
            function initCodeHash_PUSH0(address implementation) internal pure returns (bytes32 hash) {
                /// @solidity memory-safe-assembly
                assembly {
                    mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
                    mstore(0x14, implementation) // 20
                    mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
                    hash := keccak256(0x0e, 0x36)
                    // Restore the part of the free memory pointer that has been overwritten.
                    mstore(0x24, 0)
                }
            }
            /// @dev Returns the address of the deterministic PUSH0 clone of `implementation`,
            /// with `salt` by `deployer`.
            /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
            function predictDeterministicAddress_PUSH0(
                address implementation,
                bytes32 salt,
                address deployer
            ) internal pure returns (address predicted) {
                bytes32 hash = initCodeHash_PUSH0(implementation);
                predicted = predictDeterministicAddress(hash, salt, deployer);
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*           CLONES WITH IMMUTABLE ARGS OPERATIONS            */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Deploys a minimal proxy with `implementation`,
            /// using immutable arguments encoded in `data`.
            ///
            /// Note: This implementation of CWIA differs from the original implementation.
            /// If the calldata is empty, it will emit a `ReceiveETH(uint256)` event and skip the `DELEGATECALL`.
            function clone(address implementation, bytes memory data) internal returns (address instance) {
                assembly {
                    // Compute the boundaries of the data and cache the memory slots around it.
                    let mBefore3 := mload(sub(data, 0x60))
                    let mBefore2 := mload(sub(data, 0x40))
                    let mBefore1 := mload(sub(data, 0x20))
                    let dataLength := mload(data)
                    let dataEnd := add(add(data, 0x20), dataLength)
                    let mAfter1 := mload(dataEnd)
                    // +2 bytes for telling how much data there is appended to the call.
                    let extraLength := add(dataLength, 2)
                    // The `creationSize` is `extraLength + 108`
                    // The `runSize` is `creationSize - 10`.
                    /**
                     * ---------------------------------------------------------------------------------------------------+
                     * CREATION (10 bytes)                                                                                |
                     * ---------------------------------------------------------------------------------------------------|
                     * Opcode     | Mnemonic          | Stack     | Memory                                                |
                     * ---------------------------------------------------------------------------------------------------|
                     * 61 runSize | PUSH2 runSize     | r         |                                                       |
                     * 3d         | RETURNDATASIZE    | 0 r       |                                                       |
                     * 81         | DUP2              | r 0 r     |                                                       |
                     * 60 offset  | PUSH1 offset      | o r 0 r   |                                                       |
                     * 3d         | RETURNDATASIZE    | 0 o r 0 r |                                                       |
                     * 39         | CODECOPY          | 0 r       | [0..runSize): runtime code                            |
                     * f3         | RETURN            |           | [0..runSize): runtime code                            |
                     * ---------------------------------------------------------------------------------------------------|
                     * RUNTIME (98 bytes + extraLength)                                                                   |
                     * ---------------------------------------------------------------------------------------------------|
                     * Opcode   | Mnemonic       | Stack                    | Memory                                      |
                     * ---------------------------------------------------------------------------------------------------|
                     *                                                                                                    |
                     * ::: if no calldata, emit event & return w/o `DELEGATECALL` ::::::::::::::::::::::::::::::::::::::: |
                     * 36       | CALLDATASIZE   | cds                      |                                             |
                     * 60 0x2c  | PUSH1 0x2c     | 0x2c cds                 |                                             |
                     * 57       | JUMPI          |                          |                                             |
                     * 34       | CALLVALUE      | cv                       |                                             |
                     * 3d       | RETURNDATASIZE | 0 cv                     |                                             |
                     * 52       | MSTORE         |                          | [0..0x20): callvalue                        |
                     * 7f sig   | PUSH32 0x9e..  | sig                      | [0..0x20): callvalue                        |
                     * 59       | MSIZE          | 0x20 sig                 | [0..0x20): callvalue                        |
                     * 3d       | RETURNDATASIZE | 0 0x20 sig               | [0..0x20): callvalue                        |
                     * a1       | LOG1           |                          | [0..0x20): callvalue                        |
                     * 00       | STOP           |                          | [0..0x20): callvalue                        |
                     * 5b       | JUMPDEST       |                          |                                             |
                     *                                                                                                    |
                     * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
                     * 36       | CALLDATASIZE   | cds                      |                                             |
                     * 3d       | RETURNDATASIZE | 0 cds                    |                                             |
                     * 3d       | RETURNDATASIZE | 0 0 cds                  |                                             |
                     * 37       | CALLDATACOPY   |                          | [0..cds): calldata                          |
                     *                                                                                                    |
                     * ::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
                     * 3d       | RETURNDATASIZE | 0                        | [0..cds): calldata                          |
                     * 3d       | RETURNDATASIZE | 0 0                      | [0..cds): calldata                          |
                     * 3d       | RETURNDATASIZE | 0 0 0                    | [0..cds): calldata                          |
                     * 3d       | RETURNDATASIZE | 0 0 0 0                  | [0..cds): calldata                          |
                     * 61 extra | PUSH2 extra    | e 0 0 0 0                | [0..cds): calldata                          |
                     *                                                                                                    |
                     * ::: copy extra data to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
                     * 80       | DUP1           | e e 0 0 0 0              | [0..cds): calldata                          |
                     * 60 0x62  | PUSH1 0x62     | 0x62 e e 0 0 0 0         | [0..cds): calldata                          |
                     * 36       | CALLDATASIZE   | cds 0x62 e e 0 0 0 0     | [0..cds): calldata                          |
                     * 39       | CODECOPY       | e 0 0 0 0                | [0..cds): calldata, [cds..cds+e): extraData |
                     *                                                                                                    |
                     * ::: delegate call to the implementation contract ::::::::::::::::::::::::::::::::::::::::::::::::: |
                     * 36       | CALLDATASIZE   | cds e 0 0 0 0            | [0..cds): calldata, [cds..cds+e): extraData |
                     * 01       | ADD            | cds+e 0 0 0 0            | [0..cds): calldata, [cds..cds+e): extraData |
                     * 3d       | RETURNDATASIZE | 0 cds+e 0 0 0 0          | [0..cds): calldata, [cds..cds+e): extraData |
                     * 73 addr  | PUSH20 addr    | addr 0 cds+e 0 0 0 0     | [0..cds): calldata, [cds..cds+e): extraData |
                     * 5a       | GAS            | gas addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
                     * f4       | DELEGATECALL   | success 0 0              | [0..cds): calldata, [cds..cds+e): extraData |
                     *                                                                                                    |
                     * ::: copy return data to memory ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
                     * 3d       | RETURNDATASIZE | rds success 0 0          | [0..cds): calldata, [cds..cds+e): extraData |
                     * 3d       | RETURNDATASIZE | rds rds success 0 0      | [0..cds): calldata, [cds..cds+e): extraData |
                     * 93       | SWAP4          | 0 rds success 0 rds      | [0..cds): calldata, [cds..cds+e): extraData |
                     * 80       | DUP1           | 0 0 rds success 0 rds    | [0..cds): calldata, [cds..cds+e): extraData |
                     * 3e       | RETURNDATACOPY | success 0 rds            | [0..rds): returndata                        |
                     *                                                                                                    |
                     * 60 0x60  | PUSH1 0x60     | 0x60 success 0 rds       | [0..rds): returndata                        |
                     * 57       | JUMPI          | 0 rds                    | [0..rds): returndata                        |
                     *                                                                                                    |
                     * ::: revert ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
                     * fd       | REVERT         |                          | [0..rds): returndata                        |
                     *                                                                                                    |
                     * ::: return ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
                     * 5b       | JUMPDEST       | 0 rds                    | [0..rds): returndata                        |
                     * f3       | RETURN         |                          | [0..rds): returndata                        |
                     * ---------------------------------------------------------------------------------------------------+
                     */
                    // Write the bytecode before the data.
                    mstore(data, 0x5af43d3d93803e606057fd5bf3)
                    // Write the address of the implementation.
                    mstore(sub(data, 0x0d), implementation)
                    // Write the rest of the bytecode.
                    mstore(
                        sub(data, 0x21),
                        or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)
                    )
                    // `keccak256("ReceiveETH(uint256)")`
                    mstore(
                        sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff
                    )
                    mstore(
                        // Do a out-of-gas revert if `extraLength` is too big. 0xffff - 0x62 + 0x01 = 0xff9e.
                        // The actual EVM limit may be smaller and may change over time.
                        sub(data, add(0x59, lt(extraLength, 0xff9e))),
                        or(shl(0x78, add(extraLength, 0x62)), 0xfd6100003d81600a3d39f336602c57343d527f)
                    )
                    mstore(dataEnd, shl(0xf0, extraLength))
                    // Create the instance.
                    instance := create(0, sub(data, 0x4c), add(extraLength, 0x6c))
                    // If `instance` is zero, revert.
                    if iszero(instance) {
                        // Store the function selector of `DeploymentFailed()`.
                        mstore(0x00, 0x30116425)
                        // Revert with (offset, size).
                        revert(0x1c, 0x04)
                    }
                    // Restore the overwritten memory surrounding `data`.
                    mstore(dataEnd, mAfter1)
                    mstore(data, dataLength)
                    mstore(sub(data, 0x20), mBefore1)
                    mstore(sub(data, 0x40), mBefore2)
                    mstore(sub(data, 0x60), mBefore3)
                }
            }
            /// @dev Deploys a deterministic clone of `implementation`,
            /// using immutable arguments encoded in `data`, with `salt`.
            ///
            /// Note: This implementation of CWIA differs from the original implementation.
            /// If the calldata is empty, it will emit a `ReceiveETH(uint256)` event and skip the `DELEGATECALL`.
            function cloneDeterministic(address implementation, bytes memory data, bytes32 salt)
                internal
                returns (address instance)
            {
                assembly {
                    // Compute the boundaries of the data and cache the memory slots around it.
                    let mBefore3 := mload(sub(data, 0x60))
                    let mBefore2 := mload(sub(data, 0x40))
                    let mBefore1 := mload(sub(data, 0x20))
                    let dataLength := mload(data)
                    let dataEnd := add(add(data, 0x20), dataLength)
                    let mAfter1 := mload(dataEnd)
                    // +2 bytes for telling how much data there is appended to the call.
                    let extraLength := add(dataLength, 2)
                    // Write the bytecode before the data.
                    mstore(data, 0x5af43d3d93803e606057fd5bf3)
                    // Write the address of the implementation.
                    mstore(sub(data, 0x0d), implementation)
                    // Write the rest of the bytecode.
                    mstore(
                        sub(data, 0x21),
                        or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)
                    )
                    // `keccak256("ReceiveETH(uint256)")`
                    mstore(
                        sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff
                    )
                    mstore(
                        // Do a out-of-gas revert if `extraLength` is too big. 0xffff - 0x62 + 0x01 = 0xff9e.
                        // The actual EVM limit may be smaller and may change over time.
                        sub(data, add(0x59, lt(extraLength, 0xff9e))),
                        or(shl(0x78, add(extraLength, 0x62)), 0xfd6100003d81600a3d39f336602c57343d527f)
                    )
                    mstore(dataEnd, shl(0xf0, extraLength))
                    // Create the instance.
                    instance := create2(0, sub(data, 0x4c), add(extraLength, 0x6c), salt)
                    // If `instance` is zero, revert.
                    if iszero(instance) {
                        // Store the function selector of `DeploymentFailed()`.
                        mstore(0x00, 0x30116425)
                        // Revert with (offset, size).
                        revert(0x1c, 0x04)
                    }
                    // Restore the overwritten memory surrounding `data`.
                    mstore(dataEnd, mAfter1)
                    mstore(data, dataLength)
                    mstore(sub(data, 0x20), mBefore1)
                    mstore(sub(data, 0x40), mBefore2)
                    mstore(sub(data, 0x60), mBefore3)
                }
            }
            /// @dev Returns the initialization code hash of the clone of `implementation`
            /// using immutable arguments encoded in `data`.
            /// Used for mining vanity addresses with create2crunch.
            function initCodeHash(address implementation, bytes memory data)
                internal
                pure
                returns (bytes32 hash)
            {
                assembly {
                    // Compute the boundaries of the data and cache the memory slots around it.
                    let mBefore3 := mload(sub(data, 0x60))
                    let mBefore2 := mload(sub(data, 0x40))
                    let mBefore1 := mload(sub(data, 0x20))
                    let dataLength := mload(data)
                    let dataEnd := add(add(data, 0x20), dataLength)
                    let mAfter1 := mload(dataEnd)
                    // Do a out-of-gas revert if `dataLength` is too big. 0xffff - 0x02 - 0x62 = 0xff9b.
                    // The actual EVM limit may be smaller and may change over time.
                    returndatacopy(returndatasize(), returndatasize(), gt(dataLength, 0xff9b))
                    // +2 bytes for telling how much data there is appended to the call.
                    let extraLength := add(dataLength, 2)
                    // Write the bytecode before the data.
                    mstore(data, 0x5af43d3d93803e606057fd5bf3)
                    // Write the address of the implementation.
                    mstore(sub(data, 0x0d), implementation)
                    // Write the rest of the bytecode.
                    mstore(
                        sub(data, 0x21),
                        or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)
                    )
                    // `keccak256("ReceiveETH(uint256)")`
                    mstore(
                        sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff
                    )
                    mstore(
                        sub(data, 0x5a),
                        or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f)
                    )
                    mstore(dataEnd, shl(0xf0, extraLength))
                    // Compute and store the bytecode hash.
                    hash := keccak256(sub(data, 0x4c), add(extraLength, 0x6c))
                    // Restore the overwritten memory surrounding `data`.
                    mstore(dataEnd, mAfter1)
                    mstore(data, dataLength)
                    mstore(sub(data, 0x20), mBefore1)
                    mstore(sub(data, 0x40), mBefore2)
                    mstore(sub(data, 0x60), mBefore3)
                }
            }
            /// @dev Returns the address of the deterministic clone of
            /// `implementation` using immutable arguments encoded in `data`, with `salt`, by `deployer`.
            /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
            function predictDeterministicAddress(
                address implementation,
                bytes memory data,
                bytes32 salt,
                address deployer
            ) internal pure returns (address predicted) {
                bytes32 hash = initCodeHash(implementation, data);
                predicted = predictDeterministicAddress(hash, salt, deployer);
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                      OTHER OPERATIONS                      */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Returns the address when a contract with initialization code hash,
            /// `hash`, is deployed with `salt`, by `deployer`.
            /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
            function predictDeterministicAddress(bytes32 hash, bytes32 salt, address deployer)
                internal
                pure
                returns (address predicted)
            {
                /// @solidity memory-safe-assembly
                assembly {
                    // Compute and store the bytecode hash.
                    mstore8(0x00, 0xff) // Write the prefix.
                    mstore(0x35, hash)
                    mstore(0x01, shl(96, deployer))
                    mstore(0x15, salt)
                    predicted := keccak256(0x00, 0x55)
                    // Restore the part of the free memory pointer that has been overwritten.
                    mstore(0x35, 0)
                }
            }
            /// @dev Reverts if `salt` does not start with either the zero address or the caller.
            function checkStartsWithCaller(bytes32 salt) internal view {
                /// @solidity memory-safe-assembly
                assembly {
                    // If the salt does not start with the zero address or the caller.
                    if iszero(or(iszero(shr(96, salt)), eq(caller(), shr(96, salt)))) {
                        // Store the function selector of `SaltDoesNotStartWithCaller()`.
                        mstore(0x00, 0x2f634836)
                        // Revert with (offset, size).
                        revert(0x1c, 0x04)
                    }
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.4;
        /// @notice Simple single owner authorization mixin.
        /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
        ///
        /// @dev Note:
        /// This implementation does NOT auto-initialize the owner to `msg.sender`.
        /// You MUST call the `_initializeOwner` in the constructor / initializer.
        ///
        /// While the ownable portion follows
        /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
        /// the nomenclature for the 2-step ownership handover may be unique to this codebase.
        abstract contract Ownable {
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                       CUSTOM ERRORS                        */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev The caller is not authorized to call the function.
            error Unauthorized();
            /// @dev The `newOwner` cannot be the zero address.
            error NewOwnerIsZeroAddress();
            /// @dev The `pendingOwner` does not have a valid handover request.
            error NoHandoverRequest();
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                           EVENTS                           */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
            /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
            /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
            /// despite it not being as lightweight as a single argument event.
            event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
            /// @dev An ownership handover to `pendingOwner` has been requested.
            event OwnershipHandoverRequested(address indexed pendingOwner);
            /// @dev The ownership handover to `pendingOwner` has been canceled.
            event OwnershipHandoverCanceled(address indexed pendingOwner);
            /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
            uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
                0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
            /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
            uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
                0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
            /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
            uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
                0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                          STORAGE                           */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`.
            /// It is intentionally chosen to be a high value
            /// to avoid collision with lower slots.
            /// The choice of manual storage layout is to enable compatibility
            /// with both regular and upgradeable contracts.
            uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8;
            /// The ownership handover slot of `newOwner` is given by:
            /// ```
            ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
            ///     let handoverSlot := keccak256(0x00, 0x20)
            /// ```
            /// It stores the expiry timestamp of the two-step ownership handover.
            uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                     INTERNAL FUNCTIONS                     */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Initializes the owner directly without authorization guard.
            /// This function must be called upon initialization,
            /// regardless of whether the contract is upgradeable or not.
            /// This is to enable generalization to both regular and upgradeable contracts,
            /// and to save gas in case the initial owner is not the caller.
            /// For performance reasons, this function will not check if there
            /// is an existing owner.
            function _initializeOwner(address newOwner) internal virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    // Clean the upper 96 bits.
                    newOwner := shr(96, shl(96, newOwner))
                    // Store the new value.
                    sstore(not(_OWNER_SLOT_NOT), newOwner)
                    // Emit the {OwnershipTransferred} event.
                    log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
                }
            }
            /// @dev Sets the owner directly without authorization guard.
            function _setOwner(address newOwner) internal virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    let ownerSlot := not(_OWNER_SLOT_NOT)
                    // Clean the upper 96 bits.
                    newOwner := shr(96, shl(96, newOwner))
                    // Emit the {OwnershipTransferred} event.
                    log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                    // Store the new value.
                    sstore(ownerSlot, newOwner)
                }
            }
            /// @dev Throws if the sender is not the owner.
            function _checkOwner() internal view virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    // If the caller is not the stored owner, revert.
                    if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) {
                        mstore(0x00, 0x82b42900) // `Unauthorized()`.
                        revert(0x1c, 0x04)
                    }
                }
            }
            /// @dev Returns how long a two-step ownership handover is valid for in seconds.
            /// Override to return a different value if needed.
            /// Made internal to conserve bytecode. Wrap it in a public function if needed.
            function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
                return 48 * 3600;
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                  PUBLIC UPDATE FUNCTIONS                   */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Allows the owner to transfer the ownership to `newOwner`.
            function transferOwnership(address newOwner) public payable virtual onlyOwner {
                /// @solidity memory-safe-assembly
                assembly {
                    if iszero(shl(96, newOwner)) {
                        mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                        revert(0x1c, 0x04)
                    }
                }
                _setOwner(newOwner);
            }
            /// @dev Allows the owner to renounce their ownership.
            function renounceOwnership() public payable virtual onlyOwner {
                _setOwner(address(0));
            }
            /// @dev Request a two-step ownership handover to the caller.
            /// The request will automatically expire in 48 hours (172800 seconds) by default.
            function requestOwnershipHandover() public payable virtual {
                unchecked {
                    uint256 expires = block.timestamp + _ownershipHandoverValidFor();
                    /// @solidity memory-safe-assembly
                    assembly {
                        // Compute and set the handover slot to `expires`.
                        mstore(0x0c, _HANDOVER_SLOT_SEED)
                        mstore(0x00, caller())
                        sstore(keccak256(0x0c, 0x20), expires)
                        // Emit the {OwnershipHandoverRequested} event.
                        log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
                    }
                }
            }
            /// @dev Cancels the two-step ownership handover to the caller, if any.
            function cancelOwnershipHandover() public payable virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    // Compute and set the handover slot to 0.
                    mstore(0x0c, _HANDOVER_SLOT_SEED)
                    mstore(0x00, caller())
                    sstore(keccak256(0x0c, 0x20), 0)
                    // Emit the {OwnershipHandoverCanceled} event.
                    log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
                }
            }
            /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
            /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
            function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
                /// @solidity memory-safe-assembly
                assembly {
                    // Compute and set the handover slot to 0.
                    mstore(0x0c, _HANDOVER_SLOT_SEED)
                    mstore(0x00, pendingOwner)
                    let handoverSlot := keccak256(0x0c, 0x20)
                    // If the handover does not exist, or has expired.
                    if gt(timestamp(), sload(handoverSlot)) {
                        mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                        revert(0x1c, 0x04)
                    }
                    // Set the handover slot to 0.
                    sstore(handoverSlot, 0)
                }
                _setOwner(pendingOwner);
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                   PUBLIC READ FUNCTIONS                    */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Returns the owner of the contract.
            function owner() public view virtual returns (address result) {
                /// @solidity memory-safe-assembly
                assembly {
                    result := sload(not(_OWNER_SLOT_NOT))
                }
            }
            /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
            function ownershipHandoverExpiresAt(address pendingOwner)
                public
                view
                virtual
                returns (uint256 result)
            {
                /// @solidity memory-safe-assembly
                assembly {
                    // Compute the handover slot.
                    mstore(0x0c, _HANDOVER_SLOT_SEED)
                    mstore(0x00, pendingOwner)
                    // Load the handover slot.
                    result := sload(keccak256(0x0c, 0x20))
                }
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                         MODIFIERS                          */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Marks a function as only callable by the owner.
            modifier onlyOwner() virtual {
                _checkOwner();
                _;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
        pragma solidity ^0.8.0;
        import "../utils/Context.sol";
        /**
         * @dev Contract module which allows children to implement an emergency stop
         * mechanism that can be triggered by an authorized account.
         *
         * This module is used through inheritance. It will make available the
         * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
         * the functions of your contract. Note that they will not be pausable by
         * simply including this module, only once the modifiers are put in place.
         */
        abstract contract Pausable is Context {
            /**
             * @dev Emitted when the pause is triggered by `account`.
             */
            event Paused(address account);
            /**
             * @dev Emitted when the pause is lifted by `account`.
             */
            event Unpaused(address account);
            bool private _paused;
            /**
             * @dev Initializes the contract in unpaused state.
             */
            constructor() {
                _paused = false;
            }
            /**
             * @dev Modifier to make a function callable only when the contract is not paused.
             *
             * Requirements:
             *
             * - The contract must not be paused.
             */
            modifier whenNotPaused() {
                _requireNotPaused();
                _;
            }
            /**
             * @dev Modifier to make a function callable only when the contract is paused.
             *
             * Requirements:
             *
             * - The contract must be paused.
             */
            modifier whenPaused() {
                _requirePaused();
                _;
            }
            /**
             * @dev Returns true if the contract is paused, and false otherwise.
             */
            function paused() public view virtual returns (bool) {
                return _paused;
            }
            /**
             * @dev Throws if the contract is paused.
             */
            function _requireNotPaused() internal view virtual {
                require(!paused(), "Pausable: paused");
            }
            /**
             * @dev Throws if the contract is not paused.
             */
            function _requirePaused() internal view virtual {
                require(paused(), "Pausable: not paused");
            }
            /**
             * @dev Triggers stopped state.
             *
             * Requirements:
             *
             * - The contract must not be paused.
             */
            function _pause() internal virtual whenNotPaused {
                _paused = true;
                emit Paused(_msgSender());
            }
            /**
             * @dev Returns to normal state.
             *
             * Requirements:
             *
             * - The contract must be paused.
             */
            function _unpause() internal virtual whenPaused {
                _paused = false;
                emit Unpaused(_msgSender());
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {BasicMintConfiguration} from "create/interfaces/v1/BasicMintConfiguration.sol";
        import {Mint721Configuration} from "create/interfaces/v1/Mint721Configuration.sol";
        import {IPFSEditionRendererConfiguration} from "create/interfaces/v1/IPFSEditionRendererConfiguration.sol";
        import {IMetadataRenderer} from "create/interfaces/v1/IMetadataRenderer.sol";
        interface IMintFactoryEvents {
            /// @notice Emitted when a new contract is created.
            /// @param _contract The address of the newly created contract.
            /// @param _creator The address who created the contract.
            event ContractCreated(address indexed _contract, address indexed _creator);
        }
        interface IMintFactory is IMintFactoryEvents {
            error InvalidSalt();
            /// @notice Creates a new basic edition mint with the specified configurations.
            /// @dev Uses the CREATE2 opcode with `salt` to create a contract.
            /// `salt` should start with `msg.sender` and can be followed by any unique byte sequence.
            /// After the creation, the `ContractCreated` event is emitted.
            /// @param mint721Configuration The initial configuration for the NFT collection.
            /// @param metadataRenderer The metadata renderer contract address.
            /// @param metadataRendererData The configuration data for the metadata renderer, or 0 bytes if none.
            /// @param salt The CREATE2 salt used for predictable contract addressing. Must start with `msg.sender`.
            /// @param mintModuleAddresses The initial approved mint modules.
            /// @param mintModuleData The configuration data for the mint modules.
            /// @return contractAddress The address of the newly created contract.
            function createBasicEdition(
                Mint721Configuration calldata mint721Configuration,
                IMetadataRenderer metadataRenderer,
                bytes calldata metadataRendererData,
                bytes32 salt,
                address[] calldata mintModuleAddresses,
                bytes[] calldata mintModuleData
            ) external returns (address contractAddress);
            /// @notice Creates a new basic edition mint with the specified configurations.
            /// @dev This is a functionally identical to `createBasicEdition`, but the four byte selector is 00000000.
            /// Uses the CREATE2 opcode with `salt` to create a contract.
            /// `salt` should start with `msg.sender` and can be followed by any unique byte sequence.
            /// After the creation, the `ContractCreated` event is emitted.
            /// @param mint721Configuration The initial configuration for the NFT collection.
            /// @param metadataRenderer The metadata renderer contract address.
            /// @param metadataRendererData The configuration data for the metadata renderer, or 0 bytes if none.
            /// @param salt The CREATE2 salt used for predictable contract addressing. Must start with `msg.sender`.
            /// @param mintModuleAddresses The initial approved mint modules.
            /// @param mintModuleData The configuration data for the mint modules.
            /// @return contractAddress The address of the newly created contract.
            function createBasicEdition_efficient_d3ea1b36(
                Mint721Configuration calldata mint721Configuration,
                IMetadataRenderer metadataRenderer,
                bytes calldata metadataRendererData,
                bytes32 salt,
                address[] calldata mintModuleAddresses,
                bytes[] calldata mintModuleData
            ) external returns (address contractAddress);
            /// @notice Updates the contract implementations.
            /// @dev Can only be called by the protocol admin.
            /// @param mintModuleRegistry The new MintModuleRegistry contract address.
            /// @param mint721Implementation The new Mint721 contract address.
            function updateImplementations(address mintModuleRegistry, address mint721Implementation) external;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        struct Mint721Configuration {
            /// @notice NFT collection name
            string name;
            /// @notice NFT collection symbol
            string symbol;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {Mint721Configuration} from "./Mint721Configuration.sol";
        import {IMetadataRenderer} from "./IMetadataRenderer.sol";
        interface IMint721 {
            /// @notice Initializes a new Mint721 contract with the provided configuration.
            /// @dev `mintModules` and `mintModulesData` must have the same cardinality.
            /// @param configuration The configuration data.
            /// @param mintModuleRegistry The mint module registry.
            /// @param metadataRenderer The metadata renderer.
            /// @param metadataRendererConfig The configuration data for the metadata renderer, or none if not required.
            /// @param mintModules The initial approved mint modules.
            /// @param mintModuleData The configuration data for the mint modules.
            /// @param creator The creator of the contract.
            function initialize(
                Mint721Configuration calldata configuration,
                address mintModuleRegistry,
                IMetadataRenderer metadataRenderer,
                bytes calldata metadataRendererConfig,
                address[] calldata mintModules,
                bytes[] calldata mintModuleData,
                address creator
            ) external;
        }
        // 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
        pragma solidity ^0.8.21;
        struct BasicMintConfiguration {
            /// @notice Purchase cost per token.
            uint256 price;
            /// @notice UNIX timestamp of mint start.
            uint64 mintStart;
            /// @notice UNIX timestamp of mint end, or zero if open-ended.
            uint64 mintEnd;
            /// @notice Maximum token purchase limit per wallet, or zero if no limit.
            uint32 maxPerWallet;
            /// @notice Maximum tokens mintable per transaction, or zero if no limit.
            uint32 maxPerTransaction;
            /// @notice Maximum tokens mintable by this module, or zero if no limit.
            uint32 maxForModule;
            /// @notice Maximum tokens that can be minted in total, or zero if no max.
            uint32 maxSupply;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        struct IPFSEditionRendererConfiguration {
            /// @notice Name of the token
            string tokenName;
            /// @notice Description of the token
            string tokenDescription;
            /// @notice IPFS hash for token's image content
            string imageIPFSHash;
            /// @notice IPFS hash for token's animated content (if any)
            /// If empty, no animated content is associated with the token
            string animationIPFSHash;
            /// @notice Mime type for token's animated content (if any)
            string animationMimeType;
        }
        

        File 2 of 6: Mint721
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {ERC721AUpgradeable} from "erc721a-upgradeable/ERC721AUpgradeable.sol";
        import {ERC721AStorage} from "erc721a-upgradeable/ERC721AStorage.sol";
        import {Ownable} from "solady/auth/Ownable.sol";
        import {IERC2981} from "openzeppelin/interfaces/IERC2981.sol";
        import {IERC165} from "openzeppelin/interfaces/IERC165.sol";
        import {IMetadataRenderer} from "create/interfaces/v1/IMetadataRenderer.sol";
        import {IMintContract} from "create/interfaces/v1/IMintContract.sol";
        import {IMint721} from "create/interfaces/v1/IMint721.sol";
        import {Mint721Configuration} from "create/interfaces/v1/Mint721Configuration.sol";
        import {IMintModuleRegistry} from "create/interfaces/v1/IMintModuleRegistry.sol";
        import {IERC4906} from "create/interfaces/v1/IERC4906.sol";
        import {Version} from "create/contracts/v1/Version.sol";
        contract Mint721 is ERC721AUpgradeable, IMintContract, IMint721, IERC4906, IERC2981, Ownable, Version {
            bytes4 private constant _updateConfigurationSelector = bytes4(keccak256("updateConfiguration(bytes)"));
            IMintModuleRegistry private _mintModuleRegistry;
            /// @inheritdoc IMintContract
            IMetadataRenderer public metadataRenderer;
            /// @inheritdoc IMintContract
            mapping(address => bool) public isMintModuleApproved;
            /// @inheritdoc IMintContract
            uint256 public royaltyBps;
            error UnapprovedMintModule();
            error OnlyEOAAdminMintAllowed();
            error AlreadyInitialized();
            error ModuleUpdateFailed();
            error InvalidMintModuleData();
            error InvalidRoyalty();
            constructor() Version(1) {}
            /// @inheritdoc IMint721
            function initialize(
                Mint721Configuration calldata config,
                address mintModuleRegistry_,
                IMetadataRenderer _metadataRenderer,
                bytes calldata metadataRendererConfig,
                address[] calldata mintModules,
                bytes[] calldata mintModuleData,
                address creator
            ) external {
                if (ERC721AStorage.layout()._currentIndex != 0) revert AlreadyInitialized();
                ERC721AStorage.layout()._name = config.name;
                ERC721AStorage.layout()._symbol = config.symbol;
                ERC721AStorage.layout()._currentIndex = _startTokenId();
                _mintModuleRegistry = IMintModuleRegistry(mintModuleRegistry_);
                _initializeOwner(creator);
                _setMetadataRenderer(_metadataRenderer);
                if (mintModules.length != mintModuleData.length) revert InvalidMintModuleData();
                for (uint256 i; i < mintModules.length;) {
                    address mintModule = mintModules[i];
                    _addMintModule(mintModule);
                    _updateExternalConfiguration(mintModule, mintModuleData[i]);
                    unchecked {
                        ++i;
                    }
                }
                if (metadataRendererConfig.length > 0) {
                    _updateExternalConfiguration(address(_metadataRenderer), metadataRendererConfig);
                }
            }
            /// @inheritdoc IMintContract
            function mint(address to, uint256 quantity) external {
                if (!isMintModuleApproved[msg.sender]) revert UnapprovedMintModule();
                _mint(to, quantity);
            }
            /// @inheritdoc IMintContract
            function adminMint(address to, uint256 quantity) external onlyOwner {
                if (tx.origin != msg.sender) revert OnlyEOAAdminMintAllowed();
                _mint(to, quantity);
            }
            /// @inheritdoc IMintContract
            function payoutRecipient() external view override returns (address) {
                return owner();
            }
            /// @inheritdoc IMintContract
            function totalMinted() external view override returns (uint256) {
                return _totalMinted();
            }
            /// @inheritdoc IMintContract
            function addMintModule(address mintModule) external onlyOwner {
                _addMintModule(mintModule);
            }
            function _addMintModule(address mintModule) internal {
                _mintModuleRegistry.checkModule(mintModule);
                isMintModuleApproved[mintModule] = true;
                emit ModuleAdded(mintModule);
            }
            /// @inheritdoc IMintContract
            function removeMintModule(address mintModule) external onlyOwner {
                _removeMintModule(mintModule);
            }
            /// @dev We don't check if it is a valid module intentionally while removing.
            function _removeMintModule(address mintModule) internal {
                delete isMintModuleApproved[mintModule];
                emit ModuleRemoved(mintModule);
            }
            /// @inheritdoc IMintContract
            function setRoyalty(uint256 bps) external onlyOwner {
                if (bps > 1000) revert InvalidRoyalty(); // disallow over 10%
                royaltyBps = bps;
                emit RoyaltyUpdated(bps);
            }
            /// @inheritdoc IERC2981
            function royaltyInfo(uint256, uint256 _salePrice) public view virtual override returns (address, uint256) {
                uint256 royaltyAmount = (_salePrice * royaltyBps) / 10000;
                return (owner(), royaltyAmount);
            }
            /// @inheritdoc IMintContract
            function refreshMetadata() external onlyOwner {
                emit BatchMetadataUpdate(_startTokenId(), type(uint256).max);
            }
            /// @inheritdoc IMintContract
            function updateExternalConfiguration(address[] memory configurable, bytes[] calldata configData)
                external
                override
                onlyOwner
            {
                if (configurable.length != configData.length) revert InvalidMintModuleData();
                for (uint256 i; i < configurable.length;) {
                    _updateExternalConfiguration(configurable[i], configData[i]);
                    unchecked {
                        ++i;
                    }
                }
            }
            function _updateExternalConfiguration(address configurable, bytes calldata configData) internal {
                (bool ok,) = configurable.call(abi.encodeWithSelector(_updateConfigurationSelector, configData));
                if (!ok) revert ModuleUpdateFailed();
            }
            /// @inheritdoc IMintContract
            function setMetadataRenderer(IMetadataRenderer _metadataRenderer) external onlyOwner {
                _setMetadataRenderer(_metadataRenderer);
            }
            function _setMetadataRenderer(IMetadataRenderer _metadataRenderer) internal {
                metadataRenderer = _metadataRenderer;
                emit MetadataRendererUpdated(address(_metadataRenderer));
            }
            /// @inheritdoc ERC721AUpgradeable
            function _startTokenId() internal pure virtual override returns (uint256) {
                return 1;
            }
            /// @inheritdoc ERC721AUpgradeable
            function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
                if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
                return metadataRenderer.tokenURI(tokenId);
            }
            /// @inheritdoc ERC721AUpgradeable
            function supportsInterface(bytes4 interfaceId)
                public
                view
                virtual
                override(ERC721AUpgradeable, IERC165)
                returns (bool)
            {
                return super.supportsInterface(interfaceId) || interfaceId == type(IMint721).interfaceId
                    || interfaceId == type(IMintContract).interfaceId || interfaceId == type(IERC4906).interfaceId
                    || interfaceId == type(IERC2981).interfaceId;
            }
        }
        // SPDX-License-Identifier: MIT
        // ERC721A Contracts v4.2.3
        // Creator: Chiru Labs
        pragma solidity ^0.8.4;
        import './IERC721AUpgradeable.sol';
        import {ERC721AStorage} from './ERC721AStorage.sol';
        import './ERC721A__Initializable.sol';
        /**
         * @dev Interface of ERC721 token receiver.
         */
        interface ERC721A__IERC721ReceiverUpgradeable {
            function onERC721Received(
                address operator,
                address from,
                uint256 tokenId,
                bytes calldata data
            ) external returns (bytes4);
        }
        /**
         * @title ERC721A
         *
         * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
         * Non-Fungible Token Standard, including the Metadata extension.
         * Optimized for lower gas during batch mints.
         *
         * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
         * starting from `_startTokenId()`.
         *
         * Assumptions:
         *
         * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
         * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
         */
        contract ERC721AUpgradeable is ERC721A__Initializable, IERC721AUpgradeable {
            using ERC721AStorage for ERC721AStorage.Layout;
            // =============================================================
            //                           CONSTANTS
            // =============================================================
            // Mask of an entry in packed address data.
            uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
            // The bit position of `numberMinted` in packed address data.
            uint256 private constant _BITPOS_NUMBER_MINTED = 64;
            // The bit position of `numberBurned` in packed address data.
            uint256 private constant _BITPOS_NUMBER_BURNED = 128;
            // The bit position of `aux` in packed address data.
            uint256 private constant _BITPOS_AUX = 192;
            // Mask of all 256 bits in packed address data except the 64 bits for `aux`.
            uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
            // The bit position of `startTimestamp` in packed ownership.
            uint256 private constant _BITPOS_START_TIMESTAMP = 160;
            // The bit mask of the `burned` bit in packed ownership.
            uint256 private constant _BITMASK_BURNED = 1 << 224;
            // The bit position of the `nextInitialized` bit in packed ownership.
            uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
            // The bit mask of the `nextInitialized` bit in packed ownership.
            uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
            // The bit position of `extraData` in packed ownership.
            uint256 private constant _BITPOS_EXTRA_DATA = 232;
            // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
            uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
            // The mask of the lower 160 bits for addresses.
            uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
            // The maximum `quantity` that can be minted with {_mintERC2309}.
            // This limit is to prevent overflows on the address data entries.
            // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
            // is required to cause an overflow, which is unrealistic.
            uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
            // The `Transfer` event signature is given by:
            // `keccak256(bytes("Transfer(address,address,uint256)"))`.
            bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
                0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
            // =============================================================
            //                          CONSTRUCTOR
            // =============================================================
            function __ERC721A_init(string memory name_, string memory symbol_) internal onlyInitializingERC721A {
                __ERC721A_init_unchained(name_, symbol_);
            }
            function __ERC721A_init_unchained(string memory name_, string memory symbol_) internal onlyInitializingERC721A {
                ERC721AStorage.layout()._name = name_;
                ERC721AStorage.layout()._symbol = symbol_;
                ERC721AStorage.layout()._currentIndex = _startTokenId();
            }
            // =============================================================
            //                   TOKEN COUNTING OPERATIONS
            // =============================================================
            /**
             * @dev Returns the starting token ID.
             * To change the starting token ID, please override this function.
             */
            function _startTokenId() internal view virtual returns (uint256) {
                return 0;
            }
            /**
             * @dev Returns the next token ID to be minted.
             */
            function _nextTokenId() internal view virtual returns (uint256) {
                return ERC721AStorage.layout()._currentIndex;
            }
            /**
             * @dev Returns the total number of tokens in existence.
             * Burned tokens will reduce the count.
             * To get the total number of tokens minted, please see {_totalMinted}.
             */
            function totalSupply() public view virtual override returns (uint256) {
                // Counter underflow is impossible as _burnCounter cannot be incremented
                // more than `_currentIndex - _startTokenId()` times.
                unchecked {
                    return ERC721AStorage.layout()._currentIndex - ERC721AStorage.layout()._burnCounter - _startTokenId();
                }
            }
            /**
             * @dev Returns the total amount of tokens minted in the contract.
             */
            function _totalMinted() internal view virtual returns (uint256) {
                // Counter underflow is impossible as `_currentIndex` does not decrement,
                // and it is initialized to `_startTokenId()`.
                unchecked {
                    return ERC721AStorage.layout()._currentIndex - _startTokenId();
                }
            }
            /**
             * @dev Returns the total number of tokens burned.
             */
            function _totalBurned() internal view virtual returns (uint256) {
                return ERC721AStorage.layout()._burnCounter;
            }
            // =============================================================
            //                    ADDRESS DATA OPERATIONS
            // =============================================================
            /**
             * @dev Returns the number of tokens in `owner`'s account.
             */
            function balanceOf(address owner) public view virtual override returns (uint256) {
                if (owner == address(0)) revert BalanceQueryForZeroAddress();
                return ERC721AStorage.layout()._packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
            }
            /**
             * Returns the number of tokens minted by `owner`.
             */
            function _numberMinted(address owner) internal view returns (uint256) {
                return
                    (ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
            }
            /**
             * Returns the number of tokens burned by or on behalf of `owner`.
             */
            function _numberBurned(address owner) internal view returns (uint256) {
                return
                    (ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
            }
            /**
             * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
             */
            function _getAux(address owner) internal view returns (uint64) {
                return uint64(ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_AUX);
            }
            /**
             * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
             * If there are multiple variables, please pack them into a uint64.
             */
            function _setAux(address owner, uint64 aux) internal virtual {
                uint256 packed = ERC721AStorage.layout()._packedAddressData[owner];
                uint256 auxCasted;
                // Cast `aux` with assembly to avoid redundant masking.
                assembly {
                    auxCasted := aux
                }
                packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
                ERC721AStorage.layout()._packedAddressData[owner] = packed;
            }
            // =============================================================
            //                            IERC165
            // =============================================================
            /**
             * @dev Returns true if this contract implements the interface defined by
             * `interfaceId`. See the corresponding
             * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
             * to learn more about how these ids are created.
             *
             * This function call must use less than 30000 gas.
             */
            function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                // The interface IDs are constants representing the first 4 bytes
                // of the XOR of all function selectors in the interface.
                // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
                // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
                return
                    interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
                    interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
                    interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
            }
            // =============================================================
            //                        IERC721Metadata
            // =============================================================
            /**
             * @dev Returns the token collection name.
             */
            function name() public view virtual override returns (string memory) {
                return ERC721AStorage.layout()._name;
            }
            /**
             * @dev Returns the token collection symbol.
             */
            function symbol() public view virtual override returns (string memory) {
                return ERC721AStorage.layout()._symbol;
            }
            /**
             * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
             */
            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))) : '';
            }
            /**
             * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
             * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
             * by default, it can be overridden in child contracts.
             */
            function _baseURI() internal view virtual returns (string memory) {
                return '';
            }
            // =============================================================
            //                     OWNERSHIPS OPERATIONS
            // =============================================================
            /**
             * @dev Returns the owner of the `tokenId` token.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             */
            function ownerOf(uint256 tokenId) public view virtual override returns (address) {
                return address(uint160(_packedOwnershipOf(tokenId)));
            }
            /**
             * @dev Gas spent here starts off proportional to the maximum mint batch size.
             * It gradually moves to O(1) as tokens get transferred around over time.
             */
            function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
                return _unpackedOwnership(_packedOwnershipOf(tokenId));
            }
            /**
             * @dev Returns the unpacked `TokenOwnership` struct at `index`.
             */
            function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
                return _unpackedOwnership(ERC721AStorage.layout()._packedOwnerships[index]);
            }
            /**
             * @dev Initializes the ownership slot minted at `index` for efficiency purposes.
             */
            function _initializeOwnershipAt(uint256 index) internal virtual {
                if (ERC721AStorage.layout()._packedOwnerships[index] == 0) {
                    ERC721AStorage.layout()._packedOwnerships[index] = _packedOwnershipOf(index);
                }
            }
            /**
             * Returns the packed ownership data of `tokenId`.
             */
            function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) {
                if (_startTokenId() <= tokenId) {
                    packed = ERC721AStorage.layout()._packedOwnerships[tokenId];
                    // If not burned.
                    if (packed & _BITMASK_BURNED == 0) {
                        // If the data at the starting slot does not exist, start the scan.
                        if (packed == 0) {
                            if (tokenId >= ERC721AStorage.layout()._currentIndex) revert OwnerQueryForNonexistentToken();
                            // Invariant:
                            // There will always be an initialized ownership slot
                            // (i.e. `ownership.addr != address(0) && ownership.burned == false`)
                            // before an unintialized ownership slot
                            // (i.e. `ownership.addr == address(0) && ownership.burned == false`)
                            // Hence, `tokenId` will not underflow.
                            //
                            // We can directly compare the packed value.
                            // If the address is zero, packed will be zero.
                            for (;;) {
                                unchecked {
                                    packed = ERC721AStorage.layout()._packedOwnerships[--tokenId];
                                }
                                if (packed == 0) continue;
                                return packed;
                            }
                        }
                        // Otherwise, the data exists and is not burned. We can skip the scan.
                        // This is possible because we have already achieved the target condition.
                        // This saves 2143 gas on transfers of initialized tokens.
                        return packed;
                    }
                }
                revert OwnerQueryForNonexistentToken();
            }
            /**
             * @dev Returns the unpacked `TokenOwnership` struct from `packed`.
             */
            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);
            }
            /**
             * @dev Packs ownership data into a single uint256.
             */
            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))
                }
            }
            /**
             * @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
             */
            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))
                }
            }
            // =============================================================
            //                      APPROVAL OPERATIONS
            // =============================================================
            /**
             * @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}.
             *
             * Requirements:
             *
             * - The caller must own the token or be an approved operator.
             */
            function approve(address to, uint256 tokenId) public payable virtual override {
                _approve(to, tokenId, true);
            }
            /**
             * @dev Returns the account approved for `tokenId` token.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             */
            function getApproved(uint256 tokenId) public view virtual override returns (address) {
                if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
                return ERC721AStorage.layout()._tokenApprovals[tokenId].value;
            }
            /**
             * @dev Approve or remove `operator` as an operator for the caller.
             * Operators can call {transferFrom} or {safeTransferFrom}
             * for any token owned by the caller.
             *
             * Requirements:
             *
             * - The `operator` cannot be the caller.
             *
             * Emits an {ApprovalForAll} event.
             */
            function setApprovalForAll(address operator, bool approved) public virtual override {
                ERC721AStorage.layout()._operatorApprovals[_msgSenderERC721A()][operator] = approved;
                emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
            }
            /**
             * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
             *
             * See {setApprovalForAll}.
             */
            function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
                return ERC721AStorage.layout()._operatorApprovals[owner][operator];
            }
            /**
             * @dev Returns whether `tokenId` exists.
             *
             * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
             *
             * Tokens start existing when they are minted. See {_mint}.
             */
            function _exists(uint256 tokenId) internal view virtual returns (bool) {
                return
                    _startTokenId() <= tokenId &&
                    tokenId < ERC721AStorage.layout()._currentIndex && // If within bounds,
                    ERC721AStorage.layout()._packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.
            }
            /**
             * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
             */
            function _isSenderApprovedOrOwner(
                address approvedAddress,
                address owner,
                address msgSender
            ) private pure returns (bool result) {
                assembly {
                    // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
                    owner := and(owner, _BITMASK_ADDRESS)
                    // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
                    msgSender := and(msgSender, _BITMASK_ADDRESS)
                    // `msgSender == owner || msgSender == approvedAddress`.
                    result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
                }
            }
            /**
             * @dev Returns the storage slot and value for the approved address of `tokenId`.
             */
            function _getApprovedSlotAndAddress(uint256 tokenId)
                private
                view
                returns (uint256 approvedAddressSlot, address approvedAddress)
            {
                ERC721AStorage.TokenApprovalRef storage tokenApproval = ERC721AStorage.layout()._tokenApprovals[tokenId];
                // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
                assembly {
                    approvedAddressSlot := tokenApproval.slot
                    approvedAddress := sload(approvedAddressSlot)
                }
            }
            // =============================================================
            //                      TRANSFER OPERATIONS
            // =============================================================
            /**
             * @dev Transfers `tokenId` from `from` to `to`.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must be owned by `from`.
             * - If the caller is not `from`, it must be approved to move this token
             * by either {approve} or {setApprovalForAll}.
             *
             * Emits a {Transfer} event.
             */
            function transferFrom(
                address from,
                address to,
                uint256 tokenId
            ) public payable virtual override {
                uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
                if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();
                (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
                // The nested ifs save around 20+ gas over a compound boolean condition.
                if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                    if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
                if (to == address(0)) revert TransferToZeroAddress();
                _beforeTokenTransfers(from, to, tokenId, 1);
                // Clear approvals from the previous owner.
                assembly {
                    if approvedAddress {
                        // This is equivalent to `delete _tokenApprovals[tokenId]`.
                        sstore(approvedAddressSlot, 0)
                    }
                }
                // Underflow of the sender's balance is impossible because we check for
                // ownership above and the recipient's balance can't realistically overflow.
                // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
                unchecked {
                    // We can directly increment and decrement the balances.
                    --ERC721AStorage.layout()._packedAddressData[from]; // Updates: `balance -= 1`.
                    ++ERC721AStorage.layout()._packedAddressData[to]; // Updates: `balance += 1`.
                    // Updates:
                    // - `address` to the next owner.
                    // - `startTimestamp` to the timestamp of transfering.
                    // - `burned` to `false`.
                    // - `nextInitialized` to `true`.
                    ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData(
                        to,
                        _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
                    );
                    // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
                    if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                        uint256 nextTokenId = tokenId + 1;
                        // If the next slot's address is zero and not burned (i.e. packed value is zero).
                        if (ERC721AStorage.layout()._packedOwnerships[nextTokenId] == 0) {
                            // If the next slot is within bounds.
                            if (nextTokenId != ERC721AStorage.layout()._currentIndex) {
                                // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                                ERC721AStorage.layout()._packedOwnerships[nextTokenId] = prevOwnershipPacked;
                            }
                        }
                    }
                }
                emit Transfer(from, to, tokenId);
                _afterTokenTransfers(from, to, tokenId, 1);
            }
            /**
             * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId
            ) public payable virtual override {
                safeTransferFrom(from, to, tokenId, '');
            }
            /**
             * @dev Safely transfers `tokenId` token from `from` to `to`.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must exist and be owned by `from`.
             * - If the caller is not `from`, it must be approved to move this token
             * by either {approve} or {setApprovalForAll}.
             * - If `to` refers to a smart contract, it must implement
             * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
             *
             * Emits a {Transfer} event.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId,
                bytes memory _data
            ) public payable virtual override {
                transferFrom(from, to, tokenId);
                if (to.code.length != 0)
                    if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
                        revert TransferToNonERC721ReceiverImplementer();
                    }
            }
            /**
             * @dev Hook that is called before a set of serially-ordered token IDs
             * are about to be transferred. This includes minting.
             * And also called before burning one token.
             *
             * `startTokenId` - the first token ID to be transferred.
             * `quantity` - the amount to be transferred.
             *
             * Calling conditions:
             *
             * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
             * transferred to `to`.
             * - When `from` is zero, `tokenId` will be minted for `to`.
             * - When `to` is zero, `tokenId` will be burned by `from`.
             * - `from` and `to` are never both zero.
             */
            function _beforeTokenTransfers(
                address from,
                address to,
                uint256 startTokenId,
                uint256 quantity
            ) internal virtual {}
            /**
             * @dev Hook that is called after a set of serially-ordered token IDs
             * have been transferred. This includes minting.
             * And also called after one token has been burned.
             *
             * `startTokenId` - the first token ID to be transferred.
             * `quantity` - the amount to be transferred.
             *
             * Calling conditions:
             *
             * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
             * transferred to `to`.
             * - When `from` is zero, `tokenId` has been minted for `to`.
             * - When `to` is zero, `tokenId` has been burned by `from`.
             * - `from` and `to` are never both zero.
             */
            function _afterTokenTransfers(
                address from,
                address to,
                uint256 startTokenId,
                uint256 quantity
            ) internal virtual {}
            /**
             * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
             *
             * `from` - Previous owner of the given token ID.
             * `to` - Target address that will receive the token.
             * `tokenId` - Token ID to be transferred.
             * `_data` - Optional data to send along with the call.
             *
             * Returns whether the call correctly returned the expected magic value.
             */
            function _checkContractOnERC721Received(
                address from,
                address to,
                uint256 tokenId,
                bytes memory _data
            ) private returns (bool) {
                try
                    ERC721A__IERC721ReceiverUpgradeable(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data)
                returns (bytes4 retval) {
                    return retval == ERC721A__IERC721ReceiverUpgradeable(to).onERC721Received.selector;
                } catch (bytes memory reason) {
                    if (reason.length == 0) {
                        revert TransferToNonERC721ReceiverImplementer();
                    } else {
                        assembly {
                            revert(add(32, reason), mload(reason))
                        }
                    }
                }
            }
            // =============================================================
            //                        MINT OPERATIONS
            // =============================================================
            /**
             * @dev Mints `quantity` tokens and transfers them to `to`.
             *
             * Requirements:
             *
             * - `to` cannot be the zero address.
             * - `quantity` must be greater than 0.
             *
             * Emits a {Transfer} event for each mint.
             */
            function _mint(address to, uint256 quantity) internal virtual {
                uint256 startTokenId = ERC721AStorage.layout()._currentIndex;
                if (quantity == 0) revert MintZeroQuantity();
                _beforeTokenTransfers(address(0), to, startTokenId, quantity);
                // Overflows are incredibly unrealistic.
                // `balance` and `numberMinted` have a maximum limit of 2**64.
                // `tokenId` has a maximum limit of 2**256.
                unchecked {
                    // Updates:
                    // - `balance += quantity`.
                    // - `numberMinted += quantity`.
                    //
                    // We can directly add to the `balance` and `numberMinted`.
                    ERC721AStorage.layout()._packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
                    // Updates:
                    // - `address` to the owner.
                    // - `startTimestamp` to the timestamp of minting.
                    // - `burned` to `false`.
                    // - `nextInitialized` to `quantity == 1`.
                    ERC721AStorage.layout()._packedOwnerships[startTokenId] = _packOwnershipData(
                        to,
                        _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
                    );
                    uint256 toMasked;
                    uint256 end = startTokenId + quantity;
                    // Use assembly to loop and emit the `Transfer` event for gas savings.
                    // The duplicated `log4` removes an extra check and reduces stack juggling.
                    // The assembly, together with the surrounding Solidity code, have been
                    // delicately arranged to nudge the compiler into producing optimized opcodes.
                    assembly {
                        // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
                        toMasked := and(to, _BITMASK_ADDRESS)
                        // Emit the `Transfer` event.
                        log4(
                            0, // Start of data (0, since no data).
                            0, // End of data (0, since no data).
                            _TRANSFER_EVENT_SIGNATURE, // Signature.
                            0, // `address(0)`.
                            toMasked, // `to`.
                            startTokenId // `tokenId`.
                        )
                        // The `iszero(eq(,))` check ensures that large values of `quantity`
                        // that overflows uint256 will make the loop run out of gas.
                        // The compiler will optimize the `iszero` away for performance.
                        for {
                            let tokenId := add(startTokenId, 1)
                        } iszero(eq(tokenId, end)) {
                            tokenId := add(tokenId, 1)
                        } {
                            // Emit the `Transfer` event. Similar to above.
                            log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
                        }
                    }
                    if (toMasked == 0) revert MintToZeroAddress();
                    ERC721AStorage.layout()._currentIndex = end;
                }
                _afterTokenTransfers(address(0), to, startTokenId, quantity);
            }
            /**
             * @dev Mints `quantity` tokens and transfers them to `to`.
             *
             * This function is intended for efficient minting only during contract creation.
             *
             * It emits only one {ConsecutiveTransfer} as defined in
             * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
             * instead of a sequence of {Transfer} event(s).
             *
             * Calling this function outside of contract creation WILL make your contract
             * non-compliant with the ERC721 standard.
             * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
             * {ConsecutiveTransfer} event is only permissible during contract creation.
             *
             * Requirements:
             *
             * - `to` cannot be the zero address.
             * - `quantity` must be greater than 0.
             *
             * Emits a {ConsecutiveTransfer} event.
             */
            function _mintERC2309(address to, uint256 quantity) internal virtual {
                uint256 startTokenId = ERC721AStorage.layout()._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);
                // Overflows are unrealistic due to the above check for `quantity` to be below the limit.
                unchecked {
                    // Updates:
                    // - `balance += quantity`.
                    // - `numberMinted += quantity`.
                    //
                    // We can directly add to the `balance` and `numberMinted`.
                    ERC721AStorage.layout()._packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
                    // Updates:
                    // - `address` to the owner.
                    // - `startTimestamp` to the timestamp of minting.
                    // - `burned` to `false`.
                    // - `nextInitialized` to `quantity == 1`.
                    ERC721AStorage.layout()._packedOwnerships[startTokenId] = _packOwnershipData(
                        to,
                        _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
                    );
                    emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);
                    ERC721AStorage.layout()._currentIndex = startTokenId + quantity;
                }
                _afterTokenTransfers(address(0), to, startTokenId, quantity);
            }
            /**
             * @dev Safely mints `quantity` tokens and transfers them to `to`.
             *
             * Requirements:
             *
             * - If `to` refers to a smart contract, it must implement
             * {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
             * - `quantity` must be greater than 0.
             *
             * See {_mint}.
             *
             * Emits a {Transfer} event for each mint.
             */
            function _safeMint(
                address to,
                uint256 quantity,
                bytes memory _data
            ) internal virtual {
                _mint(to, quantity);
                unchecked {
                    if (to.code.length != 0) {
                        uint256 end = ERC721AStorage.layout()._currentIndex;
                        uint256 index = end - quantity;
                        do {
                            if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
                                revert TransferToNonERC721ReceiverImplementer();
                            }
                        } while (index < end);
                        // Reentrancy protection.
                        if (ERC721AStorage.layout()._currentIndex != end) revert();
                    }
                }
            }
            /**
             * @dev Equivalent to `_safeMint(to, quantity, '')`.
             */
            function _safeMint(address to, uint256 quantity) internal virtual {
                _safeMint(to, quantity, '');
            }
            // =============================================================
            //                       APPROVAL OPERATIONS
            // =============================================================
            /**
             * @dev Equivalent to `_approve(to, tokenId, false)`.
             */
            function _approve(address to, uint256 tokenId) internal virtual {
                _approve(to, tokenId, false);
            }
            /**
             * @dev Gives permission to `to` to transfer `tokenId` token to another account.
             * The approval is cleared when the token is transferred.
             *
             * Only a single account can be approved at a time, so approving the
             * zero address clears previous approvals.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             *
             * Emits an {Approval} event.
             */
            function _approve(
                address to,
                uint256 tokenId,
                bool approvalCheck
            ) internal virtual {
                address owner = ownerOf(tokenId);
                if (approvalCheck)
                    if (_msgSenderERC721A() != owner)
                        if (!isApprovedForAll(owner, _msgSenderERC721A())) {
                            revert ApprovalCallerNotOwnerNorApproved();
                        }
                ERC721AStorage.layout()._tokenApprovals[tokenId].value = to;
                emit Approval(owner, to, tokenId);
            }
            // =============================================================
            //                        BURN OPERATIONS
            // =============================================================
            /**
             * @dev Equivalent to `_burn(tokenId, false)`.
             */
            function _burn(uint256 tokenId) internal virtual {
                _burn(tokenId, false);
            }
            /**
             * @dev Destroys `tokenId`.
             * The approval is cleared when the token is burned.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             *
             * Emits a {Transfer} event.
             */
            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) {
                    // The nested ifs save around 20+ gas over a compound boolean condition.
                    if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                        if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
                }
                _beforeTokenTransfers(from, address(0), tokenId, 1);
                // Clear approvals from the previous owner.
                assembly {
                    if approvedAddress {
                        // This is equivalent to `delete _tokenApprovals[tokenId]`.
                        sstore(approvedAddressSlot, 0)
                    }
                }
                // Underflow of the sender's balance is impossible because we check for
                // ownership above and the recipient's balance can't realistically overflow.
                // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
                unchecked {
                    // Updates:
                    // - `balance -= 1`.
                    // - `numberBurned += 1`.
                    //
                    // We can directly decrement the balance, and increment the number burned.
                    // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
                    ERC721AStorage.layout()._packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
                    // Updates:
                    // - `address` to the last owner.
                    // - `startTimestamp` to the timestamp of burning.
                    // - `burned` to `true`.
                    // - `nextInitialized` to `true`.
                    ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData(
                        from,
                        (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
                    );
                    // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
                    if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                        uint256 nextTokenId = tokenId + 1;
                        // If the next slot's address is zero and not burned (i.e. packed value is zero).
                        if (ERC721AStorage.layout()._packedOwnerships[nextTokenId] == 0) {
                            // If the next slot is within bounds.
                            if (nextTokenId != ERC721AStorage.layout()._currentIndex) {
                                // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                                ERC721AStorage.layout()._packedOwnerships[nextTokenId] = prevOwnershipPacked;
                            }
                        }
                    }
                }
                emit Transfer(from, address(0), tokenId);
                _afterTokenTransfers(from, address(0), tokenId, 1);
                // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
                unchecked {
                    ERC721AStorage.layout()._burnCounter++;
                }
            }
            // =============================================================
            //                     EXTRA DATA OPERATIONS
            // =============================================================
            /**
             * @dev Directly sets the extra data for the ownership data `index`.
             */
            function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
                uint256 packed = ERC721AStorage.layout()._packedOwnerships[index];
                if (packed == 0) revert OwnershipNotInitializedForExtraData();
                uint256 extraDataCasted;
                // Cast `extraData` with assembly to avoid redundant masking.
                assembly {
                    extraDataCasted := extraData
                }
                packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
                ERC721AStorage.layout()._packedOwnerships[index] = packed;
            }
            /**
             * @dev Called during each token transfer to set the 24bit `extraData` field.
             * Intended to be overridden by the cosumer contract.
             *
             * `previousExtraData` - the value of `extraData` before transfer.
             *
             * Calling conditions:
             *
             * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
             * transferred to `to`.
             * - When `from` is zero, `tokenId` will be minted for `to`.
             * - When `to` is zero, `tokenId` will be burned by `from`.
             * - `from` and `to` are never both zero.
             */
            function _extraData(
                address from,
                address to,
                uint24 previousExtraData
            ) internal view virtual returns (uint24) {}
            /**
             * @dev Returns the next extra data for the packed ownership data.
             * The returned result is shifted into position.
             */
            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;
            }
            // =============================================================
            //                       OTHER OPERATIONS
            // =============================================================
            /**
             * @dev Returns the message sender (defaults to `msg.sender`).
             *
             * If you are writing GSN compatible contracts, you need to override this function.
             */
            function _msgSenderERC721A() internal view virtual returns (address) {
                return msg.sender;
            }
            /**
             * @dev Converts a uint256 to its ASCII string decimal representation.
             */
            function _toString(uint256 value) internal pure virtual returns (string memory str) {
                assembly {
                    // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
                    // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
                    // We will need 1 word for the trailing zeros padding, 1 word for the length,
                    // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
                    let m := add(mload(0x40), 0xa0)
                    // Update the free memory pointer to allocate.
                    mstore(0x40, m)
                    // Assign the `str` to the end.
                    str := sub(m, 0x20)
                    // Zeroize the slot after the string.
                    mstore(str, 0)
                    // Cache the end of the memory to calculate the length later.
                    let end := str
                    // We write the string from rightmost digit to leftmost digit.
                    // The following is essentially a do-while loop that also handles the zero case.
                    // prettier-ignore
                    for { let temp := value } 1 {} {
                        str := sub(str, 1)
                        // Write the character to the pointer.
                        // The ASCII index of the '0' character is 48.
                        mstore8(str, add(48, mod(temp, 10)))
                        // Keep dividing `temp` until zero.
                        temp := div(temp, 10)
                        // prettier-ignore
                        if iszero(temp) { break }
                    }
                    let length := sub(end, str)
                    // Move the pointer 32 bytes leftwards to make room for the length.
                    str := sub(str, 0x20)
                    // Store the length.
                    mstore(str, length)
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        library ERC721AStorage {
            // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
            struct TokenApprovalRef {
                address value;
            }
            struct Layout {
                // =============================================================
                //                            STORAGE
                // =============================================================
                // The next token ID to be minted.
                uint256 _currentIndex;
                // The number of tokens burned.
                uint256 _burnCounter;
                // Token name
                string _name;
                // Token symbol
                string _symbol;
                // Mapping from token ID to ownership details
                // An empty struct value does not necessarily mean the token is unowned.
                // See {_packedOwnershipOf} implementation for details.
                //
                // Bits Layout:
                // - [0..159]   `addr`
                // - [160..223] `startTimestamp`
                // - [224]      `burned`
                // - [225]      `nextInitialized`
                // - [232..255] `extraData`
                mapping(uint256 => uint256) _packedOwnerships;
                // Mapping owner address to address data.
                //
                // Bits Layout:
                // - [0..63]    `balance`
                // - [64..127]  `numberMinted`
                // - [128..191] `numberBurned`
                // - [192..255] `aux`
                mapping(address => uint256) _packedAddressData;
                // Mapping from token ID to approved address.
                mapping(uint256 => ERC721AStorage.TokenApprovalRef) _tokenApprovals;
                // Mapping from owner to operator approvals
                mapping(address => mapping(address => bool)) _operatorApprovals;
            }
            bytes32 internal constant STORAGE_SLOT = keccak256('ERC721A.contracts.storage.ERC721A');
            function layout() internal pure returns (Layout storage l) {
                bytes32 slot = STORAGE_SLOT;
                assembly {
                    l.slot := slot
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.4;
        /// @notice Simple single owner authorization mixin.
        /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
        ///
        /// @dev Note:
        /// This implementation does NOT auto-initialize the owner to `msg.sender`.
        /// You MUST call the `_initializeOwner` in the constructor / initializer.
        ///
        /// While the ownable portion follows
        /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
        /// the nomenclature for the 2-step ownership handover may be unique to this codebase.
        abstract contract Ownable {
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                       CUSTOM ERRORS                        */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev The caller is not authorized to call the function.
            error Unauthorized();
            /// @dev The `newOwner` cannot be the zero address.
            error NewOwnerIsZeroAddress();
            /// @dev The `pendingOwner` does not have a valid handover request.
            error NoHandoverRequest();
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                           EVENTS                           */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
            /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
            /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
            /// despite it not being as lightweight as a single argument event.
            event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
            /// @dev An ownership handover to `pendingOwner` has been requested.
            event OwnershipHandoverRequested(address indexed pendingOwner);
            /// @dev The ownership handover to `pendingOwner` has been canceled.
            event OwnershipHandoverCanceled(address indexed pendingOwner);
            /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
            uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
                0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
            /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
            uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
                0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
            /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
            uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
                0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                          STORAGE                           */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`.
            /// It is intentionally chosen to be a high value
            /// to avoid collision with lower slots.
            /// The choice of manual storage layout is to enable compatibility
            /// with both regular and upgradeable contracts.
            uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8;
            /// The ownership handover slot of `newOwner` is given by:
            /// ```
            ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
            ///     let handoverSlot := keccak256(0x00, 0x20)
            /// ```
            /// It stores the expiry timestamp of the two-step ownership handover.
            uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                     INTERNAL FUNCTIONS                     */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Initializes the owner directly without authorization guard.
            /// This function must be called upon initialization,
            /// regardless of whether the contract is upgradeable or not.
            /// This is to enable generalization to both regular and upgradeable contracts,
            /// and to save gas in case the initial owner is not the caller.
            /// For performance reasons, this function will not check if there
            /// is an existing owner.
            function _initializeOwner(address newOwner) internal virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    // Clean the upper 96 bits.
                    newOwner := shr(96, shl(96, newOwner))
                    // Store the new value.
                    sstore(not(_OWNER_SLOT_NOT), newOwner)
                    // Emit the {OwnershipTransferred} event.
                    log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
                }
            }
            /// @dev Sets the owner directly without authorization guard.
            function _setOwner(address newOwner) internal virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    let ownerSlot := not(_OWNER_SLOT_NOT)
                    // Clean the upper 96 bits.
                    newOwner := shr(96, shl(96, newOwner))
                    // Emit the {OwnershipTransferred} event.
                    log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                    // Store the new value.
                    sstore(ownerSlot, newOwner)
                }
            }
            /// @dev Throws if the sender is not the owner.
            function _checkOwner() internal view virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    // If the caller is not the stored owner, revert.
                    if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) {
                        mstore(0x00, 0x82b42900) // `Unauthorized()`.
                        revert(0x1c, 0x04)
                    }
                }
            }
            /// @dev Returns how long a two-step ownership handover is valid for in seconds.
            /// Override to return a different value if needed.
            /// Made internal to conserve bytecode. Wrap it in a public function if needed.
            function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
                return 48 * 3600;
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                  PUBLIC UPDATE FUNCTIONS                   */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Allows the owner to transfer the ownership to `newOwner`.
            function transferOwnership(address newOwner) public payable virtual onlyOwner {
                /// @solidity memory-safe-assembly
                assembly {
                    if iszero(shl(96, newOwner)) {
                        mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                        revert(0x1c, 0x04)
                    }
                }
                _setOwner(newOwner);
            }
            /// @dev Allows the owner to renounce their ownership.
            function renounceOwnership() public payable virtual onlyOwner {
                _setOwner(address(0));
            }
            /// @dev Request a two-step ownership handover to the caller.
            /// The request will automatically expire in 48 hours (172800 seconds) by default.
            function requestOwnershipHandover() public payable virtual {
                unchecked {
                    uint256 expires = block.timestamp + _ownershipHandoverValidFor();
                    /// @solidity memory-safe-assembly
                    assembly {
                        // Compute and set the handover slot to `expires`.
                        mstore(0x0c, _HANDOVER_SLOT_SEED)
                        mstore(0x00, caller())
                        sstore(keccak256(0x0c, 0x20), expires)
                        // Emit the {OwnershipHandoverRequested} event.
                        log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
                    }
                }
            }
            /// @dev Cancels the two-step ownership handover to the caller, if any.
            function cancelOwnershipHandover() public payable virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    // Compute and set the handover slot to 0.
                    mstore(0x0c, _HANDOVER_SLOT_SEED)
                    mstore(0x00, caller())
                    sstore(keccak256(0x0c, 0x20), 0)
                    // Emit the {OwnershipHandoverCanceled} event.
                    log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
                }
            }
            /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
            /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
            function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
                /// @solidity memory-safe-assembly
                assembly {
                    // Compute and set the handover slot to 0.
                    mstore(0x0c, _HANDOVER_SLOT_SEED)
                    mstore(0x00, pendingOwner)
                    let handoverSlot := keccak256(0x0c, 0x20)
                    // If the handover does not exist, or has expired.
                    if gt(timestamp(), sload(handoverSlot)) {
                        mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                        revert(0x1c, 0x04)
                    }
                    // Set the handover slot to 0.
                    sstore(handoverSlot, 0)
                }
                _setOwner(pendingOwner);
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                   PUBLIC READ FUNCTIONS                    */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Returns the owner of the contract.
            function owner() public view virtual returns (address result) {
                /// @solidity memory-safe-assembly
                assembly {
                    result := sload(not(_OWNER_SLOT_NOT))
                }
            }
            /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
            function ownershipHandoverExpiresAt(address pendingOwner)
                public
                view
                virtual
                returns (uint256 result)
            {
                /// @solidity memory-safe-assembly
                assembly {
                    // Compute the handover slot.
                    mstore(0x0c, _HANDOVER_SLOT_SEED)
                    mstore(0x00, pendingOwner)
                    // Load the handover slot.
                    result := sload(keccak256(0x0c, 0x20))
                }
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                         MODIFIERS                          */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Marks a function as only callable by the owner.
            modifier onlyOwner() virtual {
                _checkOwner();
                _;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)
        pragma solidity ^0.8.0;
        import "../utils/introspection/IERC165.sol";
        /**
         * @dev Interface for the NFT Royalty Standard.
         *
         * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
         * support for royalty payments across all NFT marketplaces and ecosystem participants.
         *
         * _Available since v4.5._
         */
        interface IERC2981 is IERC165 {
            /**
             * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
             * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
             */
            function royaltyInfo(uint256 tokenId, uint256 salePrice)
                external
                view
                returns (address receiver, uint256 royaltyAmount);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)
        pragma solidity ^0.8.0;
        import "../utils/introspection/IERC165.sol";
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        interface IMetadataRenderer {
            /// @notice Retrieves the token URI for the specified token ID.
            /// @param tokenId The ID of the token.
            /// @return uri The URI of the token.
            function tokenURI(uint256 tokenId) external view returns (string memory uri);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {IMetadataRenderer} from "create/interfaces/v1/IMetadataRenderer.sol";
        interface IMintContractEvents {
            /// @notice Emitted when the royalty is updated.
            event RoyaltyUpdated(uint256 bps);
            /// @notice Emitted when a new mint module is added.
            event ModuleAdded(address module);
            /// @notice Emitted when a mint module is removed.
            event ModuleRemoved(address module);
            /// @notice Emitted when the metadata renderer is updated.
            event MetadataRendererUpdated(address renderer);
        }
        interface IMintContract is IMintContractEvents {
            /// @notice Mints tokens using approved mint modules.
            /// @param to The address receiving the minted tokens.
            /// @param quantity The quantity of tokens to mint.
            function mint(address to, uint256 quantity) external;
            /// @notice Mints tokens, callable only by the contract owner.
            /// @param to The address receiving the minted tokens.
            /// @param quantity The quantity of tokens to mint.
            function adminMint(address to, uint256 quantity) external;
            /// @notice Retrieves the payout recipient address for this mint contract.
            /// @return recipient address of the payout recipient.
            function payoutRecipient() external view returns (address recipient);
            /// @notice Returns the total number of tokens minted.
            /// @return total number of tokens minted.
            function totalMinted() external view returns (uint256 total);
            /// @notice Adds a new mint module as an approved minter.
            /// @dev Can only be executed by the owner of the contract.
            /// Must be approved in the MintModuleRegistry.
            /// @param mintModule The contract address of the mint module.
            function addMintModule(address mintModule) external;
            /// @notice Removes a mint module as an approved minter.
            /// @dev Can only be executed by the owner of the contract.
            /// @param mintModule The contract address of the mint module.
            function removeMintModule(address mintModule) external;
            /// @notice Returns whether a mint module is approved.
            /// @param mintModule The contract address of the mint module.
            /// @return isApproved Whether the mint module is approved.
            function isMintModuleApproved(address mintModule) external view returns (bool isApproved);
            /// @notice Updates configuration located in an external contract.
            /// @dev Can only be executed by the owner of the contract.
            /// The cardinality of `configurables` and `configData` must be the same.
            /// @param configurables The contract addresses to configure.
            /// @param configData The configuration data for the contracts.
            function updateExternalConfiguration(address[] calldata configurables, bytes[] calldata configData) external;
            /// @notice Sets the metadata renderer.
            /// @dev This will not request a metadata refresh. If needed, call `refreshMetadata`.
            /// @param renderer The new metadata renderer.
            function setMetadataRenderer(IMetadataRenderer renderer) external;
            /// @notice Returns the metadata renderer for this contract.
            /// @return metadataRenderer The metadata renderer.
            function metadataRenderer() external returns (IMetadataRenderer metadataRenderer);
            /// @notice Triggers a batch metadata update.
            function refreshMetadata() external;
            /// @notice Updates the royalty for this contract.
            /// @dev Can only be called by the contract owner.
            /// Emits a `RoyaltyUpdated` event.
            /// @param bps The new royalty.
            function setRoyalty(uint256 bps) external;
            /// @notice Returns the royalty for this contract.
            /// @return bps The royalty.
            function royaltyBps() external returns (uint256 bps);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {Mint721Configuration} from "./Mint721Configuration.sol";
        import {IMetadataRenderer} from "./IMetadataRenderer.sol";
        interface IMint721 {
            /// @notice Initializes a new Mint721 contract with the provided configuration.
            /// @dev `mintModules` and `mintModulesData` must have the same cardinality.
            /// @param configuration The configuration data.
            /// @param mintModuleRegistry The mint module registry.
            /// @param metadataRenderer The metadata renderer.
            /// @param metadataRendererConfig The configuration data for the metadata renderer, or none if not required.
            /// @param mintModules The initial approved mint modules.
            /// @param mintModuleData The configuration data for the mint modules.
            /// @param creator The creator of the contract.
            function initialize(
                Mint721Configuration calldata configuration,
                address mintModuleRegistry,
                IMetadataRenderer metadataRenderer,
                bytes calldata metadataRendererConfig,
                address[] calldata mintModules,
                bytes[] calldata mintModuleData,
                address creator
            ) external;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        struct Mint721Configuration {
            /// @notice NFT collection name
            string name;
            /// @notice NFT collection symbol
            string symbol;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        interface IMintModuleRegistryEvents {
            /// @notice Emitted when a new module is registered.
            /// @param module The contract address of the new mint module.
            event ModuleAdded(address indexed module);
            /// @notice Emitted when a module is unregistered.
            /// @param module The address of mint module being removed.
            event ModuleRemoved(address indexed module);
        }
        interface IMintModuleRegistry is IMintModuleRegistryEvents {
            error AlreadyRegistered();
            error NotRegistered();
            error InvalidAddress();
            /// @notice Registers a new mint module.
            /// @dev Can only be executed by protocol admin. Raises `InvalidAddress` if `mintModule` is the zero address.
            /// Raises `AlreadyRegistered` if the module is already registered.
            /// @param mintModule The contract address of the mint module.
            function addModule(address mintModule) external;
            /// @notice Unregisters a mint module.
            /// @dev Can only be executed by protocol admin. Raises `InvalidAddress` if `mintModule` is the zero address.
            /// Raises `NotRegistered` if the module isn't currently registered.
            /// @param mintModule The contract address of the mint module.
            function removeModule(address mintModule) external;
            /// @notice Checks if a mint module is registered.
            /// @param mintModule The contract address of the mint module.
            /// @return isModuleRegistered True if the module is registered, false otherwise.
            function isRegistered(address mintModule) external view returns (bool isModuleRegistered);
            /// @notice Checks if the mint module is registered.
            /// @dev Reverts with `NotRegistered` if the module isn't registered.
            /// @param mintModule The contract address of the mint module.
            function checkModule(address mintModule) external;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        interface IERC4906 {
            /// @dev This event emits when the metadata of a token is changed.
            /// So that the third-party platforms such as NFT market could
            /// timely update the images and related attributes of the NFT.
            event MetadataUpdate(uint256 _tokenId);
            /// @dev This event emits when the metadata of a range of tokens is changed.
            /// So that the third-party platforms such as NFT market could
            /// timely update the images and related attributes of the NFTs.
            event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        abstract contract Version {
            /// @notice The version of the contract.
            uint32 public immutable contractVersion;
            constructor(uint32 _contractVersion) {
                contractVersion = _contractVersion;
            }
        }
        // SPDX-License-Identifier: MIT
        // ERC721A Contracts v4.2.3
        // Creator: Chiru Labs
        pragma solidity ^0.8.4;
        /**
         * @dev Interface of ERC721A.
         */
        interface IERC721AUpgradeable {
            /**
             * The caller must own the token or be an approved operator.
             */
            error ApprovalCallerNotOwnerNorApproved();
            /**
             * The token does not exist.
             */
            error ApprovalQueryForNonexistentToken();
            /**
             * Cannot query the balance for the zero address.
             */
            error BalanceQueryForZeroAddress();
            /**
             * Cannot mint to the zero address.
             */
            error MintToZeroAddress();
            /**
             * The quantity of tokens minted must be more than zero.
             */
            error MintZeroQuantity();
            /**
             * The token does not exist.
             */
            error OwnerQueryForNonexistentToken();
            /**
             * The caller must own the token or be an approved operator.
             */
            error TransferCallerNotOwnerNorApproved();
            /**
             * The token must be owned by `from`.
             */
            error TransferFromIncorrectOwner();
            /**
             * Cannot safely transfer to a contract that does not implement the
             * ERC721Receiver interface.
             */
            error TransferToNonERC721ReceiverImplementer();
            /**
             * Cannot transfer to the zero address.
             */
            error TransferToZeroAddress();
            /**
             * The token does not exist.
             */
            error URIQueryForNonexistentToken();
            /**
             * The `quantity` minted with ERC2309 exceeds the safety limit.
             */
            error MintERC2309QuantityExceedsLimit();
            /**
             * The `extraData` cannot be set on an unintialized ownership slot.
             */
            error OwnershipNotInitializedForExtraData();
            // =============================================================
            //                            STRUCTS
            // =============================================================
            struct TokenOwnership {
                // The address of the owner.
                address addr;
                // Stores the start time of ownership with minimal overhead for tokenomics.
                uint64 startTimestamp;
                // Whether the token has been burned.
                bool burned;
                // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
                uint24 extraData;
            }
            // =============================================================
            //                         TOKEN COUNTERS
            // =============================================================
            /**
             * @dev Returns the total number of tokens in existence.
             * Burned tokens will reduce the count.
             * To get the total number of tokens minted, please see {_totalMinted}.
             */
            function totalSupply() external view returns (uint256);
            // =============================================================
            //                            IERC165
            // =============================================================
            /**
             * @dev Returns true if this contract implements the interface defined by
             * `interfaceId`. See the corresponding
             * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
             * to learn more about how these ids are created.
             *
             * This function call must use less than 30000 gas.
             */
            function supportsInterface(bytes4 interfaceId) external view returns (bool);
            // =============================================================
            //                            IERC721
            // =============================================================
            /**
             * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
             */
            event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
            /**
             * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
             */
            event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
            /**
             * @dev Emitted when `owner` enables or disables
             * (`approved`) `operator` to manage all of its assets.
             */
            event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
            /**
             * @dev Returns the number of tokens in `owner`'s account.
             */
            function balanceOf(address owner) external view returns (uint256 balance);
            /**
             * @dev Returns the owner of the `tokenId` token.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             */
            function ownerOf(uint256 tokenId) external view returns (address owner);
            /**
             * @dev Safely transfers `tokenId` token from `from` to `to`,
             * checking first that contract recipients are aware of the ERC721 protocol
             * to prevent tokens from being forever locked.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must exist and be owned by `from`.
             * - If the caller is not `from`, it must be have been allowed to move
             * this token by either {approve} or {setApprovalForAll}.
             * - If `to` refers to a smart contract, it must implement
             * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
             *
             * Emits a {Transfer} event.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId,
                bytes calldata data
            ) external payable;
            /**
             * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId
            ) external payable;
            /**
             * @dev Transfers `tokenId` from `from` to `to`.
             *
             * WARNING: Usage of this method is discouraged, use {safeTransferFrom}
             * whenever possible.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must be owned by `from`.
             * - If the caller is not `from`, it must be approved to move this token
             * by either {approve} or {setApprovalForAll}.
             *
             * Emits a {Transfer} event.
             */
            function transferFrom(
                address from,
                address to,
                uint256 tokenId
            ) external payable;
            /**
             * @dev Gives permission to `to` to transfer `tokenId` token to another account.
             * The approval is cleared when the token is transferred.
             *
             * Only a single account can be approved at a time, so approving the
             * zero address clears previous approvals.
             *
             * Requirements:
             *
             * - The caller must own the token or be an approved operator.
             * - `tokenId` must exist.
             *
             * Emits an {Approval} event.
             */
            function approve(address to, uint256 tokenId) external payable;
            /**
             * @dev Approve or remove `operator` as an operator for the caller.
             * Operators can call {transferFrom} or {safeTransferFrom}
             * for any token owned by the caller.
             *
             * Requirements:
             *
             * - The `operator` cannot be the caller.
             *
             * Emits an {ApprovalForAll} event.
             */
            function setApprovalForAll(address operator, bool _approved) external;
            /**
             * @dev Returns the account approved for `tokenId` token.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             */
            function getApproved(uint256 tokenId) external view returns (address operator);
            /**
             * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
             *
             * See {setApprovalForAll}.
             */
            function isApprovedForAll(address owner, address operator) external view returns (bool);
            // =============================================================
            //                        IERC721Metadata
            // =============================================================
            /**
             * @dev Returns the token collection name.
             */
            function name() external view returns (string memory);
            /**
             * @dev Returns the token collection symbol.
             */
            function symbol() external view returns (string memory);
            /**
             * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
             */
            function tokenURI(uint256 tokenId) external view returns (string memory);
            // =============================================================
            //                           IERC2309
            // =============================================================
            /**
             * @dev Emitted when tokens in `fromTokenId` to `toTokenId`
             * (inclusive) is transferred from `from` to `to`, as defined in the
             * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
             *
             * See {_mintERC2309} for more details.
             */
            event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /**
         * @dev This is a base contract to aid in writing upgradeable diamond facet 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.
         *
         * 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.
         */
        import {ERC721A__InitializableStorage} from './ERC721A__InitializableStorage.sol';
        abstract contract ERC721A__Initializable {
            using ERC721A__InitializableStorage for ERC721A__InitializableStorage.Layout;
            /**
             * @dev Modifier to protect an initializer function from being invoked twice.
             */
            modifier initializerERC721A() {
                // If the contract is initializing we ignore whether _initialized is set in order to support multiple
                // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
                // contract may have been reentered.
                require(
                    ERC721A__InitializableStorage.layout()._initializing
                        ? _isConstructor()
                        : !ERC721A__InitializableStorage.layout()._initialized,
                    'ERC721A__Initializable: contract is already initialized'
                );
                bool isTopLevelCall = !ERC721A__InitializableStorage.layout()._initializing;
                if (isTopLevelCall) {
                    ERC721A__InitializableStorage.layout()._initializing = true;
                    ERC721A__InitializableStorage.layout()._initialized = true;
                }
                _;
                if (isTopLevelCall) {
                    ERC721A__InitializableStorage.layout()._initializing = false;
                }
            }
            /**
             * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
             * {initializer} modifier, directly or indirectly.
             */
            modifier onlyInitializingERC721A() {
                require(
                    ERC721A__InitializableStorage.layout()._initializing,
                    'ERC721A__Initializable: contract is not initializing'
                );
                _;
            }
            /// @dev Returns true if and only if the function is running in the constructor
            function _isConstructor() private view returns (bool) {
                // extcodesize checks the size of the code stored in an address, and
                // address returns the current address. Since the code is still not
                // deployed when running a constructor, any checks on its code size will
                // yield zero, making it an effective way to detect if a contract is
                // under construction or not.
                address self = address(this);
                uint256 cs;
                assembly {
                    cs := extcodesize(self)
                }
                return cs == 0;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
        pragma solidity ^0.8.0;
        /**
         * @dev Interface of the ERC165 standard, as defined in the
         * https://eips.ethereum.org/EIPS/eip-165[EIP].
         *
         * Implementers can declare support of contract interfaces, which can then be
         * queried by others ({ERC165Checker}).
         *
         * For an implementation, see {ERC165}.
         */
        interface IERC165 {
            /**
             * @dev Returns true if this contract implements the interface defined by
             * `interfaceId`. See the corresponding
             * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
             * to learn more about how these ids are created.
             *
             * This function call must use less than 30 000 gas.
             */
            function supportsInterface(bytes4 interfaceId) external view returns (bool);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /**
         * @dev This is a base storage for the  initialization function for upgradeable diamond facet contracts
         **/
        library ERC721A__InitializableStorage {
            struct Layout {
                /*
                 * Indicates that the contract has been initialized.
                 */
                bool _initialized;
                /*
                 * Indicates that the contract is in the process of being initialized.
                 */
                bool _initializing;
            }
            bytes32 internal constant STORAGE_SLOT = keccak256('ERC721A.contracts.storage.initializable.facet');
            function layout() internal pure returns (Layout storage l) {
                bytes32 slot = STORAGE_SLOT;
                assembly {
                    l.slot := slot
                }
            }
        }
        

        File 3 of 6: BasicMintModule
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {IBasicMintModule, IConfigurable} from "create/interfaces/v1/IBasicMintModule.sol";
        import {IMintPayout} from "create/interfaces/v1/IMintPayout.sol";
        import {IMintContract} from "create/interfaces/v1/IMintContract.sol";
        import {BasicMintConfiguration} from "create/interfaces/v1/BasicMintConfiguration.sol";
        import {Version} from "create/contracts/v1/Version.sol";
        contract BasicMintModule is IBasicMintModule, Version {
            IMintPayout public immutable mintPayout;
            mapping(address => BasicMintConfiguration) private _configurations;
            mapping(address => mapping(address => uint256)) private _mintedByAddress;
            mapping(address => uint256) public mintedByContract;
            /// @notice Emitted when quantity is zero.
            error InvalidQuantity();
            /// @notice Emitted if the collector is minting too many tokens per transaction.
            error TooManyTokensPerTransaction();
            /// @notice Emitted if the collector is minting too many tokens per wallet.
            error TooManyTokensPerCollector();
            /// @notice Emitted if the collector is minting more tokens than this module is allowed to mint.
            error TooManyTokensForModule();
            /// @notice Emitted if the mint has not started yet.
            error MintNotStarted();
            /// @notice Emitted if the mint has ended.
            error MintEnded();
            /// @notice Emitted when the value sent is incorrect.
            error IncorrectPayment();
            /// @notice Emitted when the max supply is reached.
            error MaxSupplyReached();
            constructor(address _mintPayout) Version(1) {
                mintPayout = IMintPayout(_mintPayout);
            }
            /// @inheritdoc IConfigurable
            function updateConfiguration(bytes calldata args) external override {
                BasicMintConfiguration memory _config = abi.decode(args, (BasicMintConfiguration));
                _configurations[msg.sender] = _config;
                emit ConfigurationUpdated(msg.sender, _config);
            }
            /// @inheritdoc IBasicMintModule
            function configuration(address _contract) external view returns (BasicMintConfiguration memory) {
                return _configurations[_contract];
            }
            /// @inheritdoc IBasicMintModule
            function mint(address _contract, address _to, address _referrer, uint256 _quantity) external payable {
                _mint(_contract, _to, _referrer, _quantity);
            }
            /// @inheritdoc IBasicMintModule
            function mint_efficient_7e80c46e(address _contract, address _to, address _referrer, uint256 _quantity)
                external
                payable
            {
                _mint(_contract, _to, _referrer, _quantity);
            }
            /// @notice The implementation of the mint function.
            /// @dev This is implemented as an internal function to share the logic between the `mint` and `mint_efficient_7e80c46e` functions.
            /// See the documentation for those functions for information on the parameters.
            function _mint(address _contract, address _to, address _referrer, uint256 _quantity) internal {
                BasicMintConfiguration memory config = _configurations[_contract];
                if (_quantity == 0) revert InvalidQuantity();
                if (config.maxPerTransaction > 0 && _quantity > config.maxPerTransaction) revert TooManyTokensPerTransaction();
                if (config.maxPerWallet > 0) {
                    if (_mintedByAddress[_contract][_to] + _quantity > config.maxPerWallet) {
                        revert TooManyTokensPerCollector();
                    }
                }
                if (config.maxForModule > 0 && mintedByContract[_contract] + _quantity > config.maxForModule) {
                    revert TooManyTokensForModule();
                }
                if (block.timestamp < config.mintStart) revert MintNotStarted();
                if (config.mintEnd > 0 && block.timestamp > config.mintEnd) revert MintEnded();
                uint256 protocolFee = mintPayout.protocolFee();
                if (msg.value != (config.price + protocolFee) * _quantity) revert IncorrectPayment();
                if (config.maxSupply > 0 && IMintContract(_contract).totalMinted() + _quantity > config.maxSupply) {
                    revert MaxSupplyReached();
                }
                _mintedByAddress[_contract][_to] += _quantity;
                mintedByContract[_contract] += _quantity;
                mintPayout.mintDeposit{value: msg.value}(_contract, msg.sender, _referrer, _quantity);
                IMintContract(_contract).mint(_to, _quantity);
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {BasicMintConfiguration} from "create/interfaces/v1/BasicMintConfiguration.sol";
        import {IConfigurable} from "create/interfaces/v1/IConfigurable.sol";
        interface IBasicMintModuleEvents {
            /// @notice Emitted when a contract's basic mint configuration is updated.
            /// @param _contract The address of the contract being configured.
            /// @param _config The new configuration.
            event ConfigurationUpdated(address indexed _contract, BasicMintConfiguration _config);
        }
        interface IBasicMintModule is IConfigurable, IBasicMintModuleEvents {
            /// @notice Retrieves the basic minting configuration for a contract.
            /// @param _contract The address of the contract.
            /// @return The current minting configuration.
            function configuration(address _contract) external view returns (BasicMintConfiguration memory);
            /// @notice Mints tokens for a NFT contract to a recipient.
            /// @dev Reverts if the mint does not work in the current configuration.
            /// @param _contract The address of the contract to mint for.
            /// @param _to The recipient of the tokens.
            /// @param _referrer The referrer of this mint, or the zero address if none.
            /// @param _quantity The quantity of tokens to mint.
            function mint(address _contract, address _to, address _referrer, uint256 _quantity) external payable;
            /// @notice Mints tokens for a NFT contract to a recipient.
            /// @dev Reverts if the mint does not work in the current configuration.
            /// This function is preferred over `mint` because the four byte signature is 0x00000000 which is cheaper to call.
            /// The implementation is identical to `mint`.
            /// @param _contract The address of the contract to mint for.
            /// @param _to The recipient of the tokens.
            /// @param _referrer The referrer of this mint, or the zero address if none.
            /// @param _quantity The quantity of tokens to mint.
            function mint_efficient_7e80c46e(address _contract, address _to, address _referrer, uint256 _quantity)
                external
                payable;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        interface IMintPayoutEvents {
            /// @notice Emitted when a deposit has been made.
            /// @param from The depositor's address.
            /// @param to The address receiving the deposit.
            /// @param reason The reason code for the deposit.
            /// @param amount The deposit amount.
            event Deposit(address from, address to, bytes4 reason, uint256 amount);
            /// @notice Emitted when a withdrawal has been made.
            /// @param from The address withdrawing.
            /// @param to The address receiving the withdrawn funds.
            /// @param amount The withdrawal amount.
            event Withdraw(address from, address to, uint256 amount);
            /// @notice Emitted during a mint deposit to provide additional context.
            /// @param depositedBy The address of the mint initiator.
            /// @param mintContract The mint contract address this mint deposit refers to.
            /// @param minter The address of the person minting.
            /// @param referrer The address of the referrer, or the zero address for no referrer.
            /// @param creator The address of the contract creator, or the protocol fee recipient if none.
            /// @param creatorPayout The amount being paid to the creator.
            /// @param referralPayout The amount being paid to the referrer.
            /// @param protocolPayout The amount being paid to the protocol.
            /// @param totalAmount The total deposit amount.
            /// @param quantity The number of tokens being minted.
            /// @param protocolFee The per-mint fee for the protocol.
            event MintDeposit(
                address depositedBy,
                address mintContract,
                address minter,
                address referrer,
                address creator,
                uint256 creatorPayout,
                uint256 referralPayout,
                uint256 protocolPayout,
                uint256 totalAmount,
                uint256 quantity,
                uint256 protocolFee
            );
            /// @notice Emitted when the protocol fee is updated.
            /// @param fee The new protocol fee.
            event ProtocolFeeUpdated(uint256 fee);
        }
        interface IMintPayout is IMintPayoutEvents {
            function balanceOf(address owner) external view returns (uint256);
            function totalSupply() external view returns (uint256);
            /// @notice The current protocol fee per-mint.
            function protocolFee() external view returns (uint256 fee);
            /// @notice Sets the protocol fee per-mint.
            /// @dev Only callable by the owner.
            /// @param fee The new protocol fee.
            function setProtocolFee(uint256 fee) external;
            /// @notice Magic value used to represent the fees belonging to the protocol.
            function protocolFeeRecipientAccount() external view returns (address);
            /// @notice Withdraws from the protocol fee balance.
            /// @dev Only callable by the owner.
            /// @param to The address receiving the withdrawn funds.
            /// @param amount The withdrawal amount.
            function withdrawProtocolFee(address to, uint256 amount) external;
            /// @notice Deposits ether for a mint.
            /// @dev Ensure that `quantity` is > 0. The `protocolFee` should be per-mint, not the total taken.
            /// Will trigger a `MintDeposit` event, followed by `Deposit` events for:
            /// creator payout, protocol payout, and referrer payout (if a referrer is specified).
            /// @param mintContract The mint contract address this mint deposit refers to.
            /// @param minter The address of the minter.
            /// @param referrer The address of the referrer, or the zero address for no referrer.
            /// @param quantity The amount being minted.
            function mintDeposit(address mintContract, address minter, address referrer, uint256 quantity) external payable;
            /// @notice Deposits ether to an address.
            /// @param to The address receiving the deposit.
            /// @param reason The reason code for the deposit.
            function deposit(address to, bytes4 reason) external payable;
            /// @notice Deposits ether to multiple addresses.
            /// @dev The length of `recipients`, `amounts`, and `reasons` must be the same.
            /// @param recipients List of addresses receiving the deposits.
            /// @param amounts List of deposit amounts.
            /// @param reasons List of reason codes for the deposits.
            function depositBatch(address[] calldata recipients, uint256[] calldata amounts, bytes4[] calldata reasons)
                external
                payable;
            /// @notice Withdraws ether from the `msg.sender`'s account to a specified address.
            /// @param to The address receiving the withdrawn funds.
            /// @param amount The withdrawal amount.
            function withdraw(address to, uint256 amount) external;
            /// @notice Withdraws all ether from the `msg.sender`'s account to a specified address.
            /// @param to The address receiving the withdrawn funds.
            function withdrawAll(address to) external;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {IMetadataRenderer} from "create/interfaces/v1/IMetadataRenderer.sol";
        interface IMintContractEvents {
            /// @notice Emitted when the royalty is updated.
            event RoyaltyUpdated(uint256 bps);
            /// @notice Emitted when a new mint module is added.
            event ModuleAdded(address module);
            /// @notice Emitted when a mint module is removed.
            event ModuleRemoved(address module);
            /// @notice Emitted when the metadata renderer is updated.
            event MetadataRendererUpdated(address renderer);
        }
        interface IMintContract is IMintContractEvents {
            /// @notice Mints tokens using approved mint modules.
            /// @param to The address receiving the minted tokens.
            /// @param quantity The quantity of tokens to mint.
            function mint(address to, uint256 quantity) external;
            /// @notice Mints tokens, callable only by the contract owner.
            /// @param to The address receiving the minted tokens.
            /// @param quantity The quantity of tokens to mint.
            function adminMint(address to, uint256 quantity) external;
            /// @notice Retrieves the payout recipient address for this mint contract.
            /// @return recipient address of the payout recipient.
            function payoutRecipient() external view returns (address recipient);
            /// @notice Returns the total number of tokens minted.
            /// @return total number of tokens minted.
            function totalMinted() external view returns (uint256 total);
            /// @notice Adds a new mint module as an approved minter.
            /// @dev Can only be executed by the owner of the contract.
            /// Must be approved in the MintModuleRegistry.
            /// @param mintModule The contract address of the mint module.
            function addMintModule(address mintModule) external;
            /// @notice Removes a mint module as an approved minter.
            /// @dev Can only be executed by the owner of the contract.
            /// @param mintModule The contract address of the mint module.
            function removeMintModule(address mintModule) external;
            /// @notice Returns whether a mint module is approved.
            /// @param mintModule The contract address of the mint module.
            /// @return isApproved Whether the mint module is approved.
            function isMintModuleApproved(address mintModule) external view returns (bool isApproved);
            /// @notice Updates configuration located in an external contract.
            /// @dev Can only be executed by the owner of the contract.
            /// The cardinality of `configurables` and `configData` must be the same.
            /// @param configurables The contract addresses to configure.
            /// @param configData The configuration data for the contracts.
            function updateExternalConfiguration(address[] calldata configurables, bytes[] calldata configData) external;
            /// @notice Sets the metadata renderer.
            /// @dev This will not request a metadata refresh. If needed, call `refreshMetadata`.
            /// @param renderer The new metadata renderer.
            function setMetadataRenderer(IMetadataRenderer renderer) external;
            /// @notice Returns the metadata renderer for this contract.
            /// @return metadataRenderer The metadata renderer.
            function metadataRenderer() external returns (IMetadataRenderer metadataRenderer);
            /// @notice Triggers a batch metadata update.
            function refreshMetadata() external;
            /// @notice Updates the royalty for this contract.
            /// @dev Can only be called by the contract owner.
            /// Emits a `RoyaltyUpdated` event.
            /// @param bps The new royalty.
            function setRoyalty(uint256 bps) external;
            /// @notice Returns the royalty for this contract.
            /// @return bps The royalty.
            function royaltyBps() external returns (uint256 bps);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        struct BasicMintConfiguration {
            /// @notice Purchase cost per token.
            uint256 price;
            /// @notice UNIX timestamp of mint start.
            uint64 mintStart;
            /// @notice UNIX timestamp of mint end, or zero if open-ended.
            uint64 mintEnd;
            /// @notice Maximum token purchase limit per wallet, or zero if no limit.
            uint32 maxPerWallet;
            /// @notice Maximum tokens mintable per transaction, or zero if no limit.
            uint32 maxPerTransaction;
            /// @notice Maximum tokens mintable by this module, or zero if no limit.
            uint32 maxForModule;
            /// @notice Maximum tokens that can be minted in total, or zero if no max.
            uint32 maxSupply;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        abstract contract Version {
            /// @notice The version of the contract.
            uint32 public immutable contractVersion;
            constructor(uint32 _contractVersion) {
                contractVersion = _contractVersion;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        interface IConfigurable {
            /// @notice Updates the configuration for the calling contract.
            /// @param data The configuration data.
            function updateConfiguration(bytes calldata data) external;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        interface IMetadataRenderer {
            /// @notice Retrieves the token URI for the specified token ID.
            /// @param tokenId The ID of the token.
            /// @return uri The URI of the token.
            function tokenURI(uint256 tokenId) external view returns (string memory uri);
        }
        

        File 4 of 6: IPFSEditionRenderer
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {Strings} from "openzeppelin/utils/Strings.sol";
        import {Base64} from "openzeppelin/utils/Base64.sol";
        import {IMetadataRenderer} from "create/interfaces/v1/IMetadataRenderer.sol";
        import {IIPFSEditionRenderer, IConfigurable} from "create/interfaces/v1/IIPFSEditionRenderer.sol";
        import {IPFSEditionRendererConfiguration} from "create/interfaces/v1/IPFSEditionRendererConfiguration.sol";
        import {Version} from "create/contracts/v1/Version.sol";
        contract IPFSEditionRenderer is IMetadataRenderer, IIPFSEditionRenderer, Version {
            mapping(address => IPFSEditionRendererConfiguration) _configurations;
            constructor() Version(1) {}
            /// @inheritdoc IConfigurable
            function updateConfiguration(bytes calldata args) external {
                IPFSEditionRendererConfiguration memory config = abi.decode(args, (IPFSEditionRendererConfiguration));
                _configurations[msg.sender] = config;
                emit ConfigurationUpdated(msg.sender, config);
            }
            /// @inheritdoc IIPFSEditionRenderer
            function configuration(address mintContract)
                external
                view
                override
                returns (IPFSEditionRendererConfiguration memory)
            {
                return _configurations[mintContract];
            }
            function tokenURIJSON(address mintContract, uint256 tokenId) public view returns (string memory) {
                IPFSEditionRendererConfiguration memory config = _configurations[mintContract];
                string memory name =
                    string.concat('"name":"', escapeJsonString(config.tokenName), " #", Strings.toString(tokenId), '"');
                string memory description = bytes(config.tokenDescription).length == 0
                    ? ""
                    : string.concat(',"description":"', escapeJsonString(config.tokenDescription), '"');
                string memory image = string.concat(',"image":"ipfs://', config.imageIPFSHash, '"');
                string memory animation = bytes(config.animationIPFSHash).length == 0
                    ? ""
                    : string.concat(
                        ',"animation_url":"ipfs://',
                        config.animationIPFSHash,
                        '","content":{"mime":"',
                        config.animationMimeType,
                        '","uri":"ipfs://',
                        config.animationIPFSHash,
                        '"}'
                    );
                return string.concat("{", name, description, image, animation, "}");
            }
            /// @inheritdoc IMetadataRenderer
            function tokenURI(uint256 tokenId) external view override returns (string memory) {
                return string.concat("data:application/json;base64,", Base64.encode(bytes(tokenURIJSON(msg.sender, tokenId))));
            }
            // JSON escaping code copied from https://github.com/bmeredith/solidity-json-writer
            // Used under MIT license, (c) 2016-2020 zOS Global Limited
            bytes1 constant BACKSLASH = bytes1(uint8(92));
            bytes1 constant BACKSPACE = bytes1(uint8(8));
            bytes1 constant CARRIAGE_RETURN = bytes1(uint8(13));
            bytes1 constant DOUBLE_QUOTE = bytes1(uint8(34));
            bytes1 constant FORM_FEED = bytes1(uint8(12));
            bytes1 constant FRONTSLASH = bytes1(uint8(47));
            bytes1 constant HORIZONTAL_TAB = bytes1(uint8(9));
            bytes1 constant NEWLINE = bytes1(uint8(10));
            function escapeJsonString(string memory value) private pure returns (string memory str) {
                bytes memory b = bytes(value);
                bool foundEscapeChars;
                for (uint256 i; i < b.length; i++) {
                    if (b[i] == BACKSLASH) {
                        foundEscapeChars = true;
                        break;
                    } else if (b[i] == DOUBLE_QUOTE) {
                        foundEscapeChars = true;
                        break;
                    } else if (b[i] == FRONTSLASH) {
                        foundEscapeChars = true;
                        break;
                    } else if (b[i] == HORIZONTAL_TAB) {
                        foundEscapeChars = true;
                        break;
                    } else if (b[i] == FORM_FEED) {
                        foundEscapeChars = true;
                        break;
                    } else if (b[i] == NEWLINE) {
                        foundEscapeChars = true;
                        break;
                    } else if (b[i] == CARRIAGE_RETURN) {
                        foundEscapeChars = true;
                        break;
                    } else if (b[i] == BACKSPACE) {
                        foundEscapeChars = true;
                        break;
                    }
                }
                if (!foundEscapeChars) {
                    return value;
                }
                for (uint256 i; i < b.length; i++) {
                    if (b[i] == BACKSLASH) {
                        str = string(abi.encodePacked(str, "\\\\\\\\"));
                    } else if (b[i] == DOUBLE_QUOTE) {
                        str = string(abi.encodePacked(str, '\\\\"'));
                    } else if (b[i] == FRONTSLASH) {
                        str = string(abi.encodePacked(str, "\\\\/"));
                    } else if (b[i] == HORIZONTAL_TAB) {
                        str = string(abi.encodePacked(str, "\\\\t"));
                    } else if (b[i] == FORM_FEED) {
                        str = string(abi.encodePacked(str, "\\\\f"));
                    } else if (b[i] == NEWLINE) {
                        str = string(abi.encodePacked(str, "\\\
        "));
                    } else if (b[i] == CARRIAGE_RETURN) {
                        str = string(abi.encodePacked(str, "\\\
        "));
                    } else if (b[i] == BACKSPACE) {
                        str = string(abi.encodePacked(str, "\\\\b"));
                    } else {
                        str = string(abi.encodePacked(str, b[i]));
                    }
                }
                return str;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)
        pragma solidity ^0.8.0;
        import "./math/Math.sol";
        /**
         * @dev String operations.
         */
        library Strings {
            bytes16 private constant _SYMBOLS = "0123456789abcdef";
            uint8 private constant _ADDRESS_LENGTH = 20;
            /**
             * @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), _SYMBOLS))
                        }
                        value /= 10;
                        if (value == 0) break;
                    }
                    return buffer;
                }
            }
            /**
             * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
             */
            function toHexString(uint256 value) internal pure returns (string memory) {
                unchecked {
                    return toHexString(value, Math.log256(value) + 1);
                }
            }
            /**
             * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
             */
            function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                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] = _SYMBOLS[value & 0xf];
                    value >>= 4;
                }
                require(value == 0, "Strings: hex length insufficient");
                return string(buffer);
            }
            /**
             * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
             */
            function toHexString(address addr) internal pure returns (string memory) {
                return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol)
        pragma solidity ^0.8.0;
        /**
         * @dev Provides a set of functions to operate with Base64 strings.
         *
         * _Available since v4.5._
         */
        library Base64 {
            /**
             * @dev Base64 Encoding/Decoding Table
             */
            string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
            /**
             * @dev Converts a `bytes` to its Bytes64 `string` representation.
             */
            function encode(bytes memory data) internal pure returns (string memory) {
                /**
                 * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
                 * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
                 */
                if (data.length == 0) return "";
                // Loads the table into memory
                string memory table = _TABLE;
                // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
                // and split into 4 numbers of 6 bits.
                // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
                // - `data.length + 2`  -> Round up
                // - `/ 3`              -> Number of 3-bytes chunks
                // - `4 *`              -> 4 characters for each chunk
                string memory result = new string(4 * ((data.length + 2) / 3));
                /// @solidity memory-safe-assembly
                assembly {
                    // Prepare the lookup table (skip the first "length" byte)
                    let tablePtr := add(table, 1)
                    // Prepare result pointer, jump over length
                    let resultPtr := add(result, 32)
                    // Run over the input, 3 bytes at a time
                    for {
                        let dataPtr := data
                        let endPtr := add(data, mload(data))
                    } lt(dataPtr, endPtr) {
                    } {
                        // Advance 3 bytes
                        dataPtr := add(dataPtr, 3)
                        let input := mload(dataPtr)
                        // To write each character, shift the 3 bytes (18 bits) chunk
                        // 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
                        // and apply logical AND with 0x3F which is the number of
                        // the previous character in the ASCII table prior to the Base64 Table
                        // The result is then added to the table to get the character to write,
                        // and finally write it in the result pointer but with a left shift
                        // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits
                        mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                        resultPtr := add(resultPtr, 1) // Advance
                        mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                        resultPtr := add(resultPtr, 1) // Advance
                        mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
                        resultPtr := add(resultPtr, 1) // Advance
                        mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
                        resultPtr := add(resultPtr, 1) // Advance
                    }
                    // When data `bytes` is not exactly 3 bytes long
                    // it is padded with `=` characters at the end
                    switch mod(mload(data), 3)
                    case 1 {
                        mstore8(sub(resultPtr, 1), 0x3d)
                        mstore8(sub(resultPtr, 2), 0x3d)
                    }
                    case 2 {
                        mstore8(sub(resultPtr, 1), 0x3d)
                    }
                }
                return result;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        interface IMetadataRenderer {
            /// @notice Retrieves the token URI for the specified token ID.
            /// @param tokenId The ID of the token.
            /// @return uri The URI of the token.
            function tokenURI(uint256 tokenId) external view returns (string memory uri);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {IPFSEditionRendererConfiguration} from "create/interfaces/v1/IPFSEditionRendererConfiguration.sol";
        import {IConfigurable} from "create/interfaces/v1/IConfigurable.sol";
        interface IIPFSEditionRendererEvents {
            /// @notice Emitted when the configuration is updated for a mint contract.
            /// @param mintContract The address of the contract being configured.
            /// @param config The new configuration.
            event ConfigurationUpdated(address indexed mintContract, IPFSEditionRendererConfiguration config);
        }
        interface IIPFSEditionRenderer is IIPFSEditionRendererEvents, IConfigurable {
            /// @notice Retrieves the configuration for a contract.
            /// @param mintContract The contract to retreive the configuration for.
            /// @return config The current configuration.
            function configuration(address mintContract)
                external
                view
                returns (IPFSEditionRendererConfiguration memory config);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        struct IPFSEditionRendererConfiguration {
            /// @notice Name of the token
            string tokenName;
            /// @notice Description of the token
            string tokenDescription;
            /// @notice IPFS hash for token's image content
            string imageIPFSHash;
            /// @notice IPFS hash for token's animated content (if any)
            /// If empty, no animated content is associated with the token
            string animationIPFSHash;
            /// @notice Mime type for token's animated content (if any)
            string animationMimeType;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        abstract contract Version {
            /// @notice The version of the contract.
            uint32 public immutable contractVersion;
            constructor(uint32 _contractVersion) {
                contractVersion = _contractVersion;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)
        pragma solidity ^0.8.0;
        /**
         * @dev Standard math utilities missing in the Solidity language.
         */
        library Math {
            enum Rounding {
                Down, // Toward negative infinity
                Up, // Toward infinity
                Zero // Toward zero
            }
            /**
             * @dev Returns the largest of two numbers.
             */
            function max(uint256 a, uint256 b) internal pure returns (uint256) {
                return a > b ? a : b;
            }
            /**
             * @dev Returns the smallest of two numbers.
             */
            function min(uint256 a, uint256 b) internal pure returns (uint256) {
                return a < b ? a : b;
            }
            /**
             * @dev Returns the average of two numbers. The result is rounded towards
             * zero.
             */
            function average(uint256 a, uint256 b) internal pure returns (uint256) {
                // (a + b) / 2 can overflow.
                return (a & b) + (a ^ b) / 2;
            }
            /**
             * @dev Returns the ceiling of the division of two numbers.
             *
             * This differs from standard division with `/` in that it rounds up instead
             * of rounding down.
             */
            function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
                // (a + b - 1) / b can overflow on addition, so we distribute.
                return a == 0 ? 0 : (a - 1) / b + 1;
            }
            /**
             * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
             * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
             * with further edits by Uniswap Labs also under MIT license.
             */
            function mulDiv(
                uint256 x,
                uint256 y,
                uint256 denominator
            ) internal pure returns (uint256 result) {
                unchecked {
                    // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                    // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                    // variables such that product = prod1 * 2^256 + prod0.
                    uint256 prod0; // Least significant 256 bits of the product
                    uint256 prod1; // Most significant 256 bits of the product
                    assembly {
                        let mm := mulmod(x, y, not(0))
                        prod0 := mul(x, y)
                        prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                    }
                    // Handle non-overflow cases, 256 by 256 division.
                    if (prod1 == 0) {
                        return prod0 / denominator;
                    }
                    // Make sure the result is less than 2^256. Also prevents denominator == 0.
                    require(denominator > prod1);
                    ///////////////////////////////////////////////
                    // 512 by 256 division.
                    ///////////////////////////////////////////////
                    // Make division exact by subtracting the remainder from [prod1 prod0].
                    uint256 remainder;
                    assembly {
                        // Compute remainder using mulmod.
                        remainder := mulmod(x, y, denominator)
                        // Subtract 256 bit number from 512 bit number.
                        prod1 := sub(prod1, gt(remainder, prod0))
                        prod0 := sub(prod0, remainder)
                    }
                    // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
                    // See https://cs.stackexchange.com/q/138556/92363.
                    // Does not overflow because the denominator cannot be zero at this stage in the function.
                    uint256 twos = denominator & (~denominator + 1);
                    assembly {
                        // Divide denominator by twos.
                        denominator := div(denominator, twos)
                        // Divide [prod1 prod0] by twos.
                        prod0 := div(prod0, twos)
                        // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                        twos := add(div(sub(0, twos), twos), 1)
                    }
                    // Shift in bits from prod1 into prod0.
                    prod0 |= prod1 * twos;
                    // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                    // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                    // four bits. That is, denominator * inv = 1 mod 2^4.
                    uint256 inverse = (3 * denominator) ^ 2;
                    // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
                    // in modular arithmetic, doubling the correct bits in each step.
                    inverse *= 2 - denominator * inverse; // inverse mod 2^8
                    inverse *= 2 - denominator * inverse; // inverse mod 2^16
                    inverse *= 2 - denominator * inverse; // inverse mod 2^32
                    inverse *= 2 - denominator * inverse; // inverse mod 2^64
                    inverse *= 2 - denominator * inverse; // inverse mod 2^128
                    inverse *= 2 - denominator * inverse; // inverse mod 2^256
                    // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                    // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                    // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                    // is no longer required.
                    result = prod0 * inverse;
                    return result;
                }
            }
            /**
             * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
             */
            function mulDiv(
                uint256 x,
                uint256 y,
                uint256 denominator,
                Rounding rounding
            ) internal pure returns (uint256) {
                uint256 result = mulDiv(x, y, denominator);
                if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
                    result += 1;
                }
                return result;
            }
            /**
             * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
             *
             * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
             */
            function sqrt(uint256 a) internal pure returns (uint256) {
                if (a == 0) {
                    return 0;
                }
                // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
                //
                // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
                // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
                //
                // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
                // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
                // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
                //
                // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
                uint256 result = 1 << (log2(a) >> 1);
                // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
                // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
                // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
                // into the expected uint128 result.
                unchecked {
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    result = (result + a / result) >> 1;
                    return min(result, a / result);
                }
            }
            /**
             * @notice Calculates sqrt(a), following the selected rounding direction.
             */
            function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
                unchecked {
                    uint256 result = sqrt(a);
                    return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
                }
            }
            /**
             * @dev Return the log in base 2, rounded down, of a positive value.
             * Returns 0 if given 0.
             */
            function log2(uint256 value) internal pure returns (uint256) {
                uint256 result = 0;
                unchecked {
                    if (value >> 128 > 0) {
                        value >>= 128;
                        result += 128;
                    }
                    if (value >> 64 > 0) {
                        value >>= 64;
                        result += 64;
                    }
                    if (value >> 32 > 0) {
                        value >>= 32;
                        result += 32;
                    }
                    if (value >> 16 > 0) {
                        value >>= 16;
                        result += 16;
                    }
                    if (value >> 8 > 0) {
                        value >>= 8;
                        result += 8;
                    }
                    if (value >> 4 > 0) {
                        value >>= 4;
                        result += 4;
                    }
                    if (value >> 2 > 0) {
                        value >>= 2;
                        result += 2;
                    }
                    if (value >> 1 > 0) {
                        result += 1;
                    }
                }
                return result;
            }
            /**
             * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
             * Returns 0 if given 0.
             */
            function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
                unchecked {
                    uint256 result = log2(value);
                    return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
                }
            }
            /**
             * @dev Return the log in base 10, rounded down, of a positive value.
             * Returns 0 if given 0.
             */
            function log10(uint256 value) internal pure returns (uint256) {
                uint256 result = 0;
                unchecked {
                    if (value >= 10**64) {
                        value /= 10**64;
                        result += 64;
                    }
                    if (value >= 10**32) {
                        value /= 10**32;
                        result += 32;
                    }
                    if (value >= 10**16) {
                        value /= 10**16;
                        result += 16;
                    }
                    if (value >= 10**8) {
                        value /= 10**8;
                        result += 8;
                    }
                    if (value >= 10**4) {
                        value /= 10**4;
                        result += 4;
                    }
                    if (value >= 10**2) {
                        value /= 10**2;
                        result += 2;
                    }
                    if (value >= 10**1) {
                        result += 1;
                    }
                }
                return result;
            }
            /**
             * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
             * Returns 0 if given 0.
             */
            function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
                unchecked {
                    uint256 result = log10(value);
                    return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
                }
            }
            /**
             * @dev Return the log in base 256, rounded down, of a positive value.
             * Returns 0 if given 0.
             *
             * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
             */
            function log256(uint256 value) internal pure returns (uint256) {
                uint256 result = 0;
                unchecked {
                    if (value >> 128 > 0) {
                        value >>= 128;
                        result += 16;
                    }
                    if (value >> 64 > 0) {
                        value >>= 64;
                        result += 8;
                    }
                    if (value >> 32 > 0) {
                        value >>= 32;
                        result += 4;
                    }
                    if (value >> 16 > 0) {
                        value >>= 16;
                        result += 2;
                    }
                    if (value >> 8 > 0) {
                        result += 1;
                    }
                }
                return result;
            }
            /**
             * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
             * Returns 0 if given 0.
             */
            function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
                unchecked {
                    uint256 result = log256(value);
                    return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        interface IConfigurable {
            /// @notice Updates the configuration for the calling contract.
            /// @param data The configuration data.
            function updateConfiguration(bytes calldata data) external;
        }
        

        File 5 of 6: Mint721
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {ERC721AUpgradeable} from "erc721a-upgradeable/ERC721AUpgradeable.sol";
        import {ERC721AStorage} from "erc721a-upgradeable/ERC721AStorage.sol";
        import {Ownable} from "solady/auth/Ownable.sol";
        import {IERC2981} from "openzeppelin/interfaces/IERC2981.sol";
        import {IERC165} from "openzeppelin/interfaces/IERC165.sol";
        import {IMetadataRenderer} from "create/interfaces/v1/IMetadataRenderer.sol";
        import {IMintContract} from "create/interfaces/v1/IMintContract.sol";
        import {IMint721} from "create/interfaces/v1/IMint721.sol";
        import {Mint721Configuration} from "create/interfaces/v1/Mint721Configuration.sol";
        import {IMintModuleRegistry} from "create/interfaces/v1/IMintModuleRegistry.sol";
        import {IERC4906} from "create/interfaces/v1/IERC4906.sol";
        import {Version} from "create/contracts/v1/Version.sol";
        contract Mint721 is ERC721AUpgradeable, IMintContract, IMint721, IERC4906, IERC2981, Ownable, Version {
            bytes4 private constant _updateConfigurationSelector = bytes4(keccak256("updateConfiguration(bytes)"));
            IMintModuleRegistry private _mintModuleRegistry;
            /// @inheritdoc IMintContract
            IMetadataRenderer public metadataRenderer;
            /// @inheritdoc IMintContract
            mapping(address => bool) public isMintModuleApproved;
            /// @inheritdoc IMintContract
            uint256 public royaltyBps;
            error UnapprovedMintModule();
            error OnlyEOAAdminMintAllowed();
            error AlreadyInitialized();
            error ModuleUpdateFailed();
            error InvalidMintModuleData();
            error InvalidRoyalty();
            constructor() Version(1) {}
            /// @inheritdoc IMint721
            function initialize(
                Mint721Configuration calldata config,
                address mintModuleRegistry_,
                IMetadataRenderer _metadataRenderer,
                bytes calldata metadataRendererConfig,
                address[] calldata mintModules,
                bytes[] calldata mintModuleData,
                address creator
            ) external {
                if (ERC721AStorage.layout()._currentIndex != 0) revert AlreadyInitialized();
                ERC721AStorage.layout()._name = config.name;
                ERC721AStorage.layout()._symbol = config.symbol;
                ERC721AStorage.layout()._currentIndex = _startTokenId();
                _mintModuleRegistry = IMintModuleRegistry(mintModuleRegistry_);
                _initializeOwner(creator);
                _setMetadataRenderer(_metadataRenderer);
                if (mintModules.length != mintModuleData.length) revert InvalidMintModuleData();
                for (uint256 i; i < mintModules.length;) {
                    address mintModule = mintModules[i];
                    _addMintModule(mintModule);
                    _updateExternalConfiguration(mintModule, mintModuleData[i]);
                    unchecked {
                        ++i;
                    }
                }
                if (metadataRendererConfig.length > 0) {
                    _updateExternalConfiguration(address(_metadataRenderer), metadataRendererConfig);
                }
            }
            /// @inheritdoc IMintContract
            function mint(address to, uint256 quantity) external {
                if (!isMintModuleApproved[msg.sender]) revert UnapprovedMintModule();
                _mint(to, quantity);
            }
            /// @inheritdoc IMintContract
            function adminMint(address to, uint256 quantity) external onlyOwner {
                if (tx.origin != msg.sender) revert OnlyEOAAdminMintAllowed();
                _mint(to, quantity);
            }
            /// @inheritdoc IMintContract
            function payoutRecipient() external view override returns (address) {
                return owner();
            }
            /// @inheritdoc IMintContract
            function totalMinted() external view override returns (uint256) {
                return _totalMinted();
            }
            /// @inheritdoc IMintContract
            function addMintModule(address mintModule) external onlyOwner {
                _addMintModule(mintModule);
            }
            function _addMintModule(address mintModule) internal {
                _mintModuleRegistry.checkModule(mintModule);
                isMintModuleApproved[mintModule] = true;
                emit ModuleAdded(mintModule);
            }
            /// @inheritdoc IMintContract
            function removeMintModule(address mintModule) external onlyOwner {
                _removeMintModule(mintModule);
            }
            /// @dev We don't check if it is a valid module intentionally while removing.
            function _removeMintModule(address mintModule) internal {
                delete isMintModuleApproved[mintModule];
                emit ModuleRemoved(mintModule);
            }
            /// @inheritdoc IMintContract
            function setRoyalty(uint256 bps) external onlyOwner {
                if (bps > 1000) revert InvalidRoyalty(); // disallow over 10%
                royaltyBps = bps;
                emit RoyaltyUpdated(bps);
            }
            /// @inheritdoc IERC2981
            function royaltyInfo(uint256, uint256 _salePrice) public view virtual override returns (address, uint256) {
                uint256 royaltyAmount = (_salePrice * royaltyBps) / 10000;
                return (owner(), royaltyAmount);
            }
            /// @inheritdoc IMintContract
            function refreshMetadata() external onlyOwner {
                emit BatchMetadataUpdate(_startTokenId(), type(uint256).max);
            }
            /// @inheritdoc IMintContract
            function updateExternalConfiguration(address[] memory configurable, bytes[] calldata configData)
                external
                override
                onlyOwner
            {
                if (configurable.length != configData.length) revert InvalidMintModuleData();
                for (uint256 i; i < configurable.length;) {
                    _updateExternalConfiguration(configurable[i], configData[i]);
                    unchecked {
                        ++i;
                    }
                }
            }
            function _updateExternalConfiguration(address configurable, bytes calldata configData) internal {
                (bool ok,) = configurable.call(abi.encodeWithSelector(_updateConfigurationSelector, configData));
                if (!ok) revert ModuleUpdateFailed();
            }
            /// @inheritdoc IMintContract
            function setMetadataRenderer(IMetadataRenderer _metadataRenderer) external onlyOwner {
                _setMetadataRenderer(_metadataRenderer);
            }
            function _setMetadataRenderer(IMetadataRenderer _metadataRenderer) internal {
                metadataRenderer = _metadataRenderer;
                emit MetadataRendererUpdated(address(_metadataRenderer));
            }
            /// @inheritdoc ERC721AUpgradeable
            function _startTokenId() internal pure virtual override returns (uint256) {
                return 1;
            }
            /// @inheritdoc ERC721AUpgradeable
            function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
                if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
                return metadataRenderer.tokenURI(tokenId);
            }
            /// @inheritdoc ERC721AUpgradeable
            function supportsInterface(bytes4 interfaceId)
                public
                view
                virtual
                override(ERC721AUpgradeable, IERC165)
                returns (bool)
            {
                return super.supportsInterface(interfaceId) || interfaceId == type(IMint721).interfaceId
                    || interfaceId == type(IMintContract).interfaceId || interfaceId == type(IERC4906).interfaceId
                    || interfaceId == type(IERC2981).interfaceId;
            }
        }
        // SPDX-License-Identifier: MIT
        // ERC721A Contracts v4.2.3
        // Creator: Chiru Labs
        pragma solidity ^0.8.4;
        import './IERC721AUpgradeable.sol';
        import {ERC721AStorage} from './ERC721AStorage.sol';
        import './ERC721A__Initializable.sol';
        /**
         * @dev Interface of ERC721 token receiver.
         */
        interface ERC721A__IERC721ReceiverUpgradeable {
            function onERC721Received(
                address operator,
                address from,
                uint256 tokenId,
                bytes calldata data
            ) external returns (bytes4);
        }
        /**
         * @title ERC721A
         *
         * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
         * Non-Fungible Token Standard, including the Metadata extension.
         * Optimized for lower gas during batch mints.
         *
         * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
         * starting from `_startTokenId()`.
         *
         * Assumptions:
         *
         * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
         * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
         */
        contract ERC721AUpgradeable is ERC721A__Initializable, IERC721AUpgradeable {
            using ERC721AStorage for ERC721AStorage.Layout;
            // =============================================================
            //                           CONSTANTS
            // =============================================================
            // Mask of an entry in packed address data.
            uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
            // The bit position of `numberMinted` in packed address data.
            uint256 private constant _BITPOS_NUMBER_MINTED = 64;
            // The bit position of `numberBurned` in packed address data.
            uint256 private constant _BITPOS_NUMBER_BURNED = 128;
            // The bit position of `aux` in packed address data.
            uint256 private constant _BITPOS_AUX = 192;
            // Mask of all 256 bits in packed address data except the 64 bits for `aux`.
            uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
            // The bit position of `startTimestamp` in packed ownership.
            uint256 private constant _BITPOS_START_TIMESTAMP = 160;
            // The bit mask of the `burned` bit in packed ownership.
            uint256 private constant _BITMASK_BURNED = 1 << 224;
            // The bit position of the `nextInitialized` bit in packed ownership.
            uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
            // The bit mask of the `nextInitialized` bit in packed ownership.
            uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
            // The bit position of `extraData` in packed ownership.
            uint256 private constant _BITPOS_EXTRA_DATA = 232;
            // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
            uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
            // The mask of the lower 160 bits for addresses.
            uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
            // The maximum `quantity` that can be minted with {_mintERC2309}.
            // This limit is to prevent overflows on the address data entries.
            // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
            // is required to cause an overflow, which is unrealistic.
            uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
            // The `Transfer` event signature is given by:
            // `keccak256(bytes("Transfer(address,address,uint256)"))`.
            bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
                0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
            // =============================================================
            //                          CONSTRUCTOR
            // =============================================================
            function __ERC721A_init(string memory name_, string memory symbol_) internal onlyInitializingERC721A {
                __ERC721A_init_unchained(name_, symbol_);
            }
            function __ERC721A_init_unchained(string memory name_, string memory symbol_) internal onlyInitializingERC721A {
                ERC721AStorage.layout()._name = name_;
                ERC721AStorage.layout()._symbol = symbol_;
                ERC721AStorage.layout()._currentIndex = _startTokenId();
            }
            // =============================================================
            //                   TOKEN COUNTING OPERATIONS
            // =============================================================
            /**
             * @dev Returns the starting token ID.
             * To change the starting token ID, please override this function.
             */
            function _startTokenId() internal view virtual returns (uint256) {
                return 0;
            }
            /**
             * @dev Returns the next token ID to be minted.
             */
            function _nextTokenId() internal view virtual returns (uint256) {
                return ERC721AStorage.layout()._currentIndex;
            }
            /**
             * @dev Returns the total number of tokens in existence.
             * Burned tokens will reduce the count.
             * To get the total number of tokens minted, please see {_totalMinted}.
             */
            function totalSupply() public view virtual override returns (uint256) {
                // Counter underflow is impossible as _burnCounter cannot be incremented
                // more than `_currentIndex - _startTokenId()` times.
                unchecked {
                    return ERC721AStorage.layout()._currentIndex - ERC721AStorage.layout()._burnCounter - _startTokenId();
                }
            }
            /**
             * @dev Returns the total amount of tokens minted in the contract.
             */
            function _totalMinted() internal view virtual returns (uint256) {
                // Counter underflow is impossible as `_currentIndex` does not decrement,
                // and it is initialized to `_startTokenId()`.
                unchecked {
                    return ERC721AStorage.layout()._currentIndex - _startTokenId();
                }
            }
            /**
             * @dev Returns the total number of tokens burned.
             */
            function _totalBurned() internal view virtual returns (uint256) {
                return ERC721AStorage.layout()._burnCounter;
            }
            // =============================================================
            //                    ADDRESS DATA OPERATIONS
            // =============================================================
            /**
             * @dev Returns the number of tokens in `owner`'s account.
             */
            function balanceOf(address owner) public view virtual override returns (uint256) {
                if (owner == address(0)) revert BalanceQueryForZeroAddress();
                return ERC721AStorage.layout()._packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
            }
            /**
             * Returns the number of tokens minted by `owner`.
             */
            function _numberMinted(address owner) internal view returns (uint256) {
                return
                    (ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
            }
            /**
             * Returns the number of tokens burned by or on behalf of `owner`.
             */
            function _numberBurned(address owner) internal view returns (uint256) {
                return
                    (ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
            }
            /**
             * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
             */
            function _getAux(address owner) internal view returns (uint64) {
                return uint64(ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_AUX);
            }
            /**
             * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
             * If there are multiple variables, please pack them into a uint64.
             */
            function _setAux(address owner, uint64 aux) internal virtual {
                uint256 packed = ERC721AStorage.layout()._packedAddressData[owner];
                uint256 auxCasted;
                // Cast `aux` with assembly to avoid redundant masking.
                assembly {
                    auxCasted := aux
                }
                packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
                ERC721AStorage.layout()._packedAddressData[owner] = packed;
            }
            // =============================================================
            //                            IERC165
            // =============================================================
            /**
             * @dev Returns true if this contract implements the interface defined by
             * `interfaceId`. See the corresponding
             * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
             * to learn more about how these ids are created.
             *
             * This function call must use less than 30000 gas.
             */
            function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                // The interface IDs are constants representing the first 4 bytes
                // of the XOR of all function selectors in the interface.
                // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
                // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
                return
                    interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
                    interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
                    interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
            }
            // =============================================================
            //                        IERC721Metadata
            // =============================================================
            /**
             * @dev Returns the token collection name.
             */
            function name() public view virtual override returns (string memory) {
                return ERC721AStorage.layout()._name;
            }
            /**
             * @dev Returns the token collection symbol.
             */
            function symbol() public view virtual override returns (string memory) {
                return ERC721AStorage.layout()._symbol;
            }
            /**
             * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
             */
            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))) : '';
            }
            /**
             * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
             * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
             * by default, it can be overridden in child contracts.
             */
            function _baseURI() internal view virtual returns (string memory) {
                return '';
            }
            // =============================================================
            //                     OWNERSHIPS OPERATIONS
            // =============================================================
            /**
             * @dev Returns the owner of the `tokenId` token.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             */
            function ownerOf(uint256 tokenId) public view virtual override returns (address) {
                return address(uint160(_packedOwnershipOf(tokenId)));
            }
            /**
             * @dev Gas spent here starts off proportional to the maximum mint batch size.
             * It gradually moves to O(1) as tokens get transferred around over time.
             */
            function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
                return _unpackedOwnership(_packedOwnershipOf(tokenId));
            }
            /**
             * @dev Returns the unpacked `TokenOwnership` struct at `index`.
             */
            function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
                return _unpackedOwnership(ERC721AStorage.layout()._packedOwnerships[index]);
            }
            /**
             * @dev Initializes the ownership slot minted at `index` for efficiency purposes.
             */
            function _initializeOwnershipAt(uint256 index) internal virtual {
                if (ERC721AStorage.layout()._packedOwnerships[index] == 0) {
                    ERC721AStorage.layout()._packedOwnerships[index] = _packedOwnershipOf(index);
                }
            }
            /**
             * Returns the packed ownership data of `tokenId`.
             */
            function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) {
                if (_startTokenId() <= tokenId) {
                    packed = ERC721AStorage.layout()._packedOwnerships[tokenId];
                    // If not burned.
                    if (packed & _BITMASK_BURNED == 0) {
                        // If the data at the starting slot does not exist, start the scan.
                        if (packed == 0) {
                            if (tokenId >= ERC721AStorage.layout()._currentIndex) revert OwnerQueryForNonexistentToken();
                            // Invariant:
                            // There will always be an initialized ownership slot
                            // (i.e. `ownership.addr != address(0) && ownership.burned == false`)
                            // before an unintialized ownership slot
                            // (i.e. `ownership.addr == address(0) && ownership.burned == false`)
                            // Hence, `tokenId` will not underflow.
                            //
                            // We can directly compare the packed value.
                            // If the address is zero, packed will be zero.
                            for (;;) {
                                unchecked {
                                    packed = ERC721AStorage.layout()._packedOwnerships[--tokenId];
                                }
                                if (packed == 0) continue;
                                return packed;
                            }
                        }
                        // Otherwise, the data exists and is not burned. We can skip the scan.
                        // This is possible because we have already achieved the target condition.
                        // This saves 2143 gas on transfers of initialized tokens.
                        return packed;
                    }
                }
                revert OwnerQueryForNonexistentToken();
            }
            /**
             * @dev Returns the unpacked `TokenOwnership` struct from `packed`.
             */
            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);
            }
            /**
             * @dev Packs ownership data into a single uint256.
             */
            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))
                }
            }
            /**
             * @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
             */
            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))
                }
            }
            // =============================================================
            //                      APPROVAL OPERATIONS
            // =============================================================
            /**
             * @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}.
             *
             * Requirements:
             *
             * - The caller must own the token or be an approved operator.
             */
            function approve(address to, uint256 tokenId) public payable virtual override {
                _approve(to, tokenId, true);
            }
            /**
             * @dev Returns the account approved for `tokenId` token.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             */
            function getApproved(uint256 tokenId) public view virtual override returns (address) {
                if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
                return ERC721AStorage.layout()._tokenApprovals[tokenId].value;
            }
            /**
             * @dev Approve or remove `operator` as an operator for the caller.
             * Operators can call {transferFrom} or {safeTransferFrom}
             * for any token owned by the caller.
             *
             * Requirements:
             *
             * - The `operator` cannot be the caller.
             *
             * Emits an {ApprovalForAll} event.
             */
            function setApprovalForAll(address operator, bool approved) public virtual override {
                ERC721AStorage.layout()._operatorApprovals[_msgSenderERC721A()][operator] = approved;
                emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
            }
            /**
             * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
             *
             * See {setApprovalForAll}.
             */
            function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
                return ERC721AStorage.layout()._operatorApprovals[owner][operator];
            }
            /**
             * @dev Returns whether `tokenId` exists.
             *
             * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
             *
             * Tokens start existing when they are minted. See {_mint}.
             */
            function _exists(uint256 tokenId) internal view virtual returns (bool) {
                return
                    _startTokenId() <= tokenId &&
                    tokenId < ERC721AStorage.layout()._currentIndex && // If within bounds,
                    ERC721AStorage.layout()._packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.
            }
            /**
             * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
             */
            function _isSenderApprovedOrOwner(
                address approvedAddress,
                address owner,
                address msgSender
            ) private pure returns (bool result) {
                assembly {
                    // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
                    owner := and(owner, _BITMASK_ADDRESS)
                    // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
                    msgSender := and(msgSender, _BITMASK_ADDRESS)
                    // `msgSender == owner || msgSender == approvedAddress`.
                    result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
                }
            }
            /**
             * @dev Returns the storage slot and value for the approved address of `tokenId`.
             */
            function _getApprovedSlotAndAddress(uint256 tokenId)
                private
                view
                returns (uint256 approvedAddressSlot, address approvedAddress)
            {
                ERC721AStorage.TokenApprovalRef storage tokenApproval = ERC721AStorage.layout()._tokenApprovals[tokenId];
                // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
                assembly {
                    approvedAddressSlot := tokenApproval.slot
                    approvedAddress := sload(approvedAddressSlot)
                }
            }
            // =============================================================
            //                      TRANSFER OPERATIONS
            // =============================================================
            /**
             * @dev Transfers `tokenId` from `from` to `to`.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must be owned by `from`.
             * - If the caller is not `from`, it must be approved to move this token
             * by either {approve} or {setApprovalForAll}.
             *
             * Emits a {Transfer} event.
             */
            function transferFrom(
                address from,
                address to,
                uint256 tokenId
            ) public payable virtual override {
                uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
                if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();
                (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
                // The nested ifs save around 20+ gas over a compound boolean condition.
                if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                    if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
                if (to == address(0)) revert TransferToZeroAddress();
                _beforeTokenTransfers(from, to, tokenId, 1);
                // Clear approvals from the previous owner.
                assembly {
                    if approvedAddress {
                        // This is equivalent to `delete _tokenApprovals[tokenId]`.
                        sstore(approvedAddressSlot, 0)
                    }
                }
                // Underflow of the sender's balance is impossible because we check for
                // ownership above and the recipient's balance can't realistically overflow.
                // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
                unchecked {
                    // We can directly increment and decrement the balances.
                    --ERC721AStorage.layout()._packedAddressData[from]; // Updates: `balance -= 1`.
                    ++ERC721AStorage.layout()._packedAddressData[to]; // Updates: `balance += 1`.
                    // Updates:
                    // - `address` to the next owner.
                    // - `startTimestamp` to the timestamp of transfering.
                    // - `burned` to `false`.
                    // - `nextInitialized` to `true`.
                    ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData(
                        to,
                        _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
                    );
                    // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
                    if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                        uint256 nextTokenId = tokenId + 1;
                        // If the next slot's address is zero and not burned (i.e. packed value is zero).
                        if (ERC721AStorage.layout()._packedOwnerships[nextTokenId] == 0) {
                            // If the next slot is within bounds.
                            if (nextTokenId != ERC721AStorage.layout()._currentIndex) {
                                // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                                ERC721AStorage.layout()._packedOwnerships[nextTokenId] = prevOwnershipPacked;
                            }
                        }
                    }
                }
                emit Transfer(from, to, tokenId);
                _afterTokenTransfers(from, to, tokenId, 1);
            }
            /**
             * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId
            ) public payable virtual override {
                safeTransferFrom(from, to, tokenId, '');
            }
            /**
             * @dev Safely transfers `tokenId` token from `from` to `to`.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must exist and be owned by `from`.
             * - If the caller is not `from`, it must be approved to move this token
             * by either {approve} or {setApprovalForAll}.
             * - If `to` refers to a smart contract, it must implement
             * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
             *
             * Emits a {Transfer} event.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId,
                bytes memory _data
            ) public payable virtual override {
                transferFrom(from, to, tokenId);
                if (to.code.length != 0)
                    if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
                        revert TransferToNonERC721ReceiverImplementer();
                    }
            }
            /**
             * @dev Hook that is called before a set of serially-ordered token IDs
             * are about to be transferred. This includes minting.
             * And also called before burning one token.
             *
             * `startTokenId` - the first token ID to be transferred.
             * `quantity` - the amount to be transferred.
             *
             * Calling conditions:
             *
             * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
             * transferred to `to`.
             * - When `from` is zero, `tokenId` will be minted for `to`.
             * - When `to` is zero, `tokenId` will be burned by `from`.
             * - `from` and `to` are never both zero.
             */
            function _beforeTokenTransfers(
                address from,
                address to,
                uint256 startTokenId,
                uint256 quantity
            ) internal virtual {}
            /**
             * @dev Hook that is called after a set of serially-ordered token IDs
             * have been transferred. This includes minting.
             * And also called after one token has been burned.
             *
             * `startTokenId` - the first token ID to be transferred.
             * `quantity` - the amount to be transferred.
             *
             * Calling conditions:
             *
             * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
             * transferred to `to`.
             * - When `from` is zero, `tokenId` has been minted for `to`.
             * - When `to` is zero, `tokenId` has been burned by `from`.
             * - `from` and `to` are never both zero.
             */
            function _afterTokenTransfers(
                address from,
                address to,
                uint256 startTokenId,
                uint256 quantity
            ) internal virtual {}
            /**
             * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
             *
             * `from` - Previous owner of the given token ID.
             * `to` - Target address that will receive the token.
             * `tokenId` - Token ID to be transferred.
             * `_data` - Optional data to send along with the call.
             *
             * Returns whether the call correctly returned the expected magic value.
             */
            function _checkContractOnERC721Received(
                address from,
                address to,
                uint256 tokenId,
                bytes memory _data
            ) private returns (bool) {
                try
                    ERC721A__IERC721ReceiverUpgradeable(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data)
                returns (bytes4 retval) {
                    return retval == ERC721A__IERC721ReceiverUpgradeable(to).onERC721Received.selector;
                } catch (bytes memory reason) {
                    if (reason.length == 0) {
                        revert TransferToNonERC721ReceiverImplementer();
                    } else {
                        assembly {
                            revert(add(32, reason), mload(reason))
                        }
                    }
                }
            }
            // =============================================================
            //                        MINT OPERATIONS
            // =============================================================
            /**
             * @dev Mints `quantity` tokens and transfers them to `to`.
             *
             * Requirements:
             *
             * - `to` cannot be the zero address.
             * - `quantity` must be greater than 0.
             *
             * Emits a {Transfer} event for each mint.
             */
            function _mint(address to, uint256 quantity) internal virtual {
                uint256 startTokenId = ERC721AStorage.layout()._currentIndex;
                if (quantity == 0) revert MintZeroQuantity();
                _beforeTokenTransfers(address(0), to, startTokenId, quantity);
                // Overflows are incredibly unrealistic.
                // `balance` and `numberMinted` have a maximum limit of 2**64.
                // `tokenId` has a maximum limit of 2**256.
                unchecked {
                    // Updates:
                    // - `balance += quantity`.
                    // - `numberMinted += quantity`.
                    //
                    // We can directly add to the `balance` and `numberMinted`.
                    ERC721AStorage.layout()._packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
                    // Updates:
                    // - `address` to the owner.
                    // - `startTimestamp` to the timestamp of minting.
                    // - `burned` to `false`.
                    // - `nextInitialized` to `quantity == 1`.
                    ERC721AStorage.layout()._packedOwnerships[startTokenId] = _packOwnershipData(
                        to,
                        _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
                    );
                    uint256 toMasked;
                    uint256 end = startTokenId + quantity;
                    // Use assembly to loop and emit the `Transfer` event for gas savings.
                    // The duplicated `log4` removes an extra check and reduces stack juggling.
                    // The assembly, together with the surrounding Solidity code, have been
                    // delicately arranged to nudge the compiler into producing optimized opcodes.
                    assembly {
                        // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
                        toMasked := and(to, _BITMASK_ADDRESS)
                        // Emit the `Transfer` event.
                        log4(
                            0, // Start of data (0, since no data).
                            0, // End of data (0, since no data).
                            _TRANSFER_EVENT_SIGNATURE, // Signature.
                            0, // `address(0)`.
                            toMasked, // `to`.
                            startTokenId // `tokenId`.
                        )
                        // The `iszero(eq(,))` check ensures that large values of `quantity`
                        // that overflows uint256 will make the loop run out of gas.
                        // The compiler will optimize the `iszero` away for performance.
                        for {
                            let tokenId := add(startTokenId, 1)
                        } iszero(eq(tokenId, end)) {
                            tokenId := add(tokenId, 1)
                        } {
                            // Emit the `Transfer` event. Similar to above.
                            log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
                        }
                    }
                    if (toMasked == 0) revert MintToZeroAddress();
                    ERC721AStorage.layout()._currentIndex = end;
                }
                _afterTokenTransfers(address(0), to, startTokenId, quantity);
            }
            /**
             * @dev Mints `quantity` tokens and transfers them to `to`.
             *
             * This function is intended for efficient minting only during contract creation.
             *
             * It emits only one {ConsecutiveTransfer} as defined in
             * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
             * instead of a sequence of {Transfer} event(s).
             *
             * Calling this function outside of contract creation WILL make your contract
             * non-compliant with the ERC721 standard.
             * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
             * {ConsecutiveTransfer} event is only permissible during contract creation.
             *
             * Requirements:
             *
             * - `to` cannot be the zero address.
             * - `quantity` must be greater than 0.
             *
             * Emits a {ConsecutiveTransfer} event.
             */
            function _mintERC2309(address to, uint256 quantity) internal virtual {
                uint256 startTokenId = ERC721AStorage.layout()._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);
                // Overflows are unrealistic due to the above check for `quantity` to be below the limit.
                unchecked {
                    // Updates:
                    // - `balance += quantity`.
                    // - `numberMinted += quantity`.
                    //
                    // We can directly add to the `balance` and `numberMinted`.
                    ERC721AStorage.layout()._packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
                    // Updates:
                    // - `address` to the owner.
                    // - `startTimestamp` to the timestamp of minting.
                    // - `burned` to `false`.
                    // - `nextInitialized` to `quantity == 1`.
                    ERC721AStorage.layout()._packedOwnerships[startTokenId] = _packOwnershipData(
                        to,
                        _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
                    );
                    emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);
                    ERC721AStorage.layout()._currentIndex = startTokenId + quantity;
                }
                _afterTokenTransfers(address(0), to, startTokenId, quantity);
            }
            /**
             * @dev Safely mints `quantity` tokens and transfers them to `to`.
             *
             * Requirements:
             *
             * - If `to` refers to a smart contract, it must implement
             * {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
             * - `quantity` must be greater than 0.
             *
             * See {_mint}.
             *
             * Emits a {Transfer} event for each mint.
             */
            function _safeMint(
                address to,
                uint256 quantity,
                bytes memory _data
            ) internal virtual {
                _mint(to, quantity);
                unchecked {
                    if (to.code.length != 0) {
                        uint256 end = ERC721AStorage.layout()._currentIndex;
                        uint256 index = end - quantity;
                        do {
                            if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
                                revert TransferToNonERC721ReceiverImplementer();
                            }
                        } while (index < end);
                        // Reentrancy protection.
                        if (ERC721AStorage.layout()._currentIndex != end) revert();
                    }
                }
            }
            /**
             * @dev Equivalent to `_safeMint(to, quantity, '')`.
             */
            function _safeMint(address to, uint256 quantity) internal virtual {
                _safeMint(to, quantity, '');
            }
            // =============================================================
            //                       APPROVAL OPERATIONS
            // =============================================================
            /**
             * @dev Equivalent to `_approve(to, tokenId, false)`.
             */
            function _approve(address to, uint256 tokenId) internal virtual {
                _approve(to, tokenId, false);
            }
            /**
             * @dev Gives permission to `to` to transfer `tokenId` token to another account.
             * The approval is cleared when the token is transferred.
             *
             * Only a single account can be approved at a time, so approving the
             * zero address clears previous approvals.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             *
             * Emits an {Approval} event.
             */
            function _approve(
                address to,
                uint256 tokenId,
                bool approvalCheck
            ) internal virtual {
                address owner = ownerOf(tokenId);
                if (approvalCheck)
                    if (_msgSenderERC721A() != owner)
                        if (!isApprovedForAll(owner, _msgSenderERC721A())) {
                            revert ApprovalCallerNotOwnerNorApproved();
                        }
                ERC721AStorage.layout()._tokenApprovals[tokenId].value = to;
                emit Approval(owner, to, tokenId);
            }
            // =============================================================
            //                        BURN OPERATIONS
            // =============================================================
            /**
             * @dev Equivalent to `_burn(tokenId, false)`.
             */
            function _burn(uint256 tokenId) internal virtual {
                _burn(tokenId, false);
            }
            /**
             * @dev Destroys `tokenId`.
             * The approval is cleared when the token is burned.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             *
             * Emits a {Transfer} event.
             */
            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) {
                    // The nested ifs save around 20+ gas over a compound boolean condition.
                    if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                        if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
                }
                _beforeTokenTransfers(from, address(0), tokenId, 1);
                // Clear approvals from the previous owner.
                assembly {
                    if approvedAddress {
                        // This is equivalent to `delete _tokenApprovals[tokenId]`.
                        sstore(approvedAddressSlot, 0)
                    }
                }
                // Underflow of the sender's balance is impossible because we check for
                // ownership above and the recipient's balance can't realistically overflow.
                // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
                unchecked {
                    // Updates:
                    // - `balance -= 1`.
                    // - `numberBurned += 1`.
                    //
                    // We can directly decrement the balance, and increment the number burned.
                    // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
                    ERC721AStorage.layout()._packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
                    // Updates:
                    // - `address` to the last owner.
                    // - `startTimestamp` to the timestamp of burning.
                    // - `burned` to `true`.
                    // - `nextInitialized` to `true`.
                    ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData(
                        from,
                        (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
                    );
                    // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
                    if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                        uint256 nextTokenId = tokenId + 1;
                        // If the next slot's address is zero and not burned (i.e. packed value is zero).
                        if (ERC721AStorage.layout()._packedOwnerships[nextTokenId] == 0) {
                            // If the next slot is within bounds.
                            if (nextTokenId != ERC721AStorage.layout()._currentIndex) {
                                // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                                ERC721AStorage.layout()._packedOwnerships[nextTokenId] = prevOwnershipPacked;
                            }
                        }
                    }
                }
                emit Transfer(from, address(0), tokenId);
                _afterTokenTransfers(from, address(0), tokenId, 1);
                // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
                unchecked {
                    ERC721AStorage.layout()._burnCounter++;
                }
            }
            // =============================================================
            //                     EXTRA DATA OPERATIONS
            // =============================================================
            /**
             * @dev Directly sets the extra data for the ownership data `index`.
             */
            function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
                uint256 packed = ERC721AStorage.layout()._packedOwnerships[index];
                if (packed == 0) revert OwnershipNotInitializedForExtraData();
                uint256 extraDataCasted;
                // Cast `extraData` with assembly to avoid redundant masking.
                assembly {
                    extraDataCasted := extraData
                }
                packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
                ERC721AStorage.layout()._packedOwnerships[index] = packed;
            }
            /**
             * @dev Called during each token transfer to set the 24bit `extraData` field.
             * Intended to be overridden by the cosumer contract.
             *
             * `previousExtraData` - the value of `extraData` before transfer.
             *
             * Calling conditions:
             *
             * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
             * transferred to `to`.
             * - When `from` is zero, `tokenId` will be minted for `to`.
             * - When `to` is zero, `tokenId` will be burned by `from`.
             * - `from` and `to` are never both zero.
             */
            function _extraData(
                address from,
                address to,
                uint24 previousExtraData
            ) internal view virtual returns (uint24) {}
            /**
             * @dev Returns the next extra data for the packed ownership data.
             * The returned result is shifted into position.
             */
            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;
            }
            // =============================================================
            //                       OTHER OPERATIONS
            // =============================================================
            /**
             * @dev Returns the message sender (defaults to `msg.sender`).
             *
             * If you are writing GSN compatible contracts, you need to override this function.
             */
            function _msgSenderERC721A() internal view virtual returns (address) {
                return msg.sender;
            }
            /**
             * @dev Converts a uint256 to its ASCII string decimal representation.
             */
            function _toString(uint256 value) internal pure virtual returns (string memory str) {
                assembly {
                    // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
                    // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
                    // We will need 1 word for the trailing zeros padding, 1 word for the length,
                    // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
                    let m := add(mload(0x40), 0xa0)
                    // Update the free memory pointer to allocate.
                    mstore(0x40, m)
                    // Assign the `str` to the end.
                    str := sub(m, 0x20)
                    // Zeroize the slot after the string.
                    mstore(str, 0)
                    // Cache the end of the memory to calculate the length later.
                    let end := str
                    // We write the string from rightmost digit to leftmost digit.
                    // The following is essentially a do-while loop that also handles the zero case.
                    // prettier-ignore
                    for { let temp := value } 1 {} {
                        str := sub(str, 1)
                        // Write the character to the pointer.
                        // The ASCII index of the '0' character is 48.
                        mstore8(str, add(48, mod(temp, 10)))
                        // Keep dividing `temp` until zero.
                        temp := div(temp, 10)
                        // prettier-ignore
                        if iszero(temp) { break }
                    }
                    let length := sub(end, str)
                    // Move the pointer 32 bytes leftwards to make room for the length.
                    str := sub(str, 0x20)
                    // Store the length.
                    mstore(str, length)
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        library ERC721AStorage {
            // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
            struct TokenApprovalRef {
                address value;
            }
            struct Layout {
                // =============================================================
                //                            STORAGE
                // =============================================================
                // The next token ID to be minted.
                uint256 _currentIndex;
                // The number of tokens burned.
                uint256 _burnCounter;
                // Token name
                string _name;
                // Token symbol
                string _symbol;
                // Mapping from token ID to ownership details
                // An empty struct value does not necessarily mean the token is unowned.
                // See {_packedOwnershipOf} implementation for details.
                //
                // Bits Layout:
                // - [0..159]   `addr`
                // - [160..223] `startTimestamp`
                // - [224]      `burned`
                // - [225]      `nextInitialized`
                // - [232..255] `extraData`
                mapping(uint256 => uint256) _packedOwnerships;
                // Mapping owner address to address data.
                //
                // Bits Layout:
                // - [0..63]    `balance`
                // - [64..127]  `numberMinted`
                // - [128..191] `numberBurned`
                // - [192..255] `aux`
                mapping(address => uint256) _packedAddressData;
                // Mapping from token ID to approved address.
                mapping(uint256 => ERC721AStorage.TokenApprovalRef) _tokenApprovals;
                // Mapping from owner to operator approvals
                mapping(address => mapping(address => bool)) _operatorApprovals;
            }
            bytes32 internal constant STORAGE_SLOT = keccak256('ERC721A.contracts.storage.ERC721A');
            function layout() internal pure returns (Layout storage l) {
                bytes32 slot = STORAGE_SLOT;
                assembly {
                    l.slot := slot
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.4;
        /// @notice Simple single owner authorization mixin.
        /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
        ///
        /// @dev Note:
        /// This implementation does NOT auto-initialize the owner to `msg.sender`.
        /// You MUST call the `_initializeOwner` in the constructor / initializer.
        ///
        /// While the ownable portion follows
        /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
        /// the nomenclature for the 2-step ownership handover may be unique to this codebase.
        abstract contract Ownable {
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                       CUSTOM ERRORS                        */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev The caller is not authorized to call the function.
            error Unauthorized();
            /// @dev The `newOwner` cannot be the zero address.
            error NewOwnerIsZeroAddress();
            /// @dev The `pendingOwner` does not have a valid handover request.
            error NoHandoverRequest();
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                           EVENTS                           */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
            /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
            /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
            /// despite it not being as lightweight as a single argument event.
            event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
            /// @dev An ownership handover to `pendingOwner` has been requested.
            event OwnershipHandoverRequested(address indexed pendingOwner);
            /// @dev The ownership handover to `pendingOwner` has been canceled.
            event OwnershipHandoverCanceled(address indexed pendingOwner);
            /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
            uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
                0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
            /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
            uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
                0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
            /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
            uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
                0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                          STORAGE                           */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`.
            /// It is intentionally chosen to be a high value
            /// to avoid collision with lower slots.
            /// The choice of manual storage layout is to enable compatibility
            /// with both regular and upgradeable contracts.
            uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8;
            /// The ownership handover slot of `newOwner` is given by:
            /// ```
            ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
            ///     let handoverSlot := keccak256(0x00, 0x20)
            /// ```
            /// It stores the expiry timestamp of the two-step ownership handover.
            uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                     INTERNAL FUNCTIONS                     */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Initializes the owner directly without authorization guard.
            /// This function must be called upon initialization,
            /// regardless of whether the contract is upgradeable or not.
            /// This is to enable generalization to both regular and upgradeable contracts,
            /// and to save gas in case the initial owner is not the caller.
            /// For performance reasons, this function will not check if there
            /// is an existing owner.
            function _initializeOwner(address newOwner) internal virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    // Clean the upper 96 bits.
                    newOwner := shr(96, shl(96, newOwner))
                    // Store the new value.
                    sstore(not(_OWNER_SLOT_NOT), newOwner)
                    // Emit the {OwnershipTransferred} event.
                    log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
                }
            }
            /// @dev Sets the owner directly without authorization guard.
            function _setOwner(address newOwner) internal virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    let ownerSlot := not(_OWNER_SLOT_NOT)
                    // Clean the upper 96 bits.
                    newOwner := shr(96, shl(96, newOwner))
                    // Emit the {OwnershipTransferred} event.
                    log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                    // Store the new value.
                    sstore(ownerSlot, newOwner)
                }
            }
            /// @dev Throws if the sender is not the owner.
            function _checkOwner() internal view virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    // If the caller is not the stored owner, revert.
                    if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) {
                        mstore(0x00, 0x82b42900) // `Unauthorized()`.
                        revert(0x1c, 0x04)
                    }
                }
            }
            /// @dev Returns how long a two-step ownership handover is valid for in seconds.
            /// Override to return a different value if needed.
            /// Made internal to conserve bytecode. Wrap it in a public function if needed.
            function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
                return 48 * 3600;
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                  PUBLIC UPDATE FUNCTIONS                   */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Allows the owner to transfer the ownership to `newOwner`.
            function transferOwnership(address newOwner) public payable virtual onlyOwner {
                /// @solidity memory-safe-assembly
                assembly {
                    if iszero(shl(96, newOwner)) {
                        mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                        revert(0x1c, 0x04)
                    }
                }
                _setOwner(newOwner);
            }
            /// @dev Allows the owner to renounce their ownership.
            function renounceOwnership() public payable virtual onlyOwner {
                _setOwner(address(0));
            }
            /// @dev Request a two-step ownership handover to the caller.
            /// The request will automatically expire in 48 hours (172800 seconds) by default.
            function requestOwnershipHandover() public payable virtual {
                unchecked {
                    uint256 expires = block.timestamp + _ownershipHandoverValidFor();
                    /// @solidity memory-safe-assembly
                    assembly {
                        // Compute and set the handover slot to `expires`.
                        mstore(0x0c, _HANDOVER_SLOT_SEED)
                        mstore(0x00, caller())
                        sstore(keccak256(0x0c, 0x20), expires)
                        // Emit the {OwnershipHandoverRequested} event.
                        log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
                    }
                }
            }
            /// @dev Cancels the two-step ownership handover to the caller, if any.
            function cancelOwnershipHandover() public payable virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    // Compute and set the handover slot to 0.
                    mstore(0x0c, _HANDOVER_SLOT_SEED)
                    mstore(0x00, caller())
                    sstore(keccak256(0x0c, 0x20), 0)
                    // Emit the {OwnershipHandoverCanceled} event.
                    log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
                }
            }
            /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
            /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
            function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
                /// @solidity memory-safe-assembly
                assembly {
                    // Compute and set the handover slot to 0.
                    mstore(0x0c, _HANDOVER_SLOT_SEED)
                    mstore(0x00, pendingOwner)
                    let handoverSlot := keccak256(0x0c, 0x20)
                    // If the handover does not exist, or has expired.
                    if gt(timestamp(), sload(handoverSlot)) {
                        mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                        revert(0x1c, 0x04)
                    }
                    // Set the handover slot to 0.
                    sstore(handoverSlot, 0)
                }
                _setOwner(pendingOwner);
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                   PUBLIC READ FUNCTIONS                    */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Returns the owner of the contract.
            function owner() public view virtual returns (address result) {
                /// @solidity memory-safe-assembly
                assembly {
                    result := sload(not(_OWNER_SLOT_NOT))
                }
            }
            /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
            function ownershipHandoverExpiresAt(address pendingOwner)
                public
                view
                virtual
                returns (uint256 result)
            {
                /// @solidity memory-safe-assembly
                assembly {
                    // Compute the handover slot.
                    mstore(0x0c, _HANDOVER_SLOT_SEED)
                    mstore(0x00, pendingOwner)
                    // Load the handover slot.
                    result := sload(keccak256(0x0c, 0x20))
                }
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                         MODIFIERS                          */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Marks a function as only callable by the owner.
            modifier onlyOwner() virtual {
                _checkOwner();
                _;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)
        pragma solidity ^0.8.0;
        import "../utils/introspection/IERC165.sol";
        /**
         * @dev Interface for the NFT Royalty Standard.
         *
         * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
         * support for royalty payments across all NFT marketplaces and ecosystem participants.
         *
         * _Available since v4.5._
         */
        interface IERC2981 is IERC165 {
            /**
             * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
             * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
             */
            function royaltyInfo(uint256 tokenId, uint256 salePrice)
                external
                view
                returns (address receiver, uint256 royaltyAmount);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)
        pragma solidity ^0.8.0;
        import "../utils/introspection/IERC165.sol";
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        interface IMetadataRenderer {
            /// @notice Retrieves the token URI for the specified token ID.
            /// @param tokenId The ID of the token.
            /// @return uri The URI of the token.
            function tokenURI(uint256 tokenId) external view returns (string memory uri);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {IMetadataRenderer} from "create/interfaces/v1/IMetadataRenderer.sol";
        interface IMintContractEvents {
            /// @notice Emitted when the royalty is updated.
            event RoyaltyUpdated(uint256 bps);
            /// @notice Emitted when a new mint module is added.
            event ModuleAdded(address module);
            /// @notice Emitted when a mint module is removed.
            event ModuleRemoved(address module);
            /// @notice Emitted when the metadata renderer is updated.
            event MetadataRendererUpdated(address renderer);
        }
        interface IMintContract is IMintContractEvents {
            /// @notice Mints tokens using approved mint modules.
            /// @param to The address receiving the minted tokens.
            /// @param quantity The quantity of tokens to mint.
            function mint(address to, uint256 quantity) external;
            /// @notice Mints tokens, callable only by the contract owner.
            /// @param to The address receiving the minted tokens.
            /// @param quantity The quantity of tokens to mint.
            function adminMint(address to, uint256 quantity) external;
            /// @notice Retrieves the payout recipient address for this mint contract.
            /// @return recipient address of the payout recipient.
            function payoutRecipient() external view returns (address recipient);
            /// @notice Returns the total number of tokens minted.
            /// @return total number of tokens minted.
            function totalMinted() external view returns (uint256 total);
            /// @notice Adds a new mint module as an approved minter.
            /// @dev Can only be executed by the owner of the contract.
            /// Must be approved in the MintModuleRegistry.
            /// @param mintModule The contract address of the mint module.
            function addMintModule(address mintModule) external;
            /// @notice Removes a mint module as an approved minter.
            /// @dev Can only be executed by the owner of the contract.
            /// @param mintModule The contract address of the mint module.
            function removeMintModule(address mintModule) external;
            /// @notice Returns whether a mint module is approved.
            /// @param mintModule The contract address of the mint module.
            /// @return isApproved Whether the mint module is approved.
            function isMintModuleApproved(address mintModule) external view returns (bool isApproved);
            /// @notice Updates configuration located in an external contract.
            /// @dev Can only be executed by the owner of the contract.
            /// The cardinality of `configurables` and `configData` must be the same.
            /// @param configurables The contract addresses to configure.
            /// @param configData The configuration data for the contracts.
            function updateExternalConfiguration(address[] calldata configurables, bytes[] calldata configData) external;
            /// @notice Sets the metadata renderer.
            /// @dev This will not request a metadata refresh. If needed, call `refreshMetadata`.
            /// @param renderer The new metadata renderer.
            function setMetadataRenderer(IMetadataRenderer renderer) external;
            /// @notice Returns the metadata renderer for this contract.
            /// @return metadataRenderer The metadata renderer.
            function metadataRenderer() external returns (IMetadataRenderer metadataRenderer);
            /// @notice Triggers a batch metadata update.
            function refreshMetadata() external;
            /// @notice Updates the royalty for this contract.
            /// @dev Can only be called by the contract owner.
            /// Emits a `RoyaltyUpdated` event.
            /// @param bps The new royalty.
            function setRoyalty(uint256 bps) external;
            /// @notice Returns the royalty for this contract.
            /// @return bps The royalty.
            function royaltyBps() external returns (uint256 bps);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {Mint721Configuration} from "./Mint721Configuration.sol";
        import {IMetadataRenderer} from "./IMetadataRenderer.sol";
        interface IMint721 {
            /// @notice Initializes a new Mint721 contract with the provided configuration.
            /// @dev `mintModules` and `mintModulesData` must have the same cardinality.
            /// @param configuration The configuration data.
            /// @param mintModuleRegistry The mint module registry.
            /// @param metadataRenderer The metadata renderer.
            /// @param metadataRendererConfig The configuration data for the metadata renderer, or none if not required.
            /// @param mintModules The initial approved mint modules.
            /// @param mintModuleData The configuration data for the mint modules.
            /// @param creator The creator of the contract.
            function initialize(
                Mint721Configuration calldata configuration,
                address mintModuleRegistry,
                IMetadataRenderer metadataRenderer,
                bytes calldata metadataRendererConfig,
                address[] calldata mintModules,
                bytes[] calldata mintModuleData,
                address creator
            ) external;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        struct Mint721Configuration {
            /// @notice NFT collection name
            string name;
            /// @notice NFT collection symbol
            string symbol;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        interface IMintModuleRegistryEvents {
            /// @notice Emitted when a new module is registered.
            /// @param module The contract address of the new mint module.
            event ModuleAdded(address indexed module);
            /// @notice Emitted when a module is unregistered.
            /// @param module The address of mint module being removed.
            event ModuleRemoved(address indexed module);
        }
        interface IMintModuleRegistry is IMintModuleRegistryEvents {
            error AlreadyRegistered();
            error NotRegistered();
            error InvalidAddress();
            /// @notice Registers a new mint module.
            /// @dev Can only be executed by protocol admin. Raises `InvalidAddress` if `mintModule` is the zero address.
            /// Raises `AlreadyRegistered` if the module is already registered.
            /// @param mintModule The contract address of the mint module.
            function addModule(address mintModule) external;
            /// @notice Unregisters a mint module.
            /// @dev Can only be executed by protocol admin. Raises `InvalidAddress` if `mintModule` is the zero address.
            /// Raises `NotRegistered` if the module isn't currently registered.
            /// @param mintModule The contract address of the mint module.
            function removeModule(address mintModule) external;
            /// @notice Checks if a mint module is registered.
            /// @param mintModule The contract address of the mint module.
            /// @return isModuleRegistered True if the module is registered, false otherwise.
            function isRegistered(address mintModule) external view returns (bool isModuleRegistered);
            /// @notice Checks if the mint module is registered.
            /// @dev Reverts with `NotRegistered` if the module isn't registered.
            /// @param mintModule The contract address of the mint module.
            function checkModule(address mintModule) external;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        interface IERC4906 {
            /// @dev This event emits when the metadata of a token is changed.
            /// So that the third-party platforms such as NFT market could
            /// timely update the images and related attributes of the NFT.
            event MetadataUpdate(uint256 _tokenId);
            /// @dev This event emits when the metadata of a range of tokens is changed.
            /// So that the third-party platforms such as NFT market could
            /// timely update the images and related attributes of the NFTs.
            event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        abstract contract Version {
            /// @notice The version of the contract.
            uint32 public immutable contractVersion;
            constructor(uint32 _contractVersion) {
                contractVersion = _contractVersion;
            }
        }
        // SPDX-License-Identifier: MIT
        // ERC721A Contracts v4.2.3
        // Creator: Chiru Labs
        pragma solidity ^0.8.4;
        /**
         * @dev Interface of ERC721A.
         */
        interface IERC721AUpgradeable {
            /**
             * The caller must own the token or be an approved operator.
             */
            error ApprovalCallerNotOwnerNorApproved();
            /**
             * The token does not exist.
             */
            error ApprovalQueryForNonexistentToken();
            /**
             * Cannot query the balance for the zero address.
             */
            error BalanceQueryForZeroAddress();
            /**
             * Cannot mint to the zero address.
             */
            error MintToZeroAddress();
            /**
             * The quantity of tokens minted must be more than zero.
             */
            error MintZeroQuantity();
            /**
             * The token does not exist.
             */
            error OwnerQueryForNonexistentToken();
            /**
             * The caller must own the token or be an approved operator.
             */
            error TransferCallerNotOwnerNorApproved();
            /**
             * The token must be owned by `from`.
             */
            error TransferFromIncorrectOwner();
            /**
             * Cannot safely transfer to a contract that does not implement the
             * ERC721Receiver interface.
             */
            error TransferToNonERC721ReceiverImplementer();
            /**
             * Cannot transfer to the zero address.
             */
            error TransferToZeroAddress();
            /**
             * The token does not exist.
             */
            error URIQueryForNonexistentToken();
            /**
             * The `quantity` minted with ERC2309 exceeds the safety limit.
             */
            error MintERC2309QuantityExceedsLimit();
            /**
             * The `extraData` cannot be set on an unintialized ownership slot.
             */
            error OwnershipNotInitializedForExtraData();
            // =============================================================
            //                            STRUCTS
            // =============================================================
            struct TokenOwnership {
                // The address of the owner.
                address addr;
                // Stores the start time of ownership with minimal overhead for tokenomics.
                uint64 startTimestamp;
                // Whether the token has been burned.
                bool burned;
                // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
                uint24 extraData;
            }
            // =============================================================
            //                         TOKEN COUNTERS
            // =============================================================
            /**
             * @dev Returns the total number of tokens in existence.
             * Burned tokens will reduce the count.
             * To get the total number of tokens minted, please see {_totalMinted}.
             */
            function totalSupply() external view returns (uint256);
            // =============================================================
            //                            IERC165
            // =============================================================
            /**
             * @dev Returns true if this contract implements the interface defined by
             * `interfaceId`. See the corresponding
             * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
             * to learn more about how these ids are created.
             *
             * This function call must use less than 30000 gas.
             */
            function supportsInterface(bytes4 interfaceId) external view returns (bool);
            // =============================================================
            //                            IERC721
            // =============================================================
            /**
             * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
             */
            event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
            /**
             * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
             */
            event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
            /**
             * @dev Emitted when `owner` enables or disables
             * (`approved`) `operator` to manage all of its assets.
             */
            event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
            /**
             * @dev Returns the number of tokens in `owner`'s account.
             */
            function balanceOf(address owner) external view returns (uint256 balance);
            /**
             * @dev Returns the owner of the `tokenId` token.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             */
            function ownerOf(uint256 tokenId) external view returns (address owner);
            /**
             * @dev Safely transfers `tokenId` token from `from` to `to`,
             * checking first that contract recipients are aware of the ERC721 protocol
             * to prevent tokens from being forever locked.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must exist and be owned by `from`.
             * - If the caller is not `from`, it must be have been allowed to move
             * this token by either {approve} or {setApprovalForAll}.
             * - If `to` refers to a smart contract, it must implement
             * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
             *
             * Emits a {Transfer} event.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId,
                bytes calldata data
            ) external payable;
            /**
             * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
             */
            function safeTransferFrom(
                address from,
                address to,
                uint256 tokenId
            ) external payable;
            /**
             * @dev Transfers `tokenId` from `from` to `to`.
             *
             * WARNING: Usage of this method is discouraged, use {safeTransferFrom}
             * whenever possible.
             *
             * Requirements:
             *
             * - `from` cannot be the zero address.
             * - `to` cannot be the zero address.
             * - `tokenId` token must be owned by `from`.
             * - If the caller is not `from`, it must be approved to move this token
             * by either {approve} or {setApprovalForAll}.
             *
             * Emits a {Transfer} event.
             */
            function transferFrom(
                address from,
                address to,
                uint256 tokenId
            ) external payable;
            /**
             * @dev Gives permission to `to` to transfer `tokenId` token to another account.
             * The approval is cleared when the token is transferred.
             *
             * Only a single account can be approved at a time, so approving the
             * zero address clears previous approvals.
             *
             * Requirements:
             *
             * - The caller must own the token or be an approved operator.
             * - `tokenId` must exist.
             *
             * Emits an {Approval} event.
             */
            function approve(address to, uint256 tokenId) external payable;
            /**
             * @dev Approve or remove `operator` as an operator for the caller.
             * Operators can call {transferFrom} or {safeTransferFrom}
             * for any token owned by the caller.
             *
             * Requirements:
             *
             * - The `operator` cannot be the caller.
             *
             * Emits an {ApprovalForAll} event.
             */
            function setApprovalForAll(address operator, bool _approved) external;
            /**
             * @dev Returns the account approved for `tokenId` token.
             *
             * Requirements:
             *
             * - `tokenId` must exist.
             */
            function getApproved(uint256 tokenId) external view returns (address operator);
            /**
             * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
             *
             * See {setApprovalForAll}.
             */
            function isApprovedForAll(address owner, address operator) external view returns (bool);
            // =============================================================
            //                        IERC721Metadata
            // =============================================================
            /**
             * @dev Returns the token collection name.
             */
            function name() external view returns (string memory);
            /**
             * @dev Returns the token collection symbol.
             */
            function symbol() external view returns (string memory);
            /**
             * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
             */
            function tokenURI(uint256 tokenId) external view returns (string memory);
            // =============================================================
            //                           IERC2309
            // =============================================================
            /**
             * @dev Emitted when tokens in `fromTokenId` to `toTokenId`
             * (inclusive) is transferred from `from` to `to`, as defined in the
             * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
             *
             * See {_mintERC2309} for more details.
             */
            event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /**
         * @dev This is a base contract to aid in writing upgradeable diamond facet 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.
         *
         * 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.
         */
        import {ERC721A__InitializableStorage} from './ERC721A__InitializableStorage.sol';
        abstract contract ERC721A__Initializable {
            using ERC721A__InitializableStorage for ERC721A__InitializableStorage.Layout;
            /**
             * @dev Modifier to protect an initializer function from being invoked twice.
             */
            modifier initializerERC721A() {
                // If the contract is initializing we ignore whether _initialized is set in order to support multiple
                // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
                // contract may have been reentered.
                require(
                    ERC721A__InitializableStorage.layout()._initializing
                        ? _isConstructor()
                        : !ERC721A__InitializableStorage.layout()._initialized,
                    'ERC721A__Initializable: contract is already initialized'
                );
                bool isTopLevelCall = !ERC721A__InitializableStorage.layout()._initializing;
                if (isTopLevelCall) {
                    ERC721A__InitializableStorage.layout()._initializing = true;
                    ERC721A__InitializableStorage.layout()._initialized = true;
                }
                _;
                if (isTopLevelCall) {
                    ERC721A__InitializableStorage.layout()._initializing = false;
                }
            }
            /**
             * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
             * {initializer} modifier, directly or indirectly.
             */
            modifier onlyInitializingERC721A() {
                require(
                    ERC721A__InitializableStorage.layout()._initializing,
                    'ERC721A__Initializable: contract is not initializing'
                );
                _;
            }
            /// @dev Returns true if and only if the function is running in the constructor
            function _isConstructor() private view returns (bool) {
                // extcodesize checks the size of the code stored in an address, and
                // address returns the current address. Since the code is still not
                // deployed when running a constructor, any checks on its code size will
                // yield zero, making it an effective way to detect if a contract is
                // under construction or not.
                address self = address(this);
                uint256 cs;
                assembly {
                    cs := extcodesize(self)
                }
                return cs == 0;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
        pragma solidity ^0.8.0;
        /**
         * @dev Interface of the ERC165 standard, as defined in the
         * https://eips.ethereum.org/EIPS/eip-165[EIP].
         *
         * Implementers can declare support of contract interfaces, which can then be
         * queried by others ({ERC165Checker}).
         *
         * For an implementation, see {ERC165}.
         */
        interface IERC165 {
            /**
             * @dev Returns true if this contract implements the interface defined by
             * `interfaceId`. See the corresponding
             * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
             * to learn more about how these ids are created.
             *
             * This function call must use less than 30 000 gas.
             */
            function supportsInterface(bytes4 interfaceId) external view returns (bool);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /**
         * @dev This is a base storage for the  initialization function for upgradeable diamond facet contracts
         **/
        library ERC721A__InitializableStorage {
            struct Layout {
                /*
                 * Indicates that the contract has been initialized.
                 */
                bool _initialized;
                /*
                 * Indicates that the contract is in the process of being initialized.
                 */
                bool _initializing;
            }
            bytes32 internal constant STORAGE_SLOT = keccak256('ERC721A.contracts.storage.initializable.facet');
            function layout() internal pure returns (Layout storage l) {
                bytes32 slot = STORAGE_SLOT;
                assembly {
                    l.slot := slot
                }
            }
        }
        

        File 6 of 6: MintModuleRegistry
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        import {Ownable} from "solady/auth/Ownable.sol";
        import {Version} from "create/contracts/v1/Version.sol";
        import {IMintModuleRegistry} from "create/interfaces/v1/IMintModuleRegistry.sol";
        contract MintModuleRegistry is IMintModuleRegistry, Ownable, Version {
            constructor() Version(1) {
                _initializeOwner(tx.origin);
            }
            /// @inheritdoc IMintModuleRegistry
            mapping(address => bool) public isRegistered;
            /// @inheritdoc IMintModuleRegistry
            function addModule(address module) external onlyOwner {
                if (module == address(0)) revert InvalidAddress();
                if (isRegistered[module]) revert AlreadyRegistered();
                isRegistered[module] = true;
                emit ModuleAdded(module);
            }
            /// @inheritdoc IMintModuleRegistry
            function removeModule(address module) external onlyOwner {
                if (module == address(0)) revert InvalidAddress();
                if (!isRegistered[module]) revert NotRegistered();
                delete isRegistered[module];
                emit ModuleRemoved(module);
            }
            /// @inheritdoc IMintModuleRegistry
            function checkModule(address mintModule) external view override {
                if (!isRegistered[mintModule]) revert NotRegistered();
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.4;
        /// @notice Simple single owner authorization mixin.
        /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
        ///
        /// @dev Note:
        /// This implementation does NOT auto-initialize the owner to `msg.sender`.
        /// You MUST call the `_initializeOwner` in the constructor / initializer.
        ///
        /// While the ownable portion follows
        /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
        /// the nomenclature for the 2-step ownership handover may be unique to this codebase.
        abstract contract Ownable {
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                       CUSTOM ERRORS                        */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev The caller is not authorized to call the function.
            error Unauthorized();
            /// @dev The `newOwner` cannot be the zero address.
            error NewOwnerIsZeroAddress();
            /// @dev The `pendingOwner` does not have a valid handover request.
            error NoHandoverRequest();
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                           EVENTS                           */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
            /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
            /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
            /// despite it not being as lightweight as a single argument event.
            event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
            /// @dev An ownership handover to `pendingOwner` has been requested.
            event OwnershipHandoverRequested(address indexed pendingOwner);
            /// @dev The ownership handover to `pendingOwner` has been canceled.
            event OwnershipHandoverCanceled(address indexed pendingOwner);
            /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
            uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
                0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
            /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
            uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
                0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
            /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
            uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
                0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                          STORAGE                           */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`.
            /// It is intentionally chosen to be a high value
            /// to avoid collision with lower slots.
            /// The choice of manual storage layout is to enable compatibility
            /// with both regular and upgradeable contracts.
            uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8;
            /// The ownership handover slot of `newOwner` is given by:
            /// ```
            ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
            ///     let handoverSlot := keccak256(0x00, 0x20)
            /// ```
            /// It stores the expiry timestamp of the two-step ownership handover.
            uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                     INTERNAL FUNCTIONS                     */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Initializes the owner directly without authorization guard.
            /// This function must be called upon initialization,
            /// regardless of whether the contract is upgradeable or not.
            /// This is to enable generalization to both regular and upgradeable contracts,
            /// and to save gas in case the initial owner is not the caller.
            /// For performance reasons, this function will not check if there
            /// is an existing owner.
            function _initializeOwner(address newOwner) internal virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    // Clean the upper 96 bits.
                    newOwner := shr(96, shl(96, newOwner))
                    // Store the new value.
                    sstore(not(_OWNER_SLOT_NOT), newOwner)
                    // Emit the {OwnershipTransferred} event.
                    log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
                }
            }
            /// @dev Sets the owner directly without authorization guard.
            function _setOwner(address newOwner) internal virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    let ownerSlot := not(_OWNER_SLOT_NOT)
                    // Clean the upper 96 bits.
                    newOwner := shr(96, shl(96, newOwner))
                    // Emit the {OwnershipTransferred} event.
                    log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                    // Store the new value.
                    sstore(ownerSlot, newOwner)
                }
            }
            /// @dev Throws if the sender is not the owner.
            function _checkOwner() internal view virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    // If the caller is not the stored owner, revert.
                    if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) {
                        mstore(0x00, 0x82b42900) // `Unauthorized()`.
                        revert(0x1c, 0x04)
                    }
                }
            }
            /// @dev Returns how long a two-step ownership handover is valid for in seconds.
            /// Override to return a different value if needed.
            /// Made internal to conserve bytecode. Wrap it in a public function if needed.
            function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
                return 48 * 3600;
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                  PUBLIC UPDATE FUNCTIONS                   */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Allows the owner to transfer the ownership to `newOwner`.
            function transferOwnership(address newOwner) public payable virtual onlyOwner {
                /// @solidity memory-safe-assembly
                assembly {
                    if iszero(shl(96, newOwner)) {
                        mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                        revert(0x1c, 0x04)
                    }
                }
                _setOwner(newOwner);
            }
            /// @dev Allows the owner to renounce their ownership.
            function renounceOwnership() public payable virtual onlyOwner {
                _setOwner(address(0));
            }
            /// @dev Request a two-step ownership handover to the caller.
            /// The request will automatically expire in 48 hours (172800 seconds) by default.
            function requestOwnershipHandover() public payable virtual {
                unchecked {
                    uint256 expires = block.timestamp + _ownershipHandoverValidFor();
                    /// @solidity memory-safe-assembly
                    assembly {
                        // Compute and set the handover slot to `expires`.
                        mstore(0x0c, _HANDOVER_SLOT_SEED)
                        mstore(0x00, caller())
                        sstore(keccak256(0x0c, 0x20), expires)
                        // Emit the {OwnershipHandoverRequested} event.
                        log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
                    }
                }
            }
            /// @dev Cancels the two-step ownership handover to the caller, if any.
            function cancelOwnershipHandover() public payable virtual {
                /// @solidity memory-safe-assembly
                assembly {
                    // Compute and set the handover slot to 0.
                    mstore(0x0c, _HANDOVER_SLOT_SEED)
                    mstore(0x00, caller())
                    sstore(keccak256(0x0c, 0x20), 0)
                    // Emit the {OwnershipHandoverCanceled} event.
                    log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
                }
            }
            /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
            /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
            function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
                /// @solidity memory-safe-assembly
                assembly {
                    // Compute and set the handover slot to 0.
                    mstore(0x0c, _HANDOVER_SLOT_SEED)
                    mstore(0x00, pendingOwner)
                    let handoverSlot := keccak256(0x0c, 0x20)
                    // If the handover does not exist, or has expired.
                    if gt(timestamp(), sload(handoverSlot)) {
                        mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                        revert(0x1c, 0x04)
                    }
                    // Set the handover slot to 0.
                    sstore(handoverSlot, 0)
                }
                _setOwner(pendingOwner);
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                   PUBLIC READ FUNCTIONS                    */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Returns the owner of the contract.
            function owner() public view virtual returns (address result) {
                /// @solidity memory-safe-assembly
                assembly {
                    result := sload(not(_OWNER_SLOT_NOT))
                }
            }
            /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
            function ownershipHandoverExpiresAt(address pendingOwner)
                public
                view
                virtual
                returns (uint256 result)
            {
                /// @solidity memory-safe-assembly
                assembly {
                    // Compute the handover slot.
                    mstore(0x0c, _HANDOVER_SLOT_SEED)
                    mstore(0x00, pendingOwner)
                    // Load the handover slot.
                    result := sload(keccak256(0x0c, 0x20))
                }
            }
            /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
            /*                         MODIFIERS                          */
            /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
            /// @dev Marks a function as only callable by the owner.
            modifier onlyOwner() virtual {
                _checkOwner();
                _;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        abstract contract Version {
            /// @notice The version of the contract.
            uint32 public immutable contractVersion;
            constructor(uint32 _contractVersion) {
                contractVersion = _contractVersion;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.21;
        interface IMintModuleRegistryEvents {
            /// @notice Emitted when a new module is registered.
            /// @param module The contract address of the new mint module.
            event ModuleAdded(address indexed module);
            /// @notice Emitted when a module is unregistered.
            /// @param module The address of mint module being removed.
            event ModuleRemoved(address indexed module);
        }
        interface IMintModuleRegistry is IMintModuleRegistryEvents {
            error AlreadyRegistered();
            error NotRegistered();
            error InvalidAddress();
            /// @notice Registers a new mint module.
            /// @dev Can only be executed by protocol admin. Raises `InvalidAddress` if `mintModule` is the zero address.
            /// Raises `AlreadyRegistered` if the module is already registered.
            /// @param mintModule The contract address of the mint module.
            function addModule(address mintModule) external;
            /// @notice Unregisters a mint module.
            /// @dev Can only be executed by protocol admin. Raises `InvalidAddress` if `mintModule` is the zero address.
            /// Raises `NotRegistered` if the module isn't currently registered.
            /// @param mintModule The contract address of the mint module.
            function removeModule(address mintModule) external;
            /// @notice Checks if a mint module is registered.
            /// @param mintModule The contract address of the mint module.
            /// @return isModuleRegistered True if the module is registered, false otherwise.
            function isRegistered(address mintModule) external view returns (bool isModuleRegistered);
            /// @notice Checks if the mint module is registered.
            /// @dev Reverts with `NotRegistered` if the module isn't registered.
            /// @param mintModule The contract address of the mint module.
            function checkModule(address mintModule) external;
        }