ETH Price: $2,619.66 (+4.45%)

Transaction Decoder

Block:
20507091 at Aug-11-2024 06:14:47 PM +UTC
Transaction Fee:
0.00108216909432676 ETH $2.83
Gas Used:
739,105 Gas / 1.464161512 Gwei

Emitted Events:

348 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b( 0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b, 0x000000000000000000000000f62b0d56ba617f803df1c464c519ff7d29451b2f )
349 Zora1155Factory.0xa45800684f65ae010ceb4385eceaed88dec7f6a6bcbe11f7ffd8bd24dd2653f4( 0xa45800684f65ae010ceb4385eceaed88dec7f6a6bcbe11f7ffd8bd24dd2653f4, 0x000000000000000000000000aedc792d23ab8681f8c0154b2d57225095c7dbb3, 0x000000000000000000000000dc783b3cb88fdb2b01c61997746b655d7b54003e, 0x000000000000000000000000dc783b3cb88fdb2b01c61997746b655d7b54003e, 00000000000000000000000000000000000000000000000000000000000000a0, 0000000000000000000000000000000000000000000000000000000000000120, 0000000000000000000000000000000000000000000000000000000000000000, 00000000000000000000000000000000000000000000000000000000000001f4, 000000000000000000000000dc783b3cb88fdb2b01c61997746b655d7b54003e, 0000000000000000000000000000000000000000000000000000000000000042, 697066733a2f2f6261666b72656964776266766f6e3469687971637272367a6a, 32656874733773656c3466643662717373787478616373656e7a62616272616d, 716d000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000011, 44616e63696e67204d6f63617373696e73000000000000000000000000000000 )
350 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x35fb03d0d293ef5b362761900725ce891f8f766b5a662cdd445372355448e7ca( 0x35fb03d0d293ef5b362761900725ce891f8f766b5a662cdd445372355448e7ca, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000dc783b3cb88fdb2b01c61997746b655d7b54003e, 0x0000000000000000000000000000000000000000000000000000000000000002 )
351 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x5086d1bcea28999da9875111e3592688fbfa821db63214c695ca35768080c2fe( 0x5086d1bcea28999da9875111e3592688fbfa821db63214c695ca35768080c2fe, 0x000000000000000000000000a6c5f2de915240270dac655152c3f6a91748cb85, 0x0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000060, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000042, 697066733a2f2f6261666b72656964776266766f6e3469687971637272367a6a, 32656874733773656c3466643662717373787478616373656e7a62616272616d, 716d000000000000000000000000000000000000000000000000000000000000 )
352 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x5837d55897cfc337f160a71d7b63a047abd50a3a8834f1c5d70f338846358c6d( 0x5837d55897cfc337f160a71d7b63a047abd50a3a8834f1c5d70f338846358c6d, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000a6c5f2de915240270dac655152c3f6a91748cb85, 0000000000000000000000000000000000000000000000000000000000000000, 00000000000000000000000000000000000000000000000000000000000001f4, 000000000000000000000000dc783b3cb88fdb2b01c61997746b655d7b54003e )
353 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0( 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0, 0000000000000000000000000000000000000000000000000000000000000000, 000000000000000000000000dc783b3cb88fdb2b01c61997746b655d7b54003e )
354 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x3be6d3a1d957610f7e900c66889b874cdc9f0c22901aa8be6ec3d2d04c14ca0f( 0x3be6d3a1d957610f7e900c66889b874cdc9f0c22901aa8be6ec3d2d04c14ca0f, 0x000000000000000000000000a6c5f2de915240270dac655152c3f6a91748cb85, 0x0000000000000000000000000000000000000000000000000000000000000000, 000000000000000000000000dc783b3cb88fdb2b01c61997746b655d7b54003e, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
355 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x3be6d3a1d957610f7e900c66889b874cdc9f0c22901aa8be6ec3d2d04c14ca0f( 0x3be6d3a1d957610f7e900c66889b874cdc9f0c22901aa8be6ec3d2d04c14ca0f, 0x000000000000000000000000a6c5f2de915240270dac655152c3f6a91748cb85, 0x0000000000000000000000000000000000000000000000000000000000000001, 000000000000000000000000dc783b3cb88fdb2b01c61997746b655d7b54003e, 0000000000000000000000000000000000000000000000000000000000000000, 000000000000000000000000dc783b3cb88fdb2b01c61997746b655d7b54003e, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
356 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x35fb03d0d293ef5b362761900725ce891f8f766b5a662cdd445372355448e7ca( 0x35fb03d0d293ef5b362761900725ce891f8f766b5a662cdd445372355448e7ca, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000a6c5f2de915240270dac655152c3f6a91748cb85, 0x0000000000000000000000000000000000000000000000000000000000000002 )
357 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x5086d1bcea28999da9875111e3592688fbfa821db63214c695ca35768080c2fe( 0x5086d1bcea28999da9875111e3592688fbfa821db63214c695ca35768080c2fe, 0x000000000000000000000000a6c5f2de915240270dac655152c3f6a91748cb85, 0x0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000060, ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000042, 697066733a2f2f6261666b72656966326569747232656f71707662786b716c6e, 35637a6c6734757a33766636343234366934797435796a67626e627862616637, 3265000000000000000000000000000000000000000000000000000000000000 )
358 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x35fb03d0d293ef5b362761900725ce891f8f766b5a662cdd445372355448e7ca( 0x35fb03d0d293ef5b362761900725ce891f8f766b5a662cdd445372355448e7ca, 0x0000000000000000000000000000000000000000000000000000000000000001, 0x000000000000000000000000a6c5f2de915240270dac655152c3f6a91748cb85, 0x0000000000000000000000000000000000000000000000000000000000000002 )
359 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b( 0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b, 0x0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000042, 697066733a2f2f6261666b72656966326569747232656f71707662786b716c6e, 35637a6c6734757a33766636343234366934797435796a67626e627862616637, 3265000000000000000000000000000000000000000000000000000000000000 )
360 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x1b944478023872bf91b25a13fdba3a686fdb1bf4dbb872f850240fad4b8cc068( 0x1b944478023872bf91b25a13fdba3a686fdb1bf4dbb872f850240fad4b8cc068, 0x0000000000000000000000000000000000000000000000000000000000000001, 0x000000000000000000000000a6c5f2de915240270dac655152c3f6a91748cb85, 0000000000000000000000000000000000000000000000000000000000000040, ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0000000000000000000000000000000000000000000000000000000000000042, 697066733a2f2f6261666b72656966326569747232656f71707662786b716c6e, 35637a6c6734757a33766636343234366934797435796a67626e627862616637, 3265000000000000000000000000000000000000000000000000000000000000 )
361 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x5837d55897cfc337f160a71d7b63a047abd50a3a8834f1c5d70f338846358c6d( 0x5837d55897cfc337f160a71d7b63a047abd50a3a8834f1c5d70f338846358c6d, 0x0000000000000000000000000000000000000000000000000000000000000001, 0x000000000000000000000000a6c5f2de915240270dac655152c3f6a91748cb85, 0000000000000000000000000000000000000000000000000000000000000000, 00000000000000000000000000000000000000000000000000000000000001f4, 000000000000000000000000dc783b3cb88fdb2b01c61997746b655d7b54003e )
362 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x35fb03d0d293ef5b362761900725ce891f8f766b5a662cdd445372355448e7ca( 0x35fb03d0d293ef5b362761900725ce891f8f766b5a662cdd445372355448e7ca, 0x0000000000000000000000000000000000000000000000000000000000000001, 0x00000000000000000000000004e2516a2c207e84a1839755675dfd8ef6302f0a, 0x0000000000000000000000000000000000000000000000000000000000000004 )
363 ZoraCreatorFixedPriceSaleStrategy.SaleSet( mediaContract=0xaedc792d23ab8681f8c0154b2d57225095c7dbb3, tokenId=1, salesConfig=[{name:saleStart, type:uint64, order:1, indexed:false, value:1723399500, valueString:1723399500}, {name:saleEnd, type:uint64, order:2, indexed:false, value:18446744073709551615, valueString:18446744073709551615}, {name:maxTokensPerAddress, type:uint64, order:3, indexed:false, value:0, valueString:0}, {name:pricePerToken, type:uint96, order:4, indexed:false, value:15000000000000000, valueString:15000000000000000}, {name:fundsRecipient, type:address, order:5, indexed:false, value:0xDc783b3cb88Fdb2B01c61997746B655D7b54003e, valueString:0xDc783b3cb88Fdb2B01c61997746B655D7b54003e}] )
364 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x35fb03d0d293ef5b362761900725ce891f8f766b5a662cdd445372355448e7ca( 0x35fb03d0d293ef5b362761900725ce891f8f766b5a662cdd445372355448e7ca, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000a6c5f2de915240270dac655152c3f6a91748cb85, 0x0000000000000000000000000000000000000000000000000000000000000000 )
365 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498( 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498, 0000000000000000000000000000000000000000000000000000000000000001 )

Account State Difference:

  Address   Before After State Difference Code
0x04E2516A...eF6302F0a
(Titan Builder)
8.772756246750041411 Eth8.773206544974603786 Eth0.000450298224562375
0xA6C5f2DE...91748cb85
0xAedc792d...095c7dbB3
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 7580990366191477516319551431636853775417539837550867334602508048238757929087879027900449337487518794946950352205601743281030887287489436310908839699191659809388444823355674645354979357162961249134900110529687881663019692932138136169432064773836259952710621644470898343405927174133984597236657651087359028670195474342013788531238380808257890765480551801068149982708333191330653462914990335414292036779052701522397263760767722087683826927505529058253836012422366209295387656704517895932345491714654640330818408147054761662211806231406253405064807161040797747
0xDc783b3c...D7b54003e
0.014204400211053749 Eth
Nonce: 28
0.013122231116726989 Eth
Nonce: 29
0.00108216909432676

Execution Trace

Zora1155Factory.0582823a( )
  • ZoraCreator1155FactoryImpl.createContract( newContractURI=ipfs://bafkreidwbfvon4ihyqcrr6zj2ehts7sel4fd6bqssxtxacsenzbabramqm, name=Dancing Mocassins, defaultRoyaltyConfiguration=[{name:royaltyMintSchedule, type:uint32, order:1, indexed:false, value:0, valueString:0}, {name:royaltyBPS, type:uint32, order:2, indexed:false, value:500, valueString:500}, {name:royaltyRecipient, type:address, order:3, indexed:false, value:0xDc783b3cb88Fdb2B01c61997746B655D7b54003e, valueString:0xDc783b3cb88Fdb2B01c61997746B655D7b54003e}], defaultAdmin=0xDc783b3cb88Fdb2B01c61997746B655D7b54003e, setupActions=[Z0y65gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABg//////////////////////////////////////////8AAAAAAAAAAAAAAAB/ksjnrAjL7KEcpukpIGciZ4abBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCaXBmczovL2JhZmtyZWlmMmVpdHIyZW9xcHZieGtxbG41Y3psZzR1ejN2ZjY0MjQ2aTR5dDV5amdibmJ4YmFmNzJlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA, r+1+ngAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9AAAAAAAAAAAAAAAANx4Ozy4j9srAcYZl3RrZV17VAA+, jsmYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAABOJRaiwgfoShg5dVZ139jvYwLwoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA==, 2QS5SgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAABOJRaiwgfoShg5dVZ139jvYwLwoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADENNt+7gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGa4/UwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADVKa6ehgAAAAAAAAAAAAAAAAADceDs8uI/bKwHGGZd0a2Vde1QAPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=] ) => ( 0xAedc792d23AB8681F8c0154b2d57225095c7dbB3 )
    • 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.60406080( )
    • 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.8a08eb4c( )
      • ZoraCreator1155Impl.initialize( contractName=Dancing Mocassins, newContractURI=ipfs://bafkreidwbfvon4ihyqcrr6zj2ehts7sel4fd6bqssxtxacsenzbabramqm, defaultRoyaltyConfiguration=[{name:royaltyMintSchedule, type:uint32, order:1, indexed:false, value:0, valueString:0}, {name:royaltyBPS, type:uint32, order:2, indexed:false, value:500, valueString:500}, {name:royaltyRecipient, type:address, order:3, indexed:false, value:0xDc783b3cb88Fdb2B01c61997746B655D7b54003e, valueString:0xDc783b3cb88Fdb2B01c61997746B655D7b54003e}], defaultAdmin=0xDc783b3cb88Fdb2B01c61997746B655D7b54003e, setupActions=[Z0y65gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABg//////////////////////////////////////////8AAAAAAAAAAAAAAAB/ksjnrAjL7KEcpukpIGciZ4abBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCaXBmczovL2JhZmtyZWlmMmVpdHIyZW9xcHZieGtxbG41Y3psZzR1ejN2ZjY0MjQ2aTR5dDV5amdibmJ4YmFmNzJlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA, r+1+ngAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9AAAAAAAAAAAAAAAANx4Ozy4j9srAcYZl3RrZV17VAA+, jsmYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAABOJRaiwgfoShg5dVZ139jvYwLwoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA==, 2QS5SgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAABOJRaiwgfoShg5dVZ139jvYwLwoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADENNt+7gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGa4/UwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADVKa6ehgAAAAAAAAAAAAAAAAADceDs8uI/bKwHGGZd0a2Vde1QAPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=] )
        • 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.674cbae6( )
          • ZoraCreator1155Impl.setupNewTokenWithCreateReferral( newURI=ipfs://bafkreif2eitr2eoqpvbxkqln5czlg4uz3vf64246i4yt5yjgbnbxbaf72e, maxSupply=115792089237316195423570985008687907853269984665640564039457584007913129639935, createReferral=0x7f92C8e7AC08cBECa11ca6e92920672267869B06 ) => ( 1 )
          • 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.afed7e9e( )
            • ZoraCreator1155Impl.updateRoyaltiesForToken( tokenId=1, newConfiguration=[{name:royaltyMintSchedule, type:uint32, order:1, indexed:false, value:0, valueString:0}, {name:royaltyBPS, type:uint32, order:2, indexed:false, value:500, valueString:500}, {name:royaltyRecipient, type:address, order:3, indexed:false, value:0xDc783b3cb88Fdb2B01c61997746B655D7b54003e, valueString:0xDc783b3cb88Fdb2B01c61997746B655D7b54003e}] )
            • 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.8ec998a0( )
              • ZoraCreator1155Impl.addPermission( tokenId=1, user=0x04E2516A2c207E84a1839755675dfd8eF6302F0a, permissionBits=4 )
              • 0xaedc792d23ab8681f8c0154b2d57225095c7dbb3.d904b94a( )
                • ZoraCreator1155Impl.callSale( tokenId=1, salesConfig=0x04E2516A2c207E84a1839755675dfd8eF6302F0a, data=0x34DB7EEE00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000066B8FD4C000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000354A6BA7A18000000000000000000000000000DC783B3CB88FDB2B01C61997746B655D7B54003E )
                  • ZoraCreatorFixedPriceSaleStrategy.supportsInterface( interfaceId=System.Byte[] ) => ( True )
                  • ZoraCreatorFixedPriceSaleStrategy.setSale( tokenId=1, salesConfig=[{name:saleStart, type:uint64, order:1, indexed:false, value:1723399500, valueString:1723399500}, {name:saleEnd, type:uint64, order:2, indexed:false, value:18446744073709551615, valueString:18446744073709551615}, {name:maxTokensPerAddress, type:uint64, order:3, indexed:false, value:0, valueString:0}, {name:pricePerToken, type:uint96, order:4, indexed:false, value:15000000000000000, valueString:15000000000000000}, {name:fundsRecipient, type:address, order:5, indexed:false, value:0xDc783b3cb88Fdb2B01c61997746B655D7b54003e, valueString:0xDc783b3cb88Fdb2B01c61997746B655D7b54003e}] )
                    File 1 of 4: Zora1155Factory
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    /*
                                 ░░░░░░░░░░░░░░              
                            ░░▒▒░░░░░░░░░░░░░░░░░░░░        
                          ░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░      
                        ░░▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░    
                       ░▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░    
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░░  
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░░░  
                      ░▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░  
                      ░▓▓▓▓▓▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░  
                       ░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░  
                        ░░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░    
                        ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▒░░    
                          ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░      
                              ░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░          
                                   OURS TRULY,
                     */
                    interface Enjoy {
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
                    pragma solidity ^0.8.0;
                    /**
                     * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
                     * proxy whose upgrades are fully controlled by the current implementation.
                     */
                    interface IERC1822Proxiable {
                        /**
                         * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
                         * address.
                         *
                         * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                         * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                         * function revert if invoked through a proxy.
                         */
                        function proxiableUUID() external view returns (bytes32);
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)
                    pragma solidity ^0.8.0;
                    import "../Proxy.sol";
                    import "./ERC1967Upgrade.sol";
                    /**
                     * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
                     * implementation address that can be changed. This address is stored in storage in the location specified by
                     * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
                     * implementation behind the proxy.
                     */
                    contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                        /**
                         * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                         *
                         * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                         * function call, and allows initializing the storage of the proxy like a Solidity constructor.
                         */
                        constructor(address _logic, bytes memory _data) payable {
                            _upgradeToAndCall(_logic, _data, false);
                        }
                        /**
                         * @dev Returns the current implementation address.
                         */
                        function _implementation() internal view virtual override returns (address impl) {
                            return ERC1967Upgrade._getImplementation();
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
                    pragma solidity ^0.8.2;
                    import "../beacon/IBeacon.sol";
                    import "../../interfaces/draft-IERC1822.sol";
                    import "../../utils/Address.sol";
                    import "../../utils/StorageSlot.sol";
                    /**
                     * @dev This abstract contract provides getters and event emitting update functions for
                     * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                     *
                     * _Available since v4.1._
                     *
                     * @custom:oz-upgrades-unsafe-allow delegatecall
                     */
                    abstract contract ERC1967Upgrade {
                        // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                        bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                        /**
                         * @dev Storage slot with the address of the current implementation.
                         * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                         * validated in the constructor.
                         */
                        bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                        /**
                         * @dev Emitted when the implementation is upgraded.
                         */
                        event Upgraded(address indexed implementation);
                        /**
                         * @dev Returns the current implementation address.
                         */
                        function _getImplementation() internal view returns (address) {
                            return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                        }
                        /**
                         * @dev Stores a new address in the EIP1967 implementation slot.
                         */
                        function _setImplementation(address newImplementation) private {
                            require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                            StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                        }
                        /**
                         * @dev Perform implementation upgrade
                         *
                         * Emits an {Upgraded} event.
                         */
                        function _upgradeTo(address newImplementation) internal {
                            _setImplementation(newImplementation);
                            emit Upgraded(newImplementation);
                        }
                        /**
                         * @dev Perform implementation upgrade with additional setup call.
                         *
                         * Emits an {Upgraded} event.
                         */
                        function _upgradeToAndCall(
                            address newImplementation,
                            bytes memory data,
                            bool forceCall
                        ) internal {
                            _upgradeTo(newImplementation);
                            if (data.length > 0 || forceCall) {
                                Address.functionDelegateCall(newImplementation, data);
                            }
                        }
                        /**
                         * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                         *
                         * Emits an {Upgraded} event.
                         */
                        function _upgradeToAndCallUUPS(
                            address newImplementation,
                            bytes memory data,
                            bool forceCall
                        ) internal {
                            // Upgrades from old implementations will perform a rollback test. This test requires the new
                            // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
                            // this special case will break upgrade paths from old UUPS implementation to new ones.
                            if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
                                _setImplementation(newImplementation);
                            } else {
                                try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                                    require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
                                } catch {
                                    revert("ERC1967Upgrade: new implementation is not UUPS");
                                }
                                _upgradeToAndCall(newImplementation, data, forceCall);
                            }
                        }
                        /**
                         * @dev Storage slot with the admin of the contract.
                         * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                         * validated in the constructor.
                         */
                        bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                        /**
                         * @dev Emitted when the admin account has changed.
                         */
                        event AdminChanged(address previousAdmin, address newAdmin);
                        /**
                         * @dev Returns the current admin.
                         */
                        function _getAdmin() internal view returns (address) {
                            return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                        }
                        /**
                         * @dev Stores a new address in the EIP1967 admin slot.
                         */
                        function _setAdmin(address newAdmin) private {
                            require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                            StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                        }
                        /**
                         * @dev Changes the admin of the proxy.
                         *
                         * Emits an {AdminChanged} event.
                         */
                        function _changeAdmin(address newAdmin) internal {
                            emit AdminChanged(_getAdmin(), newAdmin);
                            _setAdmin(newAdmin);
                        }
                        /**
                         * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                         * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                         */
                        bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                        /**
                         * @dev Emitted when the beacon is upgraded.
                         */
                        event BeaconUpgraded(address indexed beacon);
                        /**
                         * @dev Returns the current beacon.
                         */
                        function _getBeacon() internal view returns (address) {
                            return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                        }
                        /**
                         * @dev Stores a new beacon in the EIP1967 beacon slot.
                         */
                        function _setBeacon(address newBeacon) private {
                            require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
                            require(
                                Address.isContract(IBeacon(newBeacon).implementation()),
                                "ERC1967: beacon implementation is not a contract"
                            );
                            StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                        }
                        /**
                         * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                         * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                         *
                         * Emits a {BeaconUpgraded} event.
                         */
                        function _upgradeBeaconToAndCall(
                            address newBeacon,
                            bytes memory data,
                            bool forceCall
                        ) internal {
                            _setBeacon(newBeacon);
                            emit BeaconUpgraded(newBeacon);
                            if (data.length > 0 || forceCall) {
                                Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
                    pragma solidity ^0.8.0;
                    /**
                     * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
                     * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
                     * be specified by overriding the virtual {_implementation} function.
                     *
                     * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
                     * different contract through the {_delegate} function.
                     *
                     * The success and return data of the delegated call will be returned back to the caller of the proxy.
                     */
                    abstract contract Proxy {
                        /**
                         * @dev Delegates the current call to `implementation`.
                         *
                         * This function does not return to its internal call site, it will return directly to the external caller.
                         */
                        function _delegate(address implementation) internal virtual {
                            assembly {
                                // Copy msg.data. We take full control of memory in this inline assembly
                                // block because it will not return to Solidity code. We overwrite the
                                // Solidity scratch pad at memory position 0.
                                calldatacopy(0, 0, calldatasize())
                                // Call the implementation.
                                // out and outsize are 0 because we don't know the size yet.
                                let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                                // Copy the returned data.
                                returndatacopy(0, 0, returndatasize())
                                switch result
                                // delegatecall returns 0 on error.
                                case 0 {
                                    revert(0, returndatasize())
                                }
                                default {
                                    return(0, returndatasize())
                                }
                            }
                        }
                        /**
                         * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
                         * and {_fallback} should delegate.
                         */
                        function _implementation() internal view virtual returns (address);
                        /**
                         * @dev Delegates the current call to the address returned by `_implementation()`.
                         *
                         * This function does not return to its internal call site, it will return directly to the external caller.
                         */
                        function _fallback() internal virtual {
                            _beforeFallback();
                            _delegate(_implementation());
                        }
                        /**
                         * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                         * function in the contract matches the call data.
                         */
                        fallback() external payable virtual {
                            _fallback();
                        }
                        /**
                         * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                         * is empty.
                         */
                        receive() external payable virtual {
                            _fallback();
                        }
                        /**
                         * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                         * call, or as part of the Solidity `fallback` or `receive` functions.
                         *
                         * If overridden should call `super._beforeFallback()`.
                         */
                        function _beforeFallback() internal virtual {}
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
                    pragma solidity ^0.8.0;
                    /**
                     * @dev This is the interface that {BeaconProxy} expects of its beacon.
                     */
                    interface IBeacon {
                        /**
                         * @dev Must return an address that can be used as a delegate call target.
                         *
                         * {BeaconProxy} will check that this address is a contract.
                         */
                        function implementation() external view returns (address);
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
                    pragma solidity ^0.8.1;
                    /**
                     * @dev Collection of functions related to the address type
                     */
                    library Address {
                        /**
                         * @dev Returns true if `account` is a contract.
                         *
                         * [IMPORTANT]
                         * ====
                         * It is unsafe to assume that an address for which this function returns
                         * false is an externally-owned account (EOA) and not a contract.
                         *
                         * Among others, `isContract` will return false for the following
                         * types of addresses:
                         *
                         *  - an externally-owned account
                         *  - a contract in construction
                         *  - an address where a contract will be created
                         *  - an address where a contract lived, but was destroyed
                         * ====
                         *
                         * [IMPORTANT]
                         * ====
                         * You shouldn't rely on `isContract` to protect against flash loan attacks!
                         *
                         * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                         * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                         * constructor.
                         * ====
                         */
                        function isContract(address account) internal view returns (bool) {
                            // This method relies on extcodesize/address.code.length, which returns 0
                            // for contracts in construction, since the code is only stored at the end
                            // of the constructor execution.
                            return account.code.length > 0;
                        }
                        /**
                         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                         * `recipient`, forwarding all available gas and reverting on errors.
                         *
                         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                         * of certain opcodes, possibly making contracts go over the 2300 gas limit
                         * imposed by `transfer`, making them unable to receive funds via
                         * `transfer`. {sendValue} removes this limitation.
                         *
                         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                         *
                         * IMPORTANT: because control is transferred to `recipient`, care must be
                         * taken to not create reentrancy vulnerabilities. Consider using
                         * {ReentrancyGuard} or the
                         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                         */
                        function sendValue(address payable recipient, uint256 amount) internal {
                            require(address(this).balance >= amount, "Address: insufficient balance");
                            (bool success, ) = recipient.call{value: amount}("");
                            require(success, "Address: unable to send value, recipient may have reverted");
                        }
                        /**
                         * @dev Performs a Solidity function call using a low level `call`. A
                         * plain `call` is an unsafe replacement for a function call: use this
                         * function instead.
                         *
                         * If `target` reverts with a revert reason, it is bubbled up by this
                         * function (like regular Solidity function calls).
                         *
                         * Returns the raw returned data. To convert to the expected return value,
                         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                         *
                         * Requirements:
                         *
                         * - `target` must be a contract.
                         * - calling `target` with `data` must not revert.
                         *
                         * _Available since v3.1._
                         */
                        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                            return functionCallWithValue(target, data, 0, "Address: low-level call failed");
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                         * `errorMessage` as a fallback revert reason when `target` reverts.
                         *
                         * _Available since v3.1._
                         */
                        function functionCall(
                            address target,
                            bytes memory data,
                            string memory errorMessage
                        ) internal returns (bytes memory) {
                            return functionCallWithValue(target, data, 0, errorMessage);
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                         * but also transferring `value` wei to `target`.
                         *
                         * Requirements:
                         *
                         * - the calling contract must have an ETH balance of at least `value`.
                         * - the called Solidity function must be `payable`.
                         *
                         * _Available since v3.1._
                         */
                        function functionCallWithValue(
                            address target,
                            bytes memory data,
                            uint256 value
                        ) internal returns (bytes memory) {
                            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                        }
                        /**
                         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                         * with `errorMessage` as a fallback revert reason when `target` reverts.
                         *
                         * _Available since v3.1._
                         */
                        function functionCallWithValue(
                            address target,
                            bytes memory data,
                            uint256 value,
                            string memory errorMessage
                        ) internal returns (bytes memory) {
                            require(address(this).balance >= value, "Address: insufficient balance for call");
                            (bool success, bytes memory returndata) = target.call{value: value}(data);
                            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                         * but performing a static call.
                         *
                         * _Available since v3.3._
                         */
                        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                            return functionStaticCall(target, data, "Address: low-level static call failed");
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                         * but performing a static call.
                         *
                         * _Available since v3.3._
                         */
                        function functionStaticCall(
                            address target,
                            bytes memory data,
                            string memory errorMessage
                        ) internal view returns (bytes memory) {
                            (bool success, bytes memory returndata) = target.staticcall(data);
                            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                         * but performing a delegate call.
                         *
                         * _Available since v3.4._
                         */
                        function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                            return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                         * but performing a delegate call.
                         *
                         * _Available since v3.4._
                         */
                        function functionDelegateCall(
                            address target,
                            bytes memory data,
                            string memory errorMessage
                        ) internal returns (bytes memory) {
                            (bool success, bytes memory returndata) = target.delegatecall(data);
                            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                        }
                        /**
                         * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                         * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                         *
                         * _Available since v4.8._
                         */
                        function verifyCallResultFromTarget(
                            address target,
                            bool success,
                            bytes memory returndata,
                            string memory errorMessage
                        ) internal view returns (bytes memory) {
                            if (success) {
                                if (returndata.length == 0) {
                                    // only check isContract if the call was successful and the return data is empty
                                    // otherwise we already know that it was a contract
                                    require(isContract(target), "Address: call to non-contract");
                                }
                                return returndata;
                            } else {
                                _revert(returndata, errorMessage);
                            }
                        }
                        /**
                         * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                         * revert reason or using the provided one.
                         *
                         * _Available since v4.3._
                         */
                        function verifyCallResult(
                            bool success,
                            bytes memory returndata,
                            string memory errorMessage
                        ) internal pure returns (bytes memory) {
                            if (success) {
                                return returndata;
                            } else {
                                _revert(returndata, errorMessage);
                            }
                        }
                        function _revert(bytes memory returndata, string memory errorMessage) private pure {
                            // Look for revert reason and bubble it up if present
                            if (returndata.length > 0) {
                                // The easiest way to bubble the revert reason is using memory via assembly
                                /// @solidity memory-safe-assembly
                                assembly {
                                    let returndata_size := mload(returndata)
                                    revert(add(32, returndata), returndata_size)
                                }
                            } else {
                                revert(errorMessage);
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)
                    pragma solidity ^0.8.0;
                    /**
                     * @dev Library for reading and writing primitive types to specific storage slots.
                     *
                     * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                     * This library helps with reading and writing to such slots without the need for inline assembly.
                     *
                     * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                     *
                     * Example usage to set ERC1967 implementation slot:
                     * ```
                     * contract ERC1967 {
                     *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                     *
                     *     function _getImplementation() internal view returns (address) {
                     *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                     *     }
                     *
                     *     function _setImplementation(address newImplementation) internal {
                     *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                     *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                     *     }
                     * }
                     * ```
                     *
                     * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
                     */
                    library StorageSlot {
                        struct AddressSlot {
                            address value;
                        }
                        struct BooleanSlot {
                            bool value;
                        }
                        struct Bytes32Slot {
                            bytes32 value;
                        }
                        struct Uint256Slot {
                            uint256 value;
                        }
                        /**
                         * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                         */
                        function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                         */
                        function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                         */
                        function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                         */
                        function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {Enjoy} from "_imagine/mint/Enjoy.sol";
                    import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
                    /*
                                 ░░░░░░░░░░░░░░              
                            ░░▒▒░░░░░░░░░░░░░░░░░░░░        
                          ░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░      
                        ░░▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░    
                       ░▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░    
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░░  
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░░░  
                      ░▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░  
                      ░▓▓▓▓▓▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░  
                       ░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░  
                        ░░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░    
                        ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▒░░    
                          ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░      
                              ░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░          
                                   OURS TRULY,
                     */
                    /// Imagine. Mint. Enjoy.
                    /// @notice Imagine. Mint. Enjoy.
                    /// @author @iainnash / @tbtstl
                    contract Zora1155Factory is Enjoy, ERC1967Proxy {
                        constructor(address _logic, bytes memory _data) ERC1967Proxy(_logic, _data) {}
                    }
                    

                    File 2 of 4: ZoraCreatorFixedPriceSaleStrategy
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {Enjoy} from "_imagine/mint/Enjoy.sol";
                    import {IMinter1155} from "../../interfaces/IMinter1155.sol";
                    import {ICreatorCommands} from "../../interfaces/ICreatorCommands.sol";
                    import {SaleStrategy} from "../SaleStrategy.sol";
                    import {SaleCommandHelper} from "../utils/SaleCommandHelper.sol";
                    import {LimitedMintPerAddress} from "../utils/LimitedMintPerAddress.sol";
                    /*
                                 ░░░░░░░░░░░░░░              
                            ░░▒▒░░░░░░░░░░░░░░░░░░░░        
                          ░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░      
                        ░░▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░    
                       ░▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░    
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░░  
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░░░  
                      ░▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░  
                      ░▓▓▓▓▓▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░  
                       ░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░  
                        ░░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░    
                        ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▒░░    
                          ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░      
                              ░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░          
                                   OURS TRULY,
                        github.com/ourzora/zora-1155-contracts
                    */
                    /// @title ZoraCreatorFixedPriceSaleStrategy
                    /// @notice A sale strategy for ZoraCreator that allows for fixed price sales over a given time period
                    /// @author @iainnash / @tbtstl
                    contract ZoraCreatorFixedPriceSaleStrategy is Enjoy, SaleStrategy, LimitedMintPerAddress {
                        struct SalesConfig {
                            /// @notice Unix timestamp for the sale start
                            uint64 saleStart;
                            /// @notice Unix timestamp for the sale end
                            uint64 saleEnd;
                            /// @notice Max tokens that can be minted for an address, 0 if unlimited
                            uint64 maxTokensPerAddress;
                            /// @notice Price per token in eth wei
                            uint96 pricePerToken;
                            /// @notice Funds recipient (0 if no different funds recipient than the contract global)
                            address fundsRecipient;
                        }
                        // target -> tokenId -> settings
                        mapping(address => mapping(uint256 => SalesConfig)) internal salesConfigs;
                        using SaleCommandHelper for ICreatorCommands.CommandSet;
                        function contractURI() external pure override returns (string memory) {
                            return "https://github.com/ourzora/zora-1155-contracts/";
                        }
                        /// @notice The name of the sale strategy
                        function contractName() external pure override returns (string memory) {
                            return "Fixed Price Sale Strategy";
                        }
                        /// @notice The version of the sale strategy
                        function contractVersion() external pure override returns (string memory) {
                            return "1.1.0";
                        }
                        error WrongValueSent();
                        error SaleEnded();
                        error SaleHasNotStarted();
                        event SaleSet(address indexed mediaContract, uint256 indexed tokenId, SalesConfig salesConfig);
                        event MintComment(address indexed sender, address indexed tokenContract, uint256 indexed tokenId, uint256 quantity, string comment);
                        /// @notice Compiles and returns the commands needed to mint a token using this sales strategy
                        /// @param tokenId The token ID to mint
                        /// @param quantity The quantity of tokens to mint
                        /// @param ethValueSent The amount of ETH sent with the transaction
                        /// @param minterArguments The arguments passed to the minter, which should be the address to mint to
                        function requestMint(
                            address,
                            uint256 tokenId,
                            uint256 quantity,
                            uint256 ethValueSent,
                            bytes calldata minterArguments
                        ) external returns (ICreatorCommands.CommandSet memory commands) {
                            address mintTo;
                            string memory comment = "";
                            if (minterArguments.length == 32) {
                                mintTo = abi.decode(minterArguments, (address));
                            } else {
                                (mintTo, comment) = abi.decode(minterArguments, (address, string));
                            }
                            SalesConfig storage config = salesConfigs[msg.sender][tokenId];
                            // If sales config does not exist this first check will always fail.
                            // Check sale end
                            if (block.timestamp > config.saleEnd) {
                                revert SaleEnded();
                            }
                            // Check sale start
                            if (block.timestamp < config.saleStart) {
                                revert SaleHasNotStarted();
                            }
                            // Check value sent
                            if (config.pricePerToken * quantity != ethValueSent) {
                                revert WrongValueSent();
                            }
                            // Check minted per address limit
                            if (config.maxTokensPerAddress > 0) {
                                _requireMintNotOverLimitAndUpdate(config.maxTokensPerAddress, quantity, msg.sender, tokenId, mintTo);
                            }
                            bool shouldTransferFunds = config.fundsRecipient != address(0);
                            commands.setSize(shouldTransferFunds ? 2 : 1);
                            // Mint command
                            commands.mint(mintTo, tokenId, quantity);
                            if (bytes(comment).length > 0) {
                                emit MintComment(mintTo, msg.sender, tokenId, quantity, comment);
                            }
                            // Should transfer funds if funds recipient is set to a non-default address
                            if (shouldTransferFunds) {
                                commands.transfer(config.fundsRecipient, ethValueSent);
                            }
                        }
                        /// @notice Sets the sale config for a given token
                        function setSale(uint256 tokenId, SalesConfig memory salesConfig) external {
                            salesConfigs[msg.sender][tokenId] = salesConfig;
                            // Emit event
                            emit SaleSet(msg.sender, tokenId, salesConfig);
                        }
                        /// @notice Deletes the sale config for a given token
                        function resetSale(uint256 tokenId) external override {
                            delete salesConfigs[msg.sender][tokenId];
                            // Deleted sale emit event
                            emit SaleSet(msg.sender, tokenId, salesConfigs[msg.sender][tokenId]);
                        }
                        /// @notice Returns the sale config for a given token
                        function sale(address tokenContract, uint256 tokenId) external view returns (SalesConfig memory) {
                            return salesConfigs[tokenContract][tokenId];
                        }
                        function supportsInterface(bytes4 interfaceId) public pure virtual override(LimitedMintPerAddress, SaleStrategy) returns (bool) {
                            return super.supportsInterface(interfaceId) || LimitedMintPerAddress.supportsInterface(interfaceId) || SaleStrategy.supportsInterface(interfaceId);
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    /*
                                 ░░░░░░░░░░░░░░              
                            ░░▒▒░░░░░░░░░░░░░░░░░░░░        
                          ░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░      
                        ░░▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░    
                       ░▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░    
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░░  
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░░░  
                      ░▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░  
                      ░▓▓▓▓▓▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░  
                       ░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░  
                        ░░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░    
                        ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▒░░    
                          ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░      
                              ░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░          
                                   OURS TRULY,
                     */
                    interface Enjoy {
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IERC165Upgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC165Upgradeable.sol";
                    import {ICreatorCommands} from "./ICreatorCommands.sol";
                    /// @notice Minter standard interface
                    /// @dev Minters need to confirm to the ERC165 selector of type(IMinter1155).interfaceId
                    interface IMinter1155 is IERC165Upgradeable {
                        function requestMint(
                            address sender,
                            uint256 tokenId,
                            uint256 quantity,
                            uint256 ethValueSent,
                            bytes calldata minterArguments
                        ) external returns (ICreatorCommands.CommandSet memory commands);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    /// @notice Creator Commands used by minter modules passed back to the main modules
                    interface ICreatorCommands {
                        /// @notice This enum is used to define supported creator action types.
                        /// This can change in the future
                        enum CreatorActions {
                            // No operation - also the default for mintings that may not return a command
                            NO_OP,
                            // Send ether
                            SEND_ETH,
                            // Mint operation
                            MINT
                        }
                        /// @notice This command is for
                        struct Command {
                            // Method for operation
                            CreatorActions method;
                            // Arguments used for this operation
                            bytes args;
                        }
                        /// @notice This command set is returned from the minter back to the user
                        struct CommandSet {
                            Command[] commands;
                            uint256 at;
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IERC165Upgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC165Upgradeable.sol";
                    import {IMinter1155} from "../interfaces/IMinter1155.sol";
                    import {IContractMetadata} from "../interfaces/IContractMetadata.sol";
                    import {IVersionedContract} from "../interfaces/IVersionedContract.sol";
                    /// @notice Sales Strategy Helper contract template on top of IMinter1155
                    /// @author @iainnash / @tbtstl
                    abstract contract SaleStrategy is IMinter1155, IVersionedContract, IContractMetadata {
                        /// @notice This function resets the sales configuration for a given tokenId and contract.
                        /// @dev This function is intentioned to be called directly from the affected sales contract
                        function resetSale(uint256 tokenId) external virtual;
                        function supportsInterface(bytes4 interfaceId) public pure virtual returns (bool) {
                            return interfaceId == type(IMinter1155).interfaceId || interfaceId == type(IERC165Upgradeable).interfaceId;
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {ICreatorCommands} from "../../interfaces/ICreatorCommands.sol";
                    /// @title SaleCommandHelper
                    /// @notice Helper library for creating commands for the sale contract
                    /// @author @iainnash / @tbtstl
                    library SaleCommandHelper {
                        /// @notice Sets the size of commands and initializes command array. Empty entries are skipped by the resolver.
                        /// @dev Beware: this removes all previous command entries from memory
                        /// @param commandSet command set struct storage.
                        /// @param size size to set for the new struct
                        function setSize(ICreatorCommands.CommandSet memory commandSet, uint256 size) internal pure {
                            commandSet.commands = new ICreatorCommands.Command[](size);
                        }
                        /// @notice Creates a command to mint a token
                        /// @param commandSet The command set to add the command to
                        /// @param to The address to mint to
                        /// @param tokenId The token ID to mint
                        /// @param quantity The quantity of tokens to mint
                        function mint(ICreatorCommands.CommandSet memory commandSet, address to, uint256 tokenId, uint256 quantity) internal pure {
                            unchecked {
                                commandSet.commands[commandSet.at++] = ICreatorCommands.Command({
                                    method: ICreatorCommands.CreatorActions.MINT,
                                    args: abi.encode(to, tokenId, quantity)
                                });
                            }
                        }
                        /// @notice Creates a command to transfer ETH
                        /// @param commandSet The command set to add the command to
                        /// @param to The address to transfer to
                        /// @param amount The amount of ETH to transfer
                        function transfer(ICreatorCommands.CommandSet memory commandSet, address to, uint256 amount) internal pure {
                            unchecked {
                                commandSet.commands[commandSet.at++] = ICreatorCommands.Command({method: ICreatorCommands.CreatorActions.SEND_ETH, args: abi.encode(to, amount)});
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {ILimitedMintPerAddress} from "../../interfaces/ILimitedMintPerAddress.sol";
                    contract LimitedMintPerAddress is ILimitedMintPerAddress {
                        /// @notice Storage for slot to check user mints
                        /// @notice target contract -> tokenId -> minter user -> numberMinted
                        /// @dev No gap or stroage interface since this is used within non-upgradeable contracts
                        mapping(address => mapping(uint256 => mapping(address => uint256))) internal mintedPerAddress;
                        function getMintedPerWallet(address tokenContract, uint256 tokenId, address wallet) external view returns (uint256) {
                            return mintedPerAddress[tokenContract][tokenId][wallet];
                        }
                        function _requireMintNotOverLimitAndUpdate(uint256 limit, uint256 numRequestedMint, address tokenContract, uint256 tokenId, address wallet) internal {
                            mintedPerAddress[tokenContract][tokenId][wallet] += numRequestedMint;
                            if (mintedPerAddress[tokenContract][tokenId][wallet] > limit) {
                                revert UserExceedsMintLimit(wallet, limit, mintedPerAddress[tokenContract][tokenId][wallet]);
                            }
                        }
                        function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
                            return interfaceId == type(ILimitedMintPerAddress).interfaceId;
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)
                    pragma solidity ^0.8.0;
                    import "../utils/introspection/IERC165Upgradeable.sol";
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    interface IHasContractName {
                        /// @notice Contract name returns the pretty contract name
                        function contractName() external returns (string memory);
                    }
                    interface IContractMetadata is IHasContractName {
                        /// @notice Contract URI returns the uri for more information about the given contract
                        function contractURI() external returns (string memory);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    interface IVersionedContract {
                        function contractVersion() external returns (string memory);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IERC165Upgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC165Upgradeable.sol";
                    interface ILimitedMintPerAddress is IERC165Upgradeable {
                        error UserExceedsMintLimit(address user, uint256 limit, uint256 requestedAmount);
                        function getMintedPerWallet(address token, uint256 tokenId, address wallet) external view returns (uint256);
                    }
                    // 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 IERC165Upgradeable {
                        /**
                         * @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);
                    }
                    

                    File 3 of 4: ZoraCreator1155FactoryImpl
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {Initializable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
                    import {UUPSUpgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
                    import {IZoraCreator1155Factory} from "../interfaces/IZoraCreator1155Factory.sol";
                    import {IZoraCreator1155Initializer} from "../interfaces/IZoraCreator1155Initializer.sol";
                    import {IZoraCreator1155} from "../interfaces/IZoraCreator1155.sol";
                    import {ICreatorRoyaltiesControl} from "../interfaces/ICreatorRoyaltiesControl.sol";
                    import {IMinter1155} from "../interfaces/IMinter1155.sol";
                    import {IContractMetadata} from "../interfaces/IContractMetadata.sol";
                    import {Ownable2StepUpgradeable} from "../utils/ownable/Ownable2StepUpgradeable.sol";
                    import {FactoryManagedUpgradeGate} from "../upgrades/FactoryManagedUpgradeGate.sol";
                    import {Zora1155} from "../proxies/Zora1155.sol";
                    import {ContractVersionBase} from "../version/ContractVersionBase.sol";
                    /// @title ZoraCreator1155FactoryImpl
                    /// @notice Factory contract for creating new ZoraCreator1155 contracts
                    contract ZoraCreator1155FactoryImpl is IZoraCreator1155Factory, ContractVersionBase, FactoryManagedUpgradeGate, UUPSUpgradeable, IContractMetadata {
                        IZoraCreator1155 public immutable implementation;
                        IMinter1155 public immutable merkleMinter;
                        IMinter1155 public immutable fixedPriceMinter;
                        IMinter1155 public immutable redeemMinterFactory;
                        constructor(IZoraCreator1155 _implementation, IMinter1155 _merkleMinter, IMinter1155 _fixedPriceMinter, IMinter1155 _redeemMinterFactory) initializer {
                            implementation = _implementation;
                            if (address(implementation) == address(0)) {
                                revert Constructor_ImplCannotBeZero();
                            }
                            merkleMinter = _merkleMinter;
                            fixedPriceMinter = _fixedPriceMinter;
                            redeemMinterFactory = _redeemMinterFactory;
                        }
                        /// @notice ContractURI for contract information with the strategy
                        function contractURI() external pure returns (string memory) {
                            return "https://github.com/ourzora/zora-1155-contracts/";
                        }
                        /// @notice The name of the sale strategy
                        function contractName() external pure returns (string memory) {
                            return "ZORA 1155 Contract Factory";
                        }
                        /// @notice The default minters for new 1155 contracts
                        function defaultMinters() external view returns (IMinter1155[] memory minters) {
                            minters = new IMinter1155[](3);
                            minters[0] = fixedPriceMinter;
                            minters[1] = merkleMinter;
                            minters[2] = redeemMinterFactory;
                        }
                        function initialize(address _initialOwner) public initializer {
                            __Ownable_init(_initialOwner);
                            __UUPSUpgradeable_init();
                            emit FactorySetup();
                        }
                        /// @notice Creates a new ZoraCreator1155 contract
                        /// @param newContractURI The URI for the contract metadata
                        /// @param name The name of the contract
                        /// @param defaultRoyaltyConfiguration The default royalty configuration for the contract
                        /// @param defaultAdmin The default admin for the contract
                        /// @param setupActions The actions to perform on the new contract upon initialization
                        function createContract(
                            string memory newContractURI,
                            string calldata name,
                            ICreatorRoyaltiesControl.RoyaltyConfiguration memory defaultRoyaltyConfiguration,
                            address payable defaultAdmin,
                            bytes[] calldata setupActions
                        ) external returns (address) {
                            address newContract = address(new Zora1155(address(implementation)));
                            emit SetupNewContract({
                                newContract: address(newContract),
                                creator: msg.sender,
                                defaultAdmin: defaultAdmin,
                                contractURI: newContractURI,
                                name: name,
                                defaultRoyaltyConfiguration: defaultRoyaltyConfiguration
                            });
                            IZoraCreator1155Initializer(newContract).initialize(name, newContractURI, defaultRoyaltyConfiguration, defaultAdmin, setupActions);
                            return address(newContract);
                        }
                        ///                                                          ///
                        ///                         MANAGER UPGRADE                  ///
                        ///                                                          ///
                        /// @notice Ensures the caller is authorized to upgrade the contract
                        /// @dev This function is called in `upgradeTo` & `upgradeToAndCall`
                        /// @param _newImpl The new implementation address
                        function _authorizeUpgrade(address _newImpl) internal override onlyOwner {
                            if (!_equals(IContractMetadata(_newImpl).contractName(), this.contractName())) {
                                revert UpgradeToMismatchedContractName(this.contractName(), IContractMetadata(_newImpl).contractName());
                            }
                        }
                        function _equals(string memory a, string memory b) internal pure returns (bool) {
                            return (keccak256(bytes(a)) == keccak256(bytes(b)));
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol)
                    pragma solidity ^0.8.2;
                    import "../../utils/AddressUpgradeable.sol";
                    error INITIALIZABLE_CONTRACT_ALREADY_INITIALIZED();
                    error INITIALIZABLE_CONTRACT_IS_NOT_INITIALIZING();
                    error INITIALIZABLE_CONTRACT_IS_INITIALIZING();
                    /**
                     * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                     * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
                     * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                     * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                     *
                     * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
                     * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
                     * case an upgrade adds a module that needs to be initialized.
                     *
                     * For example:
                     *
                     * [.hljs-theme-light.nopadding]
                     * ```solidity
                     * contract MyToken is ERC20Upgradeable {
                     *     function initialize() initializer public {
                     *         __ERC20_init("MyToken", "MTK");
                     *     }
                     * }
                     *
                     * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
                     *     function initializeV2() reinitializer(2) public {
                     *         __ERC20Permit_init("MyToken");
                     *     }
                     * }
                     * ```
                     *
                     * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                     * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                     *
                     * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                     * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                     *
                     * [CAUTION]
                     * ====
                     * Avoid leaving a contract uninitialized.
                     *
                     * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
                     * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
                     * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
                     *
                     * [.hljs-theme-light.nopadding]
                     * ```
                     * /// @custom:oz-upgrades-unsafe-allow constructor
                     * constructor() {
                     *     _disableInitializers();
                     * }
                     * ```
                     * ====
                     */
                    abstract contract Initializable {
                        /**
                         * @dev Indicates that the contract has been initialized.
                         * @custom:oz-retyped-from bool
                         */
                        uint8 private _initialized;
                        /**
                         * @dev Indicates that the contract is in the process of being initialized.
                         */
                        bool private _initializing;
                        /**
                         * @dev Triggered when the contract has been initialized or reinitialized.
                         */
                        event Initialized(uint8 version);
                        /**
                         * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                         * `onlyInitializing` functions can be used to initialize parent contracts.
                         *
                         * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
                         * constructor.
                         *
                         * Emits an {Initialized} event.
                         */
                        modifier initializer() {
                            bool isTopLevelCall = !_initializing;
                            if ((!isTopLevelCall || _initialized != 0) && (AddressUpgradeable.isContract(address(this)) || _initialized != 1)) {
                                revert INITIALIZABLE_CONTRACT_ALREADY_INITIALIZED();
                            }
                            _initialized = 1;
                            if (isTopLevelCall) {
                                _initializing = true;
                            }
                            _;
                            if (isTopLevelCall) {
                                _initializing = false;
                                emit Initialized(1);
                            }
                        }
                        /**
                         * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                         * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                         * used to initialize parent contracts.
                         *
                         * A reinitializer may be used after the original initialization step. This is essential to configure modules that
                         * are added through upgrades and that require initialization.
                         *
                         * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
                         * cannot be nested. If one is invoked in the context of another, execution will revert.
                         *
                         * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                         * a contract, executing them in the right order is up to the developer or operator.
                         *
                         * WARNING: setting the version to 255 will prevent any future reinitialization.
                         *
                         * Emits an {Initialized} event.
                         */
                        modifier reinitializer(uint8 version) {
                            if (_initializing || _initialized >= version) {
                                revert INITIALIZABLE_CONTRACT_ALREADY_INITIALIZED();
                            }
                            _initialized = version;
                            _initializing = true;
                            _;
                            _initializing = false;
                            emit Initialized(version);
                        }
                        /**
                         * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                         * {initializer} and {reinitializer} modifiers, directly or indirectly.
                         */
                        modifier onlyInitializing() {
                            if (!_initializing) {
                                revert INITIALIZABLE_CONTRACT_IS_NOT_INITIALIZING();
                            }
                            _;
                        }
                        /**
                         * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                         * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                         * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                         * through proxies.
                         *
                         * Emits an {Initialized} event the first time it is successfully executed.
                         */
                        function _disableInitializers() internal virtual {
                            if (_initializing) {
                                revert INITIALIZABLE_CONTRACT_IS_INITIALIZING();
                            }
                            if (_initialized != type(uint8).max) {
                                _initialized = type(uint8).max;
                                emit Initialized(type(uint8).max);
                            }
                        }
                        /**
                         * @dev Returns the highest version that has been initialized. See {reinitializer}.
                         */
                        function _getInitializedVersion() internal view returns (uint8) {
                            return _initialized;
                        }
                        /**
                         * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
                         */
                        function _isInitializing() internal view returns (bool) {
                            return _initializing;
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol)
                    pragma solidity ^0.8.0;
                    import "../../interfaces/draft-IERC1822Upgradeable.sol";
                    import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
                    import "./Initializable.sol";
                    error FUNCTION_MUST_BE_CALLED_THROUGH_DELEGATECALL();
                    error FUNCTION_MUST_BE_CALLED_THROUGH_ACTIVE_PROXY();
                    error UUPS_UPGRADEABLE_MUST_NOT_BE_CALLED_THROUGH_DELEGATECALL();
                    /**
                     * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
                     * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
                     *
                     * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
                     * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
                     * `UUPSUpgradeable` with a custom implementation of upgrades.
                     *
                     * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
                     *
                     * _Available since v4.1._
                     */
                    abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
                        function __UUPSUpgradeable_init() internal onlyInitializing {
                        }
                        function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
                        }
                        /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
                        address private immutable __self = address(this);
                        /**
                         * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
                         * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
                         * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
                         * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
                         * fail.
                         */
                        modifier onlyProxy() {
                            if (address(this) == __self) {
                                revert FUNCTION_MUST_BE_CALLED_THROUGH_DELEGATECALL();
                            }
                            if (_getImplementation() != __self) {
                                revert FUNCTION_MUST_BE_CALLED_THROUGH_ACTIVE_PROXY();
                            }
                            _;
                        }
                        /**
                         * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
                         * callable on the implementing contract but not through proxies.
                         */
                        modifier notDelegated() {
                            if (address(this) != __self) {
                                revert UUPS_UPGRADEABLE_MUST_NOT_BE_CALLED_THROUGH_DELEGATECALL();
                            }
                            _;
                        }
                        /**
                         * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
                         * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
                         *
                         * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                         * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                         * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
                         */
                        function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
                            return _IMPLEMENTATION_SLOT;
                        }
                        /**
                         * @dev Upgrade the implementation of the proxy to `newImplementation`.
                         *
                         * Calls {_authorizeUpgrade}.
                         *
                         * Emits an {Upgraded} event.
                         *
                         * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                         */
                        function upgradeTo(address newImplementation) public virtual onlyProxy {
                            _authorizeUpgrade(newImplementation);
                            _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
                        }
                        /**
                         * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
                         * encoded in `data`.
                         *
                         * Calls {_authorizeUpgrade}.
                         *
                         * Emits an {Upgraded} event.
                         *
                         * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                         */
                        function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
                            _authorizeUpgrade(newImplementation);
                            _upgradeToAndCallUUPS(newImplementation, data, true);
                        }
                        /**
                         * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                         * {upgradeTo} and {upgradeToAndCall}.
                         *
                         * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
                         *
                         * ```solidity
                         * function _authorizeUpgrade(address) internal override onlyOwner {}
                         * ```
                         */
                        function _authorizeUpgrade(address newImplementation) internal virtual;
                        /**
                         * @dev This empty reserved space is put in place to allow future versions to add new
                         * variables without shifting down storage in the inheritance chain.
                         * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                         */
                        uint256[50] private __gap;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {ICreatorRoyaltiesControl} from "./ICreatorRoyaltiesControl.sol";
                    import {IMinter1155} from "./IMinter1155.sol";
                    import {IVersionedContract} from "./IVersionedContract.sol";
                    /// @notice Factory for 1155 contracts
                    /// @author @iainnash / @tbtstl
                    interface IZoraCreator1155Factory is IVersionedContract {
                        error Constructor_ImplCannotBeZero();
                        error UpgradeToMismatchedContractName(string expected, string actual);
                        event FactorySetup();
                        event SetupNewContract(
                            address indexed newContract,
                            address indexed creator,
                            address indexed defaultAdmin,
                            string contractURI,
                            string name,
                            ICreatorRoyaltiesControl.RoyaltyConfiguration defaultRoyaltyConfiguration
                        );
                        function createContract(
                            string memory contractURI,
                            string calldata name,
                            ICreatorRoyaltiesControl.RoyaltyConfiguration memory defaultRoyaltyConfiguration,
                            address payable defaultAdmin,
                            bytes[] calldata setupActions
                        ) external returns (address);
                        function defaultMinters() external returns (IMinter1155[] memory minters);
                        function initialize(address _owner) external;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {ICreatorRoyaltiesControl} from "../interfaces/ICreatorRoyaltiesControl.sol";
                    interface IZoraCreator1155Initializer {
                        function initialize(
                            string memory contractName,
                            string memory newContractURI,
                            ICreatorRoyaltiesControl.RoyaltyConfiguration memory defaultRoyaltyConfiguration,
                            address payable defaultAdmin,
                            bytes[] calldata setupActions
                        ) external;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IERC165Upgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC165Upgradeable.sol";
                    import {IERC1155MetadataURIUpgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC1155MetadataURIUpgradeable.sol";
                    import {IZoraCreator1155TypesV1} from "../nft/IZoraCreator1155TypesV1.sol";
                    import {IRenderer1155} from "../interfaces/IRenderer1155.sol";
                    import {IMinter1155} from "../interfaces/IMinter1155.sol";
                    import {IOwnable} from "../interfaces/IOwnable.sol";
                    import {IVersionedContract} from "./IVersionedContract.sol";
                    import {ICreatorRoyaltiesControl} from "../interfaces/ICreatorRoyaltiesControl.sol";
                    /*
                                 ░░░░░░░░░░░░░░              
                            ░░▒▒░░░░░░░░░░░░░░░░░░░░        
                          ░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░      
                        ░░▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░    
                       ░▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░    
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░░  
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░░░  
                      ░▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░  
                      ░▓▓▓▓▓▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░  
                       ░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░  
                        ░░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░    
                        ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▒░░    
                          ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░      
                              ░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░          
                                   OURS TRULY,
                     */
                    /// @notice Main interface for the ZoraCreator1155 contract
                    /// @author @iainnash / @tbtstl
                    interface IZoraCreator1155 is IZoraCreator1155TypesV1, IVersionedContract, IOwnable, IERC1155MetadataURIUpgradeable {
                        function PERMISSION_BIT_ADMIN() external returns (uint256);
                        function PERMISSION_BIT_MINTER() external returns (uint256);
                        function PERMISSION_BIT_SALES() external returns (uint256);
                        function PERMISSION_BIT_METADATA() external returns (uint256);
                        /// @notice Used to label the configuration update type
                        enum ConfigUpdate {
                            OWNER,
                            FUNDS_RECIPIENT,
                            TRANSFER_HOOK
                        }
                        event ConfigUpdated(address indexed updater, ConfigUpdate indexed updateType, ContractConfig newConfig);
                        event UpdatedToken(address indexed from, uint256 indexed tokenId, TokenData tokenData);
                        event SetupNewToken(uint256 indexed tokenId, address indexed sender, string newURI, uint256 maxSupply);
                        function setOwner(address newOwner) external;
                        event ContractRendererUpdated(IRenderer1155 renderer);
                        event ContractMetadataUpdated(address indexed updater, string uri, string name);
                        event Purchased(address indexed sender, address indexed minter, uint256 indexed tokenId, uint256 quantity, uint256 value);
                        error TokenIdMismatch(uint256 expected, uint256 actual);
                        error UserMissingRoleForToken(address user, uint256 tokenId, uint256 role);
                        error Config_TransferHookNotSupported(address proposedAddress);
                        error Mint_InsolventSaleTransfer();
                        error Mint_ValueTransferFail();
                        error Mint_TokenIDMintNotAllowed();
                        error Mint_UnknownCommand();
                        error Burn_NotOwnerOrApproved(address operator, address user);
                        error NewOwnerNeedsToBeAdmin();
                        error Sale_CannotCallNonSalesContract(address targetContract);
                        error CallFailed(bytes reason);
                        error Renderer_NotValidRendererContract();
                        error ETHWithdrawFailed(address recipient, uint256 amount);
                        error FundsWithdrawInsolvent(uint256 amount, uint256 contractValue);
                        error ProtocolRewardsWithdrawFailed(address caller, address recipient, uint256 amount);
                        error CannotMintMoreTokens(uint256 tokenId, uint256 quantity, uint256 totalMinted, uint256 maxSupply);
                        /// @notice Only allow minting one token id at time
                        /// @dev Mint contract function that calls the underlying sales function for commands
                        /// @param minter Address for the minter
                        /// @param tokenId tokenId to mint, set to 0 for new tokenId
                        /// @param quantity to mint
                        /// @param minterArguments calldata for the minter contracts
                        function mint(IMinter1155 minter, uint256 tokenId, uint256 quantity, bytes calldata minterArguments) external payable;
                        function adminMint(address recipient, uint256 tokenId, uint256 quantity, bytes memory data) external;
                        function adminMintBatch(address recipient, uint256[] memory tokenIds, uint256[] memory quantities, bytes memory data) external;
                        function burnBatch(address user, uint256[] calldata tokenIds, uint256[] calldata amounts) external;
                        /// @notice Contract call to setupNewToken
                        /// @param tokenURI URI for the token
                        /// @param maxSupply maxSupply for the token, set to 0 for open edition
                        function setupNewToken(string memory tokenURI, uint256 maxSupply) external returns (uint256 tokenId);
                        function updateTokenURI(uint256 tokenId, string memory _newURI) external;
                        function updateContractMetadata(string memory _newURI, string memory _newName) external;
                        // Public interface for `setTokenMetadataRenderer(uint256, address) has been deprecated.
                        function contractURI() external view returns (string memory);
                        function assumeLastTokenIdMatches(uint256 tokenId) external;
                        function updateRoyaltiesForToken(uint256 tokenId, ICreatorRoyaltiesControl.RoyaltyConfiguration memory royaltyConfiguration) external;
                        function addPermission(uint256 tokenId, address user, uint256 permissionBits) external;
                        function removePermission(uint256 tokenId, address user, uint256 permissionBits) external;
                        function isAdminOrRole(address user, uint256 tokenId, uint256 role) external view returns (bool);
                        function getTokenInfo(uint256 tokenId) external view returns (TokenData memory);
                        function callRenderer(uint256 tokenId, bytes memory data) external;
                        function callSale(uint256 tokenId, IMinter1155 salesConfig, bytes memory data) external;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IERC2981} from "@openzeppelin/contracts/interfaces/IERC2981.sol";
                    interface ICreatorRoyaltiesControl is IERC2981 {
                        /// @notice The RoyaltyConfiguration struct is used to store the royalty configuration for a given token.
                        /// @param royaltyMintSchedule Every nth token will go to the royalty recipient.
                        /// @param royaltyBPS The royalty amount in basis points for secondary sales.
                        /// @param royaltyRecipient The address that will receive the royalty payments.
                        struct RoyaltyConfiguration {
                            uint32 royaltyMintSchedule;
                            uint32 royaltyBPS;
                            address royaltyRecipient;
                        }
                        /// @notice Thrown when a user tries to have 100% supply royalties
                        error InvalidMintSchedule();
                        /// @notice Event emitted when royalties are updated
                        event UpdatedRoyalties(uint256 indexed tokenId, address indexed user, RoyaltyConfiguration configuration);
                        /// @notice External data getter to get royalties for a token
                        /// @param tokenId tokenId to get royalties configuration for
                        function getRoyalties(uint256 tokenId) external view returns (RoyaltyConfiguration memory);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IERC165Upgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC165Upgradeable.sol";
                    import {ICreatorCommands} from "./ICreatorCommands.sol";
                    /// @notice Minter standard interface
                    /// @dev Minters need to confirm to the ERC165 selector of type(IMinter1155).interfaceId
                    interface IMinter1155 is IERC165Upgradeable {
                        function requestMint(
                            address sender,
                            uint256 tokenId,
                            uint256 quantity,
                            uint256 ethValueSent,
                            bytes calldata minterArguments
                        ) external returns (ICreatorCommands.CommandSet memory commands);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    interface IContractMetadata {
                        /// @notice Contract name returns the pretty contract name
                        function contractName() external returns (string memory);
                        /// @notice Contract URI returns the uri for more information about the given contract
                        function contractURI() external returns (string memory);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IOwnable2StepUpgradeable} from "./IOwnable2StepUpgradeable.sol";
                    import {IOwnable2StepStorageV1} from "./IOwnable2StepStorageV1.sol";
                    import {Initializable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
                    /// @title Ownable
                    /// @author Rohan Kulkarni / Iain Nash
                    /// @notice Modified from OpenZeppelin Contracts v4.7.3 (access/OwnableUpgradeable.sol)
                    /// - Uses custom errors declared in IOwnable
                    /// - Adds optional two-step ownership transfer (`safeTransferOwnership` + `acceptOwnership`)
                    abstract contract Ownable2StepUpgradeable is IOwnable2StepUpgradeable, IOwnable2StepStorageV1, Initializable {
                        ///                                                          ///
                        ///                            STORAGE                       ///
                        ///                                                          ///
                        /// @dev Modifier to check if the address argument is the zero/burn address
                        modifier notZeroAddress(address check) {
                            if (check == address(0)) {
                                revert OWNER_CANNOT_BE_ZERO_ADDRESS();
                            }
                            _;
                        }
                        ///                                                          ///
                        ///                           MODIFIERS                      ///
                        ///                                                          ///
                        /// @dev Ensures the caller is the owner
                        modifier onlyOwner() {
                            if (msg.sender != _owner) {
                                revert ONLY_OWNER();
                            }
                            _;
                        }
                        /// @dev Ensures the caller is the pending owner
                        modifier onlyPendingOwner() {
                            if (msg.sender != _pendingOwner) {
                                revert ONLY_PENDING_OWNER();
                            }
                            _;
                        }
                        ///                                                          ///
                        ///                           FUNCTIONS                      ///
                        ///                                                          ///
                        /// @dev Initializes contract ownership
                        /// @param _initialOwner The initial owner address
                        function __Ownable_init(address _initialOwner) internal notZeroAddress(_initialOwner) onlyInitializing {
                            _owner = _initialOwner;
                            emit OwnerUpdated(address(0), _initialOwner);
                        }
                        /// @notice The address of the owner
                        function owner() public view virtual returns (address) {
                            return _owner;
                        }
                        /// @notice The address of the pending owner
                        function pendingOwner() public view returns (address) {
                            return _pendingOwner;
                        }
                        /// @notice Forces an ownership transfer from the last owner
                        /// @param _newOwner The new owner address
                        function transferOwnership(address _newOwner) public notZeroAddress(_newOwner) onlyOwner {
                            _transferOwnership(_newOwner);
                        }
                        /// @notice Forces an ownership transfer from any sender
                        /// @param _newOwner New owner to transfer contract to
                        /// @dev Ensure is called only from trusted internal code, no access control checks.
                        function _transferOwnership(address _newOwner) internal {
                            emit OwnerUpdated(_owner, _newOwner);
                            _owner = _newOwner;
                            if (_pendingOwner != address(0)) {
                                delete _pendingOwner;
                            }
                        }
                        /// @notice Initiates a two-step ownership transfer
                        /// @param _newOwner The new owner address
                        function safeTransferOwnership(address _newOwner) public notZeroAddress(_newOwner) onlyOwner {
                            _pendingOwner = _newOwner;
                            emit OwnerPending(_owner, _newOwner);
                        }
                        /// @notice Resign ownership of contract
                        /// @dev only callably by the owner, dangerous call.
                        function resignOwnership() public onlyOwner {
                            _transferOwnership(address(0));
                        }
                        /// @notice Accepts an ownership transfer
                        function acceptOwnership() public onlyPendingOwner {
                            emit OwnerUpdated(_owner, msg.sender);
                            _transferOwnership(msg.sender);
                        }
                        /// @notice Cancels a pending ownership transfer
                        function cancelOwnershipTransfer() public onlyOwner {
                            emit OwnerCanceled(_owner, _pendingOwner);
                            delete _pendingOwner;
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IFactoryManagedUpgradeGate} from "../interfaces/IFactoryManagedUpgradeGate.sol";
                    import {Ownable2StepUpgradeable} from "../utils/ownable/Ownable2StepUpgradeable.sol";
                    import {FactoryManagedUpgradeGateStorageV1} from "./FactoryManagedUpgradeGateStorageV1.sol";
                    /// @title FactoryManagedUpgradeGate
                    /// @notice Contract for managing upgrades and safe upgrade paths for 1155 contracts
                    abstract contract FactoryManagedUpgradeGate is IFactoryManagedUpgradeGate, Ownable2StepUpgradeable, FactoryManagedUpgradeGateStorageV1 {
                        ///                                                          ///
                        ///                CREATOR TOKEN UPGRADES                    ///
                        ///                                                          ///
                        /// @notice If an implementation is registered by the Builder DAO as an optional upgrade
                        /// @param baseImpl The base implementation address
                        /// @param upgradeImpl The upgrade implementation address
                        function isRegisteredUpgradePath(address baseImpl, address upgradeImpl) public view returns (bool) {
                            return isAllowedUpgrade[baseImpl][upgradeImpl];
                        }
                        /// @notice Called by the Builder DAO to offer implementation upgrades for created DAOs
                        /// @param baseImpls The base implementation addresses
                        /// @param upgradeImpl The upgrade implementation address
                        function registerUpgradePath(address[] memory baseImpls, address upgradeImpl) public onlyOwner {
                            unchecked {
                                for (uint256 i = 0; i < baseImpls.length; ++i) {
                                    isAllowedUpgrade[baseImpls[i]][upgradeImpl] = true;
                                    emit UpgradeRegistered(baseImpls[i], upgradeImpl);
                                }
                            }
                        }
                        /// @notice Called by the Builder DAO to remove an upgrade
                        /// @param baseImpl The base implementation address
                        /// @param upgradeImpl The upgrade implementation address
                        function removeUpgradePath(address baseImpl, address upgradeImpl) public onlyOwner {
                            delete isAllowedUpgrade[baseImpl][upgradeImpl];
                            emit UpgradeRemoved(baseImpl, upgradeImpl);
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {Enjoy} from "_imagine/mint/Enjoy.sol";
                    import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
                    /*
                                 ░░░░░░░░░░░░░░              
                            ░░▒▒░░░░░░░░░░░░░░░░░░░░        
                          ░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░      
                        ░░▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░    
                       ░▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░    
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░░  
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░░░  
                      ░▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░  
                      ░▓▓▓▓▓▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░  
                       ░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░  
                        ░░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░    
                        ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▒░░    
                          ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░      
                              ░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░          
                                   OURS TRULY,
                     */
                    /// Imagine. Mint. Enjoy.
                    /// @notice Imagine. Mint. Enjoy.
                    /// @author ZORA @iainnash / @tbtstl
                    contract Zora1155 is Enjoy, ERC1967Proxy {
                        constructor(address _logic) ERC1967Proxy(_logic, "") {}
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IVersionedContract} from "../interfaces/IVersionedContract.sol";
                    /// @title ContractVersionBase
                    /// @notice Base contract for versioning contracts
                    contract ContractVersionBase is IVersionedContract {
                        /// @notice The version of the contract
                        function contractVersion() external pure override returns (string memory) {
                            return "1.4.0";
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
                    pragma solidity ^0.8.1;
                    error ADDRESS_INSUFFICIENT_BALANCE();
                    error ADDRESS_UNABLE_TO_SEND_VALUE();
                    error ADDRESS_LOW_LEVEL_CALL_FAILED();
                    error ADDRESS_LOW_LEVEL_CALL_WITH_VALUE_FAILED();
                    error ADDRESS_INSUFFICIENT_BALANCE_FOR_CALL();
                    error ADDRESS_LOW_LEVEL_STATIC_CALL_FAILED();
                    error ADDRESS_CALL_TO_NON_CONTRACT();
                    /**
                     * @dev Collection of functions related to the address type
                     */
                    library AddressUpgradeable {
                        /**
                         * @dev Returns true if `account` is a contract.
                         *
                         * [IMPORTANT]
                         * ====
                         * It is unsafe to assume that an address for which this function returns
                         * false is an externally-owned account (EOA) and not a contract.
                         *
                         * Among others, `isContract` will return false for the following
                         * types of addresses:
                         *
                         *  - an externally-owned account
                         *  - a contract in construction
                         *  - an address where a contract will be created
                         *  - an address where a contract lived, but was destroyed
                         *
                         * Furthermore, `isContract` will also return true if the target contract within
                         * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                         * which only has an effect at the end of a transaction.
                         * ====
                         *
                         * [IMPORTANT]
                         * ====
                         * You shouldn't rely on `isContract` to protect against flash loan attacks!
                         *
                         * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                         * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                         * constructor.
                         * ====
                         */
                        function isContract(address account) internal view returns (bool) {
                            // This method relies on extcodesize/address.code.length, which returns 0
                            // for contracts in construction, since the code is only stored at the end
                            // of the constructor execution.
                            return account.code.length > 0;
                        }
                        /**
                         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                         * `recipient`, forwarding all available gas and reverting on errors.
                         *
                         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                         * of certain opcodes, possibly making contracts go over the 2300 gas limit
                         * imposed by `transfer`, making them unable to receive funds via
                         * `transfer`. {sendValue} removes this limitation.
                         *
                         * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                         *
                         * IMPORTANT: because control is transferred to `recipient`, care must be
                         * taken to not create reentrancy vulnerabilities. Consider using
                         * {ReentrancyGuard} or the
                         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                         */
                        function sendValue(address payable recipient, uint256 amount) internal {
                            if (address(this).balance > amount) {
                                revert ADDRESS_INSUFFICIENT_BALANCE();
                            }
                            (bool success, ) = recipient.call{value: amount}("");
                            if (!success) {
                                revert ADDRESS_UNABLE_TO_SEND_VALUE();
                            }
                        }
                        /**
                         * @dev Performs a Solidity function call using a low level `call`. A
                         * plain `call` is an unsafe replacement for a function call: use this
                         * function instead.
                         *
                         * If `target` reverts with a revert reason, it is bubbled up by this
                         * function (like regular Solidity function calls).
                         *
                         * Returns the raw returned data. To convert to the expected return value,
                         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                         *
                         * Requirements:
                         *
                         * - `target` must be a contract.
                         * - calling `target` with `data` must not revert.
                         *
                         * _Available since v3.1._
                         */
                        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                            return functionCallWithValue(target, data, 0);
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                         * but also transferring `value` wei to `target`.
                         *
                         * Requirements:
                         *
                         * - the calling contract must have an ETH balance of at least `value`.
                         * - the called Solidity function must be `payable`.
                         *
                         * _Available since v3.1._
                         */
                        function functionCallWithValue(
                            address target,
                            bytes memory data,
                            uint256 value
                        ) internal returns (bytes memory) {
                            if (address(this).balance < value) {
                                revert ADDRESS_INSUFFICIENT_BALANCE();
                            }
                            (bool success, bytes memory returndata) = target.call{value: value}(data);
                            return verifyCallResultFromTarget(target, success, returndata);
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                         * but performing a static call.
                         *
                         * _Available since v3.3._
                         */
                        function functionStaticCall(
                            address target,
                            bytes memory data
                        ) internal view returns (bytes memory) {
                            (bool success, bytes memory returndata) = target.staticcall(data);
                            return verifyCallResultFromTarget(target, success, returndata);
                        }
                        /**
                         * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                         * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                         *
                         * _Available since v4.8._
                         */
                        function verifyCallResultFromTarget(
                            address target,
                            bool success,
                            bytes memory returndata
                        ) internal view returns (bytes memory) {
                            if (success) {
                                if (returndata.length == 0) {
                                    // only check isContract if the call was successful and the return data is empty
                                    // otherwise we already know that it was a contract
                                    if (!isContract(target)) {
                                        revert ADDRESS_CALL_TO_NON_CONTRACT();
                                    }
                                }
                                return returndata;
                            } else {
                                _revert(returndata);
                            }
                        }
                        /**
                         * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                         * revert reason or using the provided one.
                         *
                         * _Available since v4.3._
                         */
                        function verifyCallResult(
                            bool success,
                            bytes memory returndata
                        ) internal pure returns (bytes memory) {
                            if (success) {
                                return returndata;
                            } else {
                                _revert(returndata);
                            }
                        }
                        function _revert(bytes memory returndata) private pure {
                            // Look for revert reason and bubble it up if present
                            if (returndata.length > 0) {
                                // The easiest way to bubble the revert reason is using memory via assembly
                                /// @solidity memory-safe-assembly
                                assembly {
                                    let returndata_size := mload(returndata)
                                    revert(add(32, returndata), returndata_size)
                                }
                            } else {
                                revert ADDRESS_LOW_LEVEL_CALL_FAILED();
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
                    pragma solidity ^0.8.0;
                    /**
                     * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
                     * proxy whose upgrades are fully controlled by the current implementation.
                     */
                    interface IERC1822ProxiableUpgradeable {
                        /**
                         * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
                         * address.
                         *
                         * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                         * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                         * function revert if invoked through a proxy.
                         */
                        function proxiableUUID() external view returns (bytes32);
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
                    pragma solidity ^0.8.2;
                    import "../beacon/IBeaconUpgradeable.sol";
                    import "../../interfaces/draft-IERC1822Upgradeable.sol";
                    import "../../utils/AddressUpgradeable.sol";
                    import "../../utils/StorageSlotUpgradeable.sol";
                    import "../utils/Initializable.sol";
                    error ERC1967_NEW_IMPL_NOT_CONTRACT();
                    error ERC1967_UNSUPPORTED_PROXIABLEUUID();
                    error ERC1967_NEW_IMPL_NOT_UUPS();
                    error ERC1967_NEW_ADMIN_IS_ZERO_ADDRESS();
                    error ERC1967_NEW_BEACON_IS_NOT_CONTRACT();
                    error ERC1967_BEACON_IMPL_IS_NOT_CONTRACT();
                    error ADDRESS_DELEGATECALL_TO_NON_CONTRACT();
                    /**
                     * @dev This abstract contract provides getters and event emitting update functions for
                     * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                     *
                     * _Available since v4.1._
                     */
                    abstract contract ERC1967UpgradeUpgradeable is Initializable {
                        function __ERC1967Upgrade_init() internal onlyInitializing {
                        }
                        function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
                        }
                        // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                        bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                        /**
                         * @dev Storage slot with the address of the current implementation.
                         * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                         * validated in the constructor.
                         */
                        bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                        /**
                         * @dev Emitted when the implementation is upgraded.
                         */
                        event Upgraded(address indexed implementation);
                        /**
                         * @dev Returns the current implementation address.
                         */
                        function _getImplementation() internal view returns (address) {
                            return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                        }
                        /**
                         * @dev Stores a new address in the EIP1967 implementation slot.
                         */
                        function _setImplementation(address newImplementation) private {
                            if (!AddressUpgradeable.isContract(newImplementation)) {
                                revert ERC1967_NEW_IMPL_NOT_CONTRACT();
                            } 
                            StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                        }
                        /**
                         * @dev Perform implementation upgrade
                         *
                         * Emits an {Upgraded} event.
                         */
                        function _upgradeTo(address newImplementation) internal {
                            _setImplementation(newImplementation);
                            emit Upgraded(newImplementation);
                        }
                        /**
                         * @dev Perform implementation upgrade with additional setup call.
                         *
                         * Emits an {Upgraded} event.
                         */
                        function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                            _upgradeTo(newImplementation);
                            if (data.length > 0 || forceCall) {
                                _functionDelegateCall(newImplementation, data);
                            }
                        }
                        /**
                         * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                         *
                         * Emits an {Upgraded} event.
                         */
                        function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
                            // Upgrades from old implementations will perform a rollback test. This test requires the new
                            // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
                            // this special case will break upgrade paths from old UUPS implementation to new ones.
                            if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
                                _setImplementation(newImplementation);
                            } else {
                                try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                                    if (slot != _IMPLEMENTATION_SLOT) {
                                        revert ERC1967_UNSUPPORTED_PROXIABLEUUID();
                                    }
                                } catch {
                                    revert ERC1967_NEW_IMPL_NOT_UUPS();
                                }
                                _upgradeToAndCall(newImplementation, data, forceCall);
                            }
                        }
                        /**
                         * @dev Storage slot with the admin of the contract.
                         * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                         * validated in the constructor.
                         */
                        bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                        /**
                         * @dev Emitted when the admin account has changed.
                         */
                        event AdminChanged(address previousAdmin, address newAdmin);
                        /**
                         * @dev Returns the current admin.
                         */
                        function _getAdmin() internal view returns (address) {
                            return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
                        }
                        /**
                         * @dev Stores a new address in the EIP1967 admin slot.
                         */
                        function _setAdmin(address newAdmin) private {
                            if (newAdmin == address(0)) {
                                revert ERC1967_NEW_ADMIN_IS_ZERO_ADDRESS();
                            }
                            StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                        }
                        /**
                         * @dev Changes the admin of the proxy.
                         *
                         * Emits an {AdminChanged} event.
                         */
                        function _changeAdmin(address newAdmin) internal {
                            emit AdminChanged(_getAdmin(), newAdmin);
                            _setAdmin(newAdmin);
                        }
                        /**
                         * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                         * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                         */
                        bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                        /**
                         * @dev Emitted when the beacon is upgraded.
                         */
                        event BeaconUpgraded(address indexed beacon);
                        /**
                         * @dev Returns the current beacon.
                         */
                        function _getBeacon() internal view returns (address) {
                            return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
                        }
                        /**
                         * @dev Stores a new beacon in the EIP1967 beacon slot.
                         */
                        function _setBeacon(address newBeacon) private {
                            if (!AddressUpgradeable.isContract(newBeacon)) {
                                revert ERC1967_NEW_BEACON_IS_NOT_CONTRACT();
                            }
                            if (!AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation())) {
                                revert ERC1967_BEACON_IMPL_IS_NOT_CONTRACT();
                            }
                            StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                        }
                        /**
                         * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                         * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                         *
                         * Emits a {BeaconUpgraded} event.
                         */
                        function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                            _setBeacon(newBeacon);
                            emit BeaconUpgraded(newBeacon);
                            if (data.length > 0 || forceCall) {
                                _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
                            }
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                         * but performing a delegate call.
                         *
                         * _Available since v3.4._
                         */
                        function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {
                            if (!AddressUpgradeable.isContract(target)) {
                                revert ADDRESS_DELEGATECALL_TO_NON_CONTRACT();
                            }
                            // solhint-disable-next-line avoid-low-level-calls
                            (bool success, bytes memory returndata) = target.delegatecall(data);
                            return AddressUpgradeable.verifyCallResult(success, returndata);
                        }
                        /**
                         * @dev This empty reserved space is put in place to allow future versions to add new
                         * variables without shifting down storage in the inheritance chain.
                         * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                         */
                        uint256[50] private __gap;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    interface IVersionedContract {
                        function contractVersion() external returns (string memory);
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)
                    pragma solidity ^0.8.0;
                    import "../utils/introspection/IERC165Upgradeable.sol";
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155MetadataURI.sol)
                    pragma solidity ^0.8.0;
                    import "../token/ERC1155/extensions/IERC1155MetadataURIUpgradeable.sol";
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {ITransferHookReceiver} from "../interfaces/ITransferHookReceiver.sol";
                    /*
                                 ░░░░░░░░░░░░░░              
                            ░░▒▒░░░░░░░░░░░░░░░░░░░░        
                          ░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░      
                        ░░▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░    
                       ░▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░    
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░░  
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░░░  
                      ░▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░  
                      ░▓▓▓▓▓▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░  
                       ░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░  
                        ░░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░    
                        ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▒░░    
                          ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░      
                              ░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░          
                                   OURS TRULY,
                     */
                    /// Imagine. Mint. Enjoy.
                    /// @notice Interface for types used across the ZoraCreator1155 contract
                    /// @author @iainnash / @tbtstl
                    interface IZoraCreator1155TypesV1 {
                        /// @notice Used to store individual token data
                        struct TokenData {
                            string uri;
                            uint256 maxSupply;
                            uint256 totalMinted;
                        }
                        /// @notice Used to store contract-level configuration
                        struct ContractConfig {
                            address owner;
                            uint96 __gap1;
                            address payable fundsRecipient;
                            uint96 __gap2;
                            ITransferHookReceiver transferHook;
                            uint96 __gap3;
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IERC165Upgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC165Upgradeable.sol";
                    /// @dev IERC165 type required
                    interface IRenderer1155 is IERC165Upgradeable {
                        /// @notice Called for assigned tokenId, or when token id is globally set to a renderer
                        /// @dev contract target is assumed to be msg.sender
                        /// @param tokenId token id to get uri for
                        function uri(uint256 tokenId) external view returns (string memory);
                        /// @notice Only called for tokenId == 0
                        /// @dev contract target is assumed to be msg.sender
                        function contractURI() external view returns (string memory);
                        /// @notice Sets up renderer from contract
                        /// @param initData data to setup renderer with
                        /// @dev contract target is assumed to be msg.sender
                        function setup(bytes memory initData) external;
                        // IERC165 type required – set in base helper
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    interface IOwnable {
                        function owner() external returns (address);
                        event OwnershipTransferred(address lastOwner, address newOwner);
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.9.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
                    pragma solidity 0.8.17;
                    /// @notice Creator Commands used by minter modules passed back to the main modules
                    interface ICreatorCommands {
                        /// @notice This enum is used to define supported creator action types.
                        /// This can change in the future
                        enum CreatorActions {
                            // No operation - also the default for mintings that may not return a command
                            NO_OP,
                            // Send ether
                            SEND_ETH,
                            // Mint operation
                            MINT
                        }
                        /// @notice This command is for
                        struct Command {
                            // Method for operation
                            CreatorActions method;
                            // Arguments used for this operation
                            bytes args;
                        }
                        /// @notice This command set is returned from the minter back to the user
                        struct CommandSet {
                            Command[] commands;
                            uint256 at;
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    /// @title IOwnable2StepUpgradeable
                    /// @author Rohan Kulkarni
                    /// @notice The external Ownable events, errors, and functions
                    interface IOwnable2StepUpgradeable {
                        ///                                                          ///
                        ///                            EVENTS                        ///
                        ///                                                          ///
                        /// @notice Emitted when ownership has been updated
                        /// @param prevOwner The previous owner address
                        /// @param newOwner The new owner address
                        event OwnerUpdated(address indexed prevOwner, address indexed newOwner);
                        /// @notice Emitted when an ownership transfer is pending
                        /// @param owner The current owner address
                        /// @param pendingOwner The pending new owner address
                        event OwnerPending(address indexed owner, address indexed pendingOwner);
                        /// @notice Emitted when a pending ownership transfer has been canceled
                        /// @param owner The current owner address
                        /// @param canceledOwner The canceled owner address
                        event OwnerCanceled(address indexed owner, address indexed canceledOwner);
                        ///                                                          ///
                        ///                            ERRORS                        ///
                        ///                                                          ///
                        /// @dev Reverts if an unauthorized user calls an owner function
                        error ONLY_OWNER();
                        /// @dev Reverts if an unauthorized user calls a pending owner function
                        error ONLY_PENDING_OWNER();
                        /// @dev Owner cannot be the zero/burn address
                        error OWNER_CANNOT_BE_ZERO_ADDRESS();
                        ///                                                          ///
                        ///                           FUNCTIONS                      ///
                        ///                                                          ///
                        /// @notice The address of the owner
                        function owner() external view returns (address);
                        /// @notice The address of the pending owner
                        function pendingOwner() external view returns (address);
                        /// @notice Forces an ownership transfer
                        /// @param newOwner The new owner address
                        function transferOwnership(address newOwner) external;
                        /// @notice Initiates a two-step ownership transfer
                        /// @param newOwner The new owner address
                        function safeTransferOwnership(address newOwner) external;
                        /// @notice Accepts an ownership transfer
                        function acceptOwnership() external;
                        /// @notice Cancels a pending ownership transfer
                        function cancelOwnershipTransfer() external;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    abstract contract IOwnable2StepStorageV1 {
                        /// @dev The address of the owner
                        address internal _owner;
                        /// @dev The address of the pending owner
                        address internal _pendingOwner;
                        /// @dev storage gap
                        uint256[50] private __gap;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    /// @notice Factory Upgrade Gate Admin Factory Implementation – Allows specific contract upgrades as a safety measure
                    interface IFactoryManagedUpgradeGate {
                        /// @notice If an implementation is registered by the Builder DAO as an optional upgrade
                        /// @param baseImpl The base implementation address
                        /// @param upgradeImpl The upgrade implementation address
                        function isRegisteredUpgradePath(address baseImpl, address upgradeImpl) external view returns (bool);
                        /// @notice Called by the Builder DAO to offer implementation upgrades for created DAOs
                        /// @param baseImpls The base implementation addresses
                        /// @param upgradeImpl The upgrade implementation address
                        function registerUpgradePath(address[] memory baseImpls, address upgradeImpl) external;
                        /// @notice Called by the Builder DAO to remove an upgrade
                        /// @param baseImpl The base implementation address
                        /// @param upgradeImpl The upgrade implementation address
                        function removeUpgradePath(address baseImpl, address upgradeImpl) external;
                        event UpgradeRegistered(address indexed baseImpl, address indexed upgradeImpl);
                        event UpgradeRemoved(address indexed baseImpl, address indexed upgradeImpl);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    abstract contract FactoryManagedUpgradeGateStorageV1 {
                        mapping(address => mapping(address => bool)) public isAllowedUpgrade;
                        uint256[50] private __gap;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    /*
                                 ░░░░░░░░░░░░░░              
                            ░░▒▒░░░░░░░░░░░░░░░░░░░░        
                          ░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░      
                        ░░▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░    
                       ░▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░    
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░░  
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░░░  
                      ░▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░  
                      ░▓▓▓▓▓▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░  
                       ░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░  
                        ░░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░    
                        ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▒░░    
                          ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░      
                              ░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░          
                                   OURS TRULY,
                     */
                    interface Enjoy {
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)
                    pragma solidity ^0.8.0;
                    import "../Proxy.sol";
                    import "./ERC1967Upgrade.sol";
                    /**
                     * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
                     * implementation address that can be changed. This address is stored in storage in the location specified by
                     * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
                     * implementation behind the proxy.
                     */
                    contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                        /**
                         * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                         *
                         * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                         * function call, and allows initializing the storage of the proxy like a Solidity constructor.
                         */
                        constructor(address _logic, bytes memory _data) payable {
                            _upgradeToAndCall(_logic, _data, false);
                        }
                        /**
                         * @dev Returns the current implementation address.
                         */
                        function _implementation() internal view virtual override returns (address impl) {
                            return ERC1967Upgrade._getImplementation();
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
                    pragma solidity ^0.8.0;
                    /**
                     * @dev This is the interface that {BeaconProxy} expects of its beacon.
                     */
                    interface IBeaconUpgradeable {
                        /**
                         * @dev Must return an address that can be used as a delegate call target.
                         *
                         * {BeaconProxy} will check that this address is a contract.
                         */
                        function implementation() external view returns (address);
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)
                    // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
                    pragma solidity ^0.8.0;
                    /**
                     * @dev Library for reading and writing primitive types to specific storage slots.
                     *
                     * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                     * This library helps with reading and writing to such slots without the need for inline assembly.
                     *
                     * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                     *
                     * Example usage to set ERC1967 implementation slot:
                     * ```solidity
                     * contract ERC1967 {
                     *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                     *
                     *     function _getImplementation() internal view returns (address) {
                     *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                     *     }
                     *
                     *     function _setImplementation(address newImplementation) internal {
                     *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                     *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                     *     }
                     * }
                     * ```
                     *
                     * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
                     * _Available since v4.9 for `string`, `bytes`._
                     */
                    library StorageSlotUpgradeable {
                        struct AddressSlot {
                            address value;
                        }
                        struct BooleanSlot {
                            bool value;
                        }
                        struct Bytes32Slot {
                            bytes32 value;
                        }
                        struct Uint256Slot {
                            uint256 value;
                        }
                        struct StringSlot {
                            string value;
                        }
                        struct BytesSlot {
                            bytes value;
                        }
                        /**
                         * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                         */
                        function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                         */
                        function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                         */
                        function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                         */
                        function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `StringSlot` with member `value` located at `slot`.
                         */
                        function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                         */
                        function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := store.slot
                            }
                        }
                        /**
                         * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                         */
                        function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                         */
                        function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := store.slot
                            }
                        }
                    }
                    // 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 IERC165Upgradeable {
                        /**
                         * @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
                    // OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)
                    pragma solidity ^0.8.0;
                    import "../IERC1155Upgradeable.sol";
                    /**
                     * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
                     * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
                     *
                     * _Available since v3.1._
                     */
                    interface IERC1155MetadataURIUpgradeable is IERC1155Upgradeable {
                        /**
                         * @dev Returns the URI for token type `id`.
                         *
                         * If the `\\{id\\}` substring is present in the URI, it must be replaced by
                         * clients with the actual token type ID.
                         */
                        function uri(uint256 id) external view returns (string memory);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IERC165Upgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC165Upgradeable.sol";
                    interface ITransferHookReceiver is IERC165Upgradeable {
                        /// @notice Token transfer batch callback
                        /// @param target target contract for transfer
                        /// @param operator operator address for transfer
                        /// @param from user address for amount transferred
                        /// @param to user address for amount transferred
                        /// @param ids list of token ids transferred
                        /// @param amounts list of values transferred
                        /// @param data data as perscribed by 1155 standard
                        function onTokenTransferBatch(
                            address target,
                            address operator,
                            address from,
                            address to,
                            uint256[] memory ids,
                            uint256[] memory amounts,
                            bytes memory data
                        ) external;
                        // IERC165 type required
                    }
                    // 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
                    // OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
                    pragma solidity ^0.8.0;
                    /**
                     * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
                     * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
                     * be specified by overriding the virtual {_implementation} function.
                     *
                     * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
                     * different contract through the {_delegate} function.
                     *
                     * The success and return data of the delegated call will be returned back to the caller of the proxy.
                     */
                    abstract contract Proxy {
                        /**
                         * @dev Delegates the current call to `implementation`.
                         *
                         * This function does not return to its internal call site, it will return directly to the external caller.
                         */
                        function _delegate(address implementation) internal virtual {
                            assembly {
                                // Copy msg.data. We take full control of memory in this inline assembly
                                // block because it will not return to Solidity code. We overwrite the
                                // Solidity scratch pad at memory position 0.
                                calldatacopy(0, 0, calldatasize())
                                // Call the implementation.
                                // out and outsize are 0 because we don't know the size yet.
                                let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                                // Copy the returned data.
                                returndatacopy(0, 0, returndatasize())
                                switch result
                                // delegatecall returns 0 on error.
                                case 0 {
                                    revert(0, returndatasize())
                                }
                                default {
                                    return(0, returndatasize())
                                }
                            }
                        }
                        /**
                         * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
                         * and {_fallback} should delegate.
                         */
                        function _implementation() internal view virtual returns (address);
                        /**
                         * @dev Delegates the current call to the address returned by `_implementation()`.
                         *
                         * This function does not return to its internal call site, it will return directly to the external caller.
                         */
                        function _fallback() internal virtual {
                            _beforeFallback();
                            _delegate(_implementation());
                        }
                        /**
                         * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                         * function in the contract matches the call data.
                         */
                        fallback() external payable virtual {
                            _fallback();
                        }
                        /**
                         * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                         * is empty.
                         */
                        receive() external payable virtual {
                            _fallback();
                        }
                        /**
                         * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                         * call, or as part of the Solidity `fallback` or `receive` functions.
                         *
                         * If overridden should call `super._beforeFallback()`.
                         */
                        function _beforeFallback() internal virtual {}
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
                    pragma solidity ^0.8.2;
                    import "../beacon/IBeacon.sol";
                    import "../../interfaces/IERC1967.sol";
                    import "../../interfaces/draft-IERC1822.sol";
                    import "../../utils/Address.sol";
                    import "../../utils/StorageSlot.sol";
                    /**
                     * @dev This abstract contract provides getters and event emitting update functions for
                     * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                     *
                     * _Available since v4.1._
                     */
                    abstract contract ERC1967Upgrade is IERC1967 {
                        // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                        bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                        /**
                         * @dev Storage slot with the address of the current implementation.
                         * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                         * validated in the constructor.
                         */
                        bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                        /**
                         * @dev Returns the current implementation address.
                         */
                        function _getImplementation() internal view returns (address) {
                            return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                        }
                        /**
                         * @dev Stores a new address in the EIP1967 implementation slot.
                         */
                        function _setImplementation(address newImplementation) private {
                            require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                            StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                        }
                        /**
                         * @dev Perform implementation upgrade
                         *
                         * Emits an {Upgraded} event.
                         */
                        function _upgradeTo(address newImplementation) internal {
                            _setImplementation(newImplementation);
                            emit Upgraded(newImplementation);
                        }
                        /**
                         * @dev Perform implementation upgrade with additional setup call.
                         *
                         * Emits an {Upgraded} event.
                         */
                        function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                            _upgradeTo(newImplementation);
                            if (data.length > 0 || forceCall) {
                                Address.functionDelegateCall(newImplementation, data);
                            }
                        }
                        /**
                         * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                         *
                         * Emits an {Upgraded} event.
                         */
                        function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
                            // Upgrades from old implementations will perform a rollback test. This test requires the new
                            // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
                            // this special case will break upgrade paths from old UUPS implementation to new ones.
                            if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
                                _setImplementation(newImplementation);
                            } else {
                                try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                                    require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
                                } catch {
                                    revert("ERC1967Upgrade: new implementation is not UUPS");
                                }
                                _upgradeToAndCall(newImplementation, data, forceCall);
                            }
                        }
                        /**
                         * @dev Storage slot with the admin of the contract.
                         * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                         * validated in the constructor.
                         */
                        bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                        /**
                         * @dev Returns the current admin.
                         */
                        function _getAdmin() internal view returns (address) {
                            return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                        }
                        /**
                         * @dev Stores a new address in the EIP1967 admin slot.
                         */
                        function _setAdmin(address newAdmin) private {
                            require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                            StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                        }
                        /**
                         * @dev Changes the admin of the proxy.
                         *
                         * Emits an {AdminChanged} event.
                         */
                        function _changeAdmin(address newAdmin) internal {
                            emit AdminChanged(_getAdmin(), newAdmin);
                            _setAdmin(newAdmin);
                        }
                        /**
                         * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                         * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                         */
                        bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                        /**
                         * @dev Returns the current beacon.
                         */
                        function _getBeacon() internal view returns (address) {
                            return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                        }
                        /**
                         * @dev Stores a new beacon in the EIP1967 beacon slot.
                         */
                        function _setBeacon(address newBeacon) private {
                            require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
                            require(
                                Address.isContract(IBeacon(newBeacon).implementation()),
                                "ERC1967: beacon implementation is not a contract"
                            );
                            StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                        }
                        /**
                         * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                         * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                         *
                         * Emits a {BeaconUpgraded} event.
                         */
                        function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                            _setBeacon(newBeacon);
                            emit BeaconUpgraded(newBeacon);
                            if (data.length > 0 || forceCall) {
                                Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)
                    pragma solidity ^0.8.0;
                    import "../../utils/introspection/IERC165Upgradeable.sol";
                    /**
                     * @dev Required interface of an ERC1155 compliant contract, as defined in the
                     * https://eips.ethereum.org/EIPS/eip-1155[EIP].
                     *
                     * _Available since v3.1._
                     */
                    interface IERC1155Upgradeable is IERC165Upgradeable {
                        /**
                         * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
                         */
                        event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
                        /**
                         * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
                         * transfers.
                         */
                        event TransferBatch(
                            address indexed operator,
                            address indexed from,
                            address indexed to,
                            uint256[] ids,
                            uint256[] values
                        );
                        /**
                         * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
                         * `approved`.
                         */
                        event ApprovalForAll(address indexed account, address indexed operator, bool approved);
                        /**
                         * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
                         *
                         * If an {URI} event was emitted for `id`, the standard
                         * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
                         * returned by {IERC1155MetadataURI-uri}.
                         */
                        event URI(string value, uint256 indexed id);
                        /**
                         * @dev Returns the amount of tokens of token type `id` owned by `account`.
                         *
                         * Requirements:
                         *
                         * - `account` cannot be the zero address.
                         */
                        function balanceOf(address account, uint256 id) external view returns (uint256);
                        /**
                         * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
                         *
                         * Requirements:
                         *
                         * - `accounts` and `ids` must have the same length.
                         */
                        function balanceOfBatch(
                            address[] calldata accounts,
                            uint256[] calldata ids
                        ) external view returns (uint256[] memory);
                        /**
                         * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
                         *
                         * Emits an {ApprovalForAll} event.
                         *
                         * Requirements:
                         *
                         * - `operator` cannot be the caller.
                         */
                        function setApprovalForAll(address operator, bool approved) external;
                        /**
                         * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
                         *
                         * See {setApprovalForAll}.
                         */
                        function isApprovedForAll(address account, address operator) external view returns (bool);
                        /**
                         * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
                         *
                         * Emits a {TransferSingle} event.
                         *
                         * Requirements:
                         *
                         * - `to` cannot be the zero address.
                         * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
                         * - `from` must have a balance of tokens of type `id` of at least `amount`.
                         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
                         * acceptance magic value.
                         */
                        function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
                        /**
                         * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
                         *
                         * Emits a {TransferBatch} event.
                         *
                         * Requirements:
                         *
                         * - `ids` and `amounts` must have the same length.
                         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
                         * acceptance magic value.
                         */
                        function safeBatchTransferFrom(
                            address from,
                            address to,
                            uint256[] calldata ids,
                            uint256[] calldata amounts,
                            bytes calldata data
                        ) external;
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
                    pragma solidity ^0.8.0;
                    /**
                     * @dev This is the interface that {BeaconProxy} expects of its beacon.
                     */
                    interface IBeacon {
                        /**
                         * @dev Must return an address that can be used as a delegate call target.
                         *
                         * {BeaconProxy} will check that this address is a contract.
                         */
                        function implementation() external view returns (address);
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)
                    pragma solidity ^0.8.0;
                    /**
                     * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
                     *
                     * _Available since v4.8.3._
                     */
                    interface IERC1967 {
                        /**
                         * @dev Emitted when the implementation is upgraded.
                         */
                        event Upgraded(address indexed implementation);
                        /**
                         * @dev Emitted when the admin account has changed.
                         */
                        event AdminChanged(address previousAdmin, address newAdmin);
                        /**
                         * @dev Emitted when the beacon is changed.
                         */
                        event BeaconUpgraded(address indexed beacon);
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
                    pragma solidity ^0.8.0;
                    /**
                     * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
                     * proxy whose upgrades are fully controlled by the current implementation.
                     */
                    interface IERC1822Proxiable {
                        /**
                         * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
                         * address.
                         *
                         * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                         * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                         * function revert if invoked through a proxy.
                         */
                        function proxiableUUID() external view returns (bytes32);
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
                    pragma solidity ^0.8.1;
                    /**
                     * @dev Collection of functions related to the address type
                     */
                    library Address {
                        /**
                         * @dev Returns true if `account` is a contract.
                         *
                         * [IMPORTANT]
                         * ====
                         * It is unsafe to assume that an address for which this function returns
                         * false is an externally-owned account (EOA) and not a contract.
                         *
                         * Among others, `isContract` will return false for the following
                         * types of addresses:
                         *
                         *  - an externally-owned account
                         *  - a contract in construction
                         *  - an address where a contract will be created
                         *  - an address where a contract lived, but was destroyed
                         *
                         * Furthermore, `isContract` will also return true if the target contract within
                         * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                         * which only has an effect at the end of a transaction.
                         * ====
                         *
                         * [IMPORTANT]
                         * ====
                         * You shouldn't rely on `isContract` to protect against flash loan attacks!
                         *
                         * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                         * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                         * constructor.
                         * ====
                         */
                        function isContract(address account) internal view returns (bool) {
                            // This method relies on extcodesize/address.code.length, which returns 0
                            // for contracts in construction, since the code is only stored at the end
                            // of the constructor execution.
                            return account.code.length > 0;
                        }
                        /**
                         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                         * `recipient`, forwarding all available gas and reverting on errors.
                         *
                         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                         * of certain opcodes, possibly making contracts go over the 2300 gas limit
                         * imposed by `transfer`, making them unable to receive funds via
                         * `transfer`. {sendValue} removes this limitation.
                         *
                         * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                         *
                         * IMPORTANT: because control is transferred to `recipient`, care must be
                         * taken to not create reentrancy vulnerabilities. Consider using
                         * {ReentrancyGuard} or the
                         * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                         */
                        function sendValue(address payable recipient, uint256 amount) internal {
                            require(address(this).balance >= amount, "Address: insufficient balance");
                            (bool success, ) = recipient.call{value: amount}("");
                            require(success, "Address: unable to send value, recipient may have reverted");
                        }
                        /**
                         * @dev Performs a Solidity function call using a low level `call`. A
                         * plain `call` is an unsafe replacement for a function call: use this
                         * function instead.
                         *
                         * If `target` reverts with a revert reason, it is bubbled up by this
                         * function (like regular Solidity function calls).
                         *
                         * Returns the raw returned data. To convert to the expected return value,
                         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                         *
                         * Requirements:
                         *
                         * - `target` must be a contract.
                         * - calling `target` with `data` must not revert.
                         *
                         * _Available since v3.1._
                         */
                        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                            return functionCallWithValue(target, data, 0, "Address: low-level call failed");
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                         * `errorMessage` as a fallback revert reason when `target` reverts.
                         *
                         * _Available since v3.1._
                         */
                        function functionCall(
                            address target,
                            bytes memory data,
                            string memory errorMessage
                        ) internal returns (bytes memory) {
                            return functionCallWithValue(target, data, 0, errorMessage);
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                         * but also transferring `value` wei to `target`.
                         *
                         * Requirements:
                         *
                         * - the calling contract must have an ETH balance of at least `value`.
                         * - the called Solidity function must be `payable`.
                         *
                         * _Available since v3.1._
                         */
                        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                        }
                        /**
                         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                         * with `errorMessage` as a fallback revert reason when `target` reverts.
                         *
                         * _Available since v3.1._
                         */
                        function functionCallWithValue(
                            address target,
                            bytes memory data,
                            uint256 value,
                            string memory errorMessage
                        ) internal returns (bytes memory) {
                            require(address(this).balance >= value, "Address: insufficient balance for call");
                            (bool success, bytes memory returndata) = target.call{value: value}(data);
                            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                         * but performing a static call.
                         *
                         * _Available since v3.3._
                         */
                        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                            return functionStaticCall(target, data, "Address: low-level static call failed");
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                         * but performing a static call.
                         *
                         * _Available since v3.3._
                         */
                        function functionStaticCall(
                            address target,
                            bytes memory data,
                            string memory errorMessage
                        ) internal view returns (bytes memory) {
                            (bool success, bytes memory returndata) = target.staticcall(data);
                            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                         * but performing a delegate call.
                         *
                         * _Available since v3.4._
                         */
                        function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                            return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                         * but performing a delegate call.
                         *
                         * _Available since v3.4._
                         */
                        function functionDelegateCall(
                            address target,
                            bytes memory data,
                            string memory errorMessage
                        ) internal returns (bytes memory) {
                            (bool success, bytes memory returndata) = target.delegatecall(data);
                            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                        }
                        /**
                         * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                         * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                         *
                         * _Available since v4.8._
                         */
                        function verifyCallResultFromTarget(
                            address target,
                            bool success,
                            bytes memory returndata,
                            string memory errorMessage
                        ) internal view returns (bytes memory) {
                            if (success) {
                                if (returndata.length == 0) {
                                    // only check isContract if the call was successful and the return data is empty
                                    // otherwise we already know that it was a contract
                                    require(isContract(target), "Address: call to non-contract");
                                }
                                return returndata;
                            } else {
                                _revert(returndata, errorMessage);
                            }
                        }
                        /**
                         * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                         * revert reason or using the provided one.
                         *
                         * _Available since v4.3._
                         */
                        function verifyCallResult(
                            bool success,
                            bytes memory returndata,
                            string memory errorMessage
                        ) internal pure returns (bytes memory) {
                            if (success) {
                                return returndata;
                            } else {
                                _revert(returndata, errorMessage);
                            }
                        }
                        function _revert(bytes memory returndata, string memory errorMessage) private pure {
                            // Look for revert reason and bubble it up if present
                            if (returndata.length > 0) {
                                // The easiest way to bubble the revert reason is using memory via assembly
                                /// @solidity memory-safe-assembly
                                assembly {
                                    let returndata_size := mload(returndata)
                                    revert(add(32, returndata), returndata_size)
                                }
                            } else {
                                revert(errorMessage);
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
                    // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
                    pragma solidity ^0.8.0;
                    /**
                     * @dev Library for reading and writing primitive types to specific storage slots.
                     *
                     * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                     * This library helps with reading and writing to such slots without the need for inline assembly.
                     *
                     * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                     *
                     * Example usage to set ERC1967 implementation slot:
                     * ```solidity
                     * contract ERC1967 {
                     *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                     *
                     *     function _getImplementation() internal view returns (address) {
                     *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                     *     }
                     *
                     *     function _setImplementation(address newImplementation) internal {
                     *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                     *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                     *     }
                     * }
                     * ```
                     *
                     * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
                     * _Available since v4.9 for `string`, `bytes`._
                     */
                    library StorageSlot {
                        struct AddressSlot {
                            address value;
                        }
                        struct BooleanSlot {
                            bool value;
                        }
                        struct Bytes32Slot {
                            bytes32 value;
                        }
                        struct Uint256Slot {
                            uint256 value;
                        }
                        struct StringSlot {
                            string value;
                        }
                        struct BytesSlot {
                            bytes value;
                        }
                        /**
                         * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                         */
                        function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                         */
                        function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                         */
                        function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                         */
                        function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `StringSlot` with member `value` located at `slot`.
                         */
                        function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                         */
                        function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := store.slot
                            }
                        }
                        /**
                         * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                         */
                        function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                         */
                        function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := store.slot
                            }
                        }
                    }
                    

                    File 4 of 4: ZoraCreator1155Impl
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {ERC1155Upgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/token/ERC1155/ERC1155Upgradeable.sol";
                    import {ReentrancyGuardUpgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/security/ReentrancyGuardUpgradeable.sol";
                    import {UUPSUpgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
                    import {IERC1155MetadataURIUpgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC1155MetadataURIUpgradeable.sol";
                    import {IERC165Upgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC165Upgradeable.sol";
                    import {IProtocolRewards} from "@zoralabs/protocol-rewards/dist/contracts/interfaces/IProtocolRewards.sol";
                    import {ERC1155Rewards} from "@zoralabs/protocol-rewards/dist/contracts/abstract/ERC1155/ERC1155Rewards.sol";
                    import {ERC1155RewardsStorageV1} from "@zoralabs/protocol-rewards/dist/contracts/abstract/ERC1155/ERC1155RewardsStorageV1.sol";
                    import {IZoraCreator1155} from "../interfaces/IZoraCreator1155.sol";
                    import {IZoraCreator1155Initializer} from "../interfaces/IZoraCreator1155Initializer.sol";
                    import {ReentrancyGuardUpgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/security/ReentrancyGuardUpgradeable.sol";
                    import {UUPSUpgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
                    import {MathUpgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/utils/math/MathUpgradeable.sol";
                    import {ContractVersionBase} from "../version/ContractVersionBase.sol";
                    import {CreatorPermissionControl} from "../permissions/CreatorPermissionControl.sol";
                    import {CreatorRendererControl} from "../renderer/CreatorRendererControl.sol";
                    import {CreatorRoyaltiesControl} from "../royalties/CreatorRoyaltiesControl.sol";
                    import {ICreatorCommands} from "../interfaces/ICreatorCommands.sol";
                    import {IMinter1155} from "../interfaces/IMinter1155.sol";
                    import {IRenderer1155} from "../interfaces/IRenderer1155.sol";
                    import {ITransferHookReceiver} from "../interfaces/ITransferHookReceiver.sol";
                    import {IFactoryManagedUpgradeGate} from "../interfaces/IFactoryManagedUpgradeGate.sol";
                    import {IZoraCreator1155} from "../interfaces/IZoraCreator1155.sol";
                    import {LegacyNamingControl} from "../legacy-naming/LegacyNamingControl.sol";
                    import {MintFeeManager} from "../fee/MintFeeManager.sol";
                    import {PublicMulticall} from "../utils/PublicMulticall.sol";
                    import {SharedBaseConstants} from "../shared/SharedBaseConstants.sol";
                    import {TransferHelperUtils} from "../utils/TransferHelperUtils.sol";
                    import {ZoraCreator1155StorageV1} from "./ZoraCreator1155StorageV1.sol";
                    /// Imagine. Mint. Enjoy.
                    /// @title ZoraCreator1155Impl
                    /// @notice The core implementation contract for a creator's 1155 token
                    /// @author @iainnash / @tbtstl
                    contract ZoraCreator1155Impl is
                        IZoraCreator1155,
                        IZoraCreator1155Initializer,
                        ContractVersionBase,
                        ReentrancyGuardUpgradeable,
                        PublicMulticall,
                        ERC1155Upgradeable,
                        MintFeeManager,
                        UUPSUpgradeable,
                        CreatorRendererControl,
                        LegacyNamingControl,
                        ZoraCreator1155StorageV1,
                        CreatorPermissionControl,
                        CreatorRoyaltiesControl,
                        ERC1155Rewards,
                        ERC1155RewardsStorageV1
                    {
                        /// @notice This user role allows for any action to be performed
                        uint256 public constant PERMISSION_BIT_ADMIN = 2 ** 1;
                        /// @notice This user role allows for only mint actions to be performed
                        uint256 public constant PERMISSION_BIT_MINTER = 2 ** 2;
                        /// @notice This user role allows for only managing sales configurations
                        uint256 public constant PERMISSION_BIT_SALES = 2 ** 3;
                        /// @notice This user role allows for only managing metadata configuration
                        uint256 public constant PERMISSION_BIT_METADATA = 2 ** 4;
                        /// @notice This user role allows for only withdrawing funds and setting funds withdraw address
                        uint256 public constant PERMISSION_BIT_FUNDS_MANAGER = 2 ** 5;
                        /// @notice Factory contract
                        IFactoryManagedUpgradeGate internal immutable factory;
                        constructor(
                            uint256 _mintFeeAmount,
                            address _mintFeeRecipient,
                            address _factory,
                            address _protocolRewards
                        ) MintFeeManager(_mintFeeAmount, _mintFeeRecipient) ERC1155Rewards(_protocolRewards, _mintFeeRecipient) initializer {
                            factory = IFactoryManagedUpgradeGate(_factory);
                        }
                        /// @notice Initializes the contract
                        /// @param contractName the legacy on-chain contract name
                        /// @param newContractURI The contract URI
                        /// @param defaultRoyaltyConfiguration The default royalty configuration
                        /// @param defaultAdmin The default admin to manage the token
                        /// @param setupActions The setup actions to run, if any
                        function initialize(
                            string memory contractName,
                            string memory newContractURI,
                            RoyaltyConfiguration memory defaultRoyaltyConfiguration,
                            address payable defaultAdmin,
                            bytes[] calldata setupActions
                        ) external nonReentrant initializer {
                            // We are not initalizing the OZ 1155 implementation
                            // to save contract storage space and runtime
                            // since the only thing affected here is the uri.
                            // __ERC1155_init("");
                            // Setup uups
                            __UUPSUpgradeable_init();
                            // Setup re-entracy guard
                            __ReentrancyGuard_init();
                            // Setup contract-default token ID
                            _setupDefaultToken(defaultAdmin, newContractURI, defaultRoyaltyConfiguration);
                            // Set owner to default admin
                            _setOwner(defaultAdmin);
                            _setFundsRecipient(defaultAdmin);
                            _setName(contractName);
                            // Run Setup actions
                            if (setupActions.length > 0) {
                                // Temporarily make sender admin
                                _addPermission(CONTRACT_BASE_ID, msg.sender, PERMISSION_BIT_ADMIN);
                                // Make calls
                                multicall(setupActions);
                                // Remove admin
                                _removePermission(CONTRACT_BASE_ID, msg.sender, PERMISSION_BIT_ADMIN);
                            }
                        }
                        /// @notice sets up the global configuration for the 1155 contract
                        /// @param newContractURI The contract URI
                        /// @param defaultRoyaltyConfiguration The default royalty configuration
                        function _setupDefaultToken(address defaultAdmin, string memory newContractURI, RoyaltyConfiguration memory defaultRoyaltyConfiguration) internal {
                            // Add admin permission to default admin to manage contract
                            _addPermission(CONTRACT_BASE_ID, defaultAdmin, PERMISSION_BIT_ADMIN);
                            // Mint token ID 0 / don't allow any user mints
                            _setupNewToken(newContractURI, 0);
                            // Update default royalties
                            _updateRoyalties(CONTRACT_BASE_ID, defaultRoyaltyConfiguration);
                        }
                        /// @notice Updates the royalty configuration for a token
                        /// @param tokenId The token ID to update
                        /// @param newConfiguration The new royalty configuration
                        function updateRoyaltiesForToken(
                            uint256 tokenId,
                            RoyaltyConfiguration memory newConfiguration
                        ) external onlyAdminOrRole(tokenId, PERMISSION_BIT_FUNDS_MANAGER) {
                            _updateRoyalties(tokenId, newConfiguration);
                        }
                        /// @notice remove this function from openzeppelin impl
                        /// @dev This makes this internal function a no-op
                        function _setURI(string memory newuri) internal virtual override {}
                        /// @notice This gets the next token in line to be minted when minting linearly (default behavior) and updates the counter
                        function _getAndUpdateNextTokenId() internal returns (uint256) {
                            unchecked {
                                return nextTokenId++;
                            }
                        }
                        /// @notice Ensure that the next token ID is correct
                        /// @dev This reverts if the invariant doesn't match. This is used for multicall token id assumptions
                        /// @param lastTokenId The last token ID
                        function assumeLastTokenIdMatches(uint256 lastTokenId) external view {
                            unchecked {
                                if (nextTokenId - 1 != lastTokenId) {
                                    revert TokenIdMismatch(lastTokenId, nextTokenId - 1);
                                }
                            }
                        }
                        /// @notice Checks if a user either has a role for a token or if they are the admin
                        /// @dev This is an internal function that is called by the external getter and internal functions
                        /// @param user The user to check
                        /// @param tokenId The token ID to check
                        /// @param role The role to check
                        /// @return true or false if the permission exists for the user given the token id
                        function _isAdminOrRole(address user, uint256 tokenId, uint256 role) internal view returns (bool) {
                            return _hasAnyPermission(tokenId, user, PERMISSION_BIT_ADMIN | role);
                        }
                        /// @notice Checks if a user either has a role for a token or if they are the admin
                        /// @param user The user to check
                        /// @param tokenId The token ID to check
                        /// @param role The role to check
                        /// @return true or false if the permission exists for the user given the token id
                        function isAdminOrRole(address user, uint256 tokenId, uint256 role) external view returns (bool) {
                            return _isAdminOrRole(user, tokenId, role);
                        }
                        /// @notice Checks if the user is an admin for the given tokenId
                        /// @dev This function reverts if the permission does not exist for the given user and tokenId
                        /// @param user user to check
                        /// @param tokenId tokenId to check
                        /// @param role role to check for admin
                        function _requireAdminOrRole(address user, uint256 tokenId, uint256 role) internal view {
                            if (!(_hasAnyPermission(tokenId, user, PERMISSION_BIT_ADMIN | role) || _hasAnyPermission(CONTRACT_BASE_ID, user, PERMISSION_BIT_ADMIN | role))) {
                                revert UserMissingRoleForToken(user, tokenId, role);
                            }
                        }
                        /// @notice Checks if the user is an admin
                        /// @dev This reverts if the user is not an admin for the given token id or contract
                        /// @param user user to check
                        /// @param tokenId tokenId to check
                        function _requireAdmin(address user, uint256 tokenId) internal view {
                            if (!(_hasAnyPermission(tokenId, user, PERMISSION_BIT_ADMIN) || _hasAnyPermission(CONTRACT_BASE_ID, user, PERMISSION_BIT_ADMIN))) {
                                revert UserMissingRoleForToken(user, tokenId, PERMISSION_BIT_ADMIN);
                            }
                        }
                        /// @notice Modifier checking if the user is an admin or has a role
                        /// @dev This reverts if the msg.sender is not an admin for the given token id or contract
                        /// @param tokenId tokenId to check
                        /// @param role role to check
                        modifier onlyAdminOrRole(uint256 tokenId, uint256 role) {
                            _requireAdminOrRole(msg.sender, tokenId, role);
                            _;
                        }
                        /// @notice Modifier checking if the user is an admin
                        /// @dev This reverts if the msg.sender is not an admin for the given token id or contract
                        /// @param tokenId tokenId to check
                        modifier onlyAdmin(uint256 tokenId) {
                            _requireAdmin(msg.sender, tokenId);
                            _;
                        }
                        /// @notice Modifier checking if the requested quantity of tokens can be minted for the tokenId
                        /// @dev This reverts if the number that can be minted is exceeded
                        /// @param tokenId token id to check available allowed quantity
                        /// @param quantity requested to be minted
                        modifier canMintQuantity(uint256 tokenId, uint256 quantity) {
                            _requireCanMintQuantity(tokenId, quantity);
                            _;
                        }
                        /// @notice Only from approved address for burn
                        /// @param from address that the tokens will be burned from, validate that this is msg.sender or that msg.sender is approved
                        modifier onlyFromApprovedForBurn(address from) {
                            if (from != msg.sender && !isApprovedForAll(from, msg.sender)) {
                                revert Burn_NotOwnerOrApproved(msg.sender, from);
                            }
                            _;
                        }
                        /// @notice Checks if a user can mint a quantity of a token
                        /// @dev Reverts if the mint exceeds the allowed quantity (or if the token does not exist)
                        /// @param tokenId The token ID to check
                        /// @param quantity The quantity of tokens to mint to check
                        function _requireCanMintQuantity(uint256 tokenId, uint256 quantity) internal view {
                            TokenData storage tokenInformation = tokens[tokenId];
                            if (tokenInformation.totalMinted + quantity > tokenInformation.maxSupply) {
                                revert CannotMintMoreTokens(tokenId, quantity, tokenInformation.totalMinted, tokenInformation.maxSupply);
                            }
                        }
                        /// @notice Set up a new token
                        /// @param newURI The URI for the token
                        /// @param maxSupply The maximum supply of the token
                        function setupNewToken(
                            string calldata newURI,
                            uint256 maxSupply
                        ) public onlyAdminOrRole(CONTRACT_BASE_ID, PERMISSION_BIT_MINTER) nonReentrant returns (uint256) {
                            uint256 tokenId = _setupNewTokenAndPermission(newURI, maxSupply, msg.sender, PERMISSION_BIT_ADMIN);
                            return tokenId;
                        }
                        /// @notice Set up a new token with a create referral
                        /// @param newURI The URI for the token
                        /// @param maxSupply The maximum supply of the token
                        /// @param createReferral The address of the create referral
                        function setupNewTokenWithCreateReferral(
                            string calldata newURI,
                            uint256 maxSupply,
                            address createReferral
                        ) public onlyAdminOrRole(CONTRACT_BASE_ID, PERMISSION_BIT_MINTER) nonReentrant returns (uint256) {
                            uint256 tokenId = _setupNewTokenAndPermission(newURI, maxSupply, msg.sender, PERMISSION_BIT_ADMIN);
                            _setCreateReferral(tokenId, createReferral);
                            return tokenId;
                        }
                        function _setupNewTokenAndPermission(string calldata newURI, uint256 maxSupply, address user, uint256 permission) internal returns (uint256) {
                            uint256 tokenId = _setupNewToken(newURI, maxSupply);
                            _addPermission(tokenId, user, permission);
                            if (bytes(newURI).length > 0) {
                                emit URI(newURI, tokenId);
                            }
                            emit SetupNewToken(tokenId, user, newURI, maxSupply);
                            return tokenId;
                        }
                        /// @notice Update the token URI for a token
                        /// @param tokenId The token ID to update the URI for
                        /// @param _newURI The new URI
                        function updateTokenURI(uint256 tokenId, string memory _newURI) external onlyAdminOrRole(tokenId, PERMISSION_BIT_METADATA) {
                            if (tokenId == CONTRACT_BASE_ID) {
                                revert();
                            }
                            emit URI(_newURI, tokenId);
                            tokens[tokenId].uri = _newURI;
                        }
                        /// @notice Update the global contract metadata
                        /// @param _newURI The new contract URI
                        /// @param _newName The new contract name
                        function updateContractMetadata(string memory _newURI, string memory _newName) external onlyAdminOrRole(0, PERMISSION_BIT_METADATA) {
                            tokens[CONTRACT_BASE_ID].uri = _newURI;
                            _setName(_newName);
                            emit ContractMetadataUpdated(msg.sender, _newURI, _newName);
                        }
                        function _setupNewToken(string memory newURI, uint256 maxSupply) internal returns (uint256 tokenId) {
                            tokenId = _getAndUpdateNextTokenId();
                            TokenData memory tokenData = TokenData({uri: newURI, maxSupply: maxSupply, totalMinted: 0});
                            tokens[tokenId] = tokenData;
                            emit UpdatedToken(msg.sender, tokenId, tokenData);
                        }
                        /// @notice Add a role to a user for a token
                        /// @param tokenId The token ID to add the role to
                        /// @param user The user to add the role to
                        /// @param permissionBits The permission bit to add
                        function addPermission(uint256 tokenId, address user, uint256 permissionBits) external onlyAdmin(tokenId) {
                            _addPermission(tokenId, user, permissionBits);
                        }
                        /// @notice Remove a role from a user for a token
                        /// @param tokenId The token ID to remove the role from
                        /// @param user The user to remove the role from
                        /// @param permissionBits The permission bit to remove
                        function removePermission(uint256 tokenId, address user, uint256 permissionBits) external onlyAdmin(tokenId) {
                            _removePermission(tokenId, user, permissionBits);
                            // Clear owner field
                            if (tokenId == CONTRACT_BASE_ID && user == config.owner && !_hasAnyPermission(CONTRACT_BASE_ID, user, PERMISSION_BIT_ADMIN)) {
                                _setOwner(address(0));
                            }
                        }
                        /// @notice Set the owner of the contract
                        /// @param newOwner The new owner of the contract
                        function setOwner(address newOwner) external onlyAdmin(CONTRACT_BASE_ID) {
                            if (!_hasAnyPermission(CONTRACT_BASE_ID, newOwner, PERMISSION_BIT_ADMIN)) {
                                revert NewOwnerNeedsToBeAdmin();
                            }
                            // Update owner field
                            _setOwner(newOwner);
                        }
                        /// @notice Getter for the owner singleton of the contract for outside interfaces
                        /// @return the owner of the contract singleton for compat.
                        function owner() external view returns (address) {
                            return config.owner;
                        }
                        /// @notice AdminMint that only checks if the requested quantity can be minted and has a re-entrant guard
                        /// @param recipient recipient for admin minted tokens
                        /// @param tokenId token id to mint
                        /// @param quantity quantity to mint
                        /// @param data callback data as specified by the 1155 spec
                        function _adminMint(address recipient, uint256 tokenId, uint256 quantity, bytes memory data) internal {
                            _mint(recipient, tokenId, quantity, data);
                        }
                        /// @notice Mint a token to a user as the admin or minter
                        /// @param recipient The recipient of the token
                        /// @param tokenId The token ID to mint
                        /// @param quantity The quantity of tokens to mint
                        /// @param data The data to pass to the onERC1155Received function
                        function adminMint(
                            address recipient,
                            uint256 tokenId,
                            uint256 quantity,
                            bytes memory data
                        ) external nonReentrant onlyAdminOrRole(tokenId, PERMISSION_BIT_MINTER) {
                            // Call internal admin mint
                            _adminMint(recipient, tokenId, quantity, data);
                        }
                        /// @notice Batch mint tokens to a user as the admin or minter
                        /// @param recipient The recipient of the tokens
                        /// @param tokenIds The token IDs to mint
                        /// @param quantities The quantities of tokens to mint
                        /// @param data The data to pass to the onERC1155BatchReceived function
                        function adminMintBatch(address recipient, uint256[] memory tokenIds, uint256[] memory quantities, bytes memory data) external nonReentrant {
                            bool isGlobalAdminOrMinter = _isAdminOrRole(msg.sender, CONTRACT_BASE_ID, PERMISSION_BIT_MINTER);
                            for (uint256 i = 0; i < tokenIds.length; ++i) {
                                if (!isGlobalAdminOrMinter) {
                                    _requireAdminOrRole(msg.sender, tokenIds[i], PERMISSION_BIT_MINTER);
                                }
                            }
                            _mintBatch(recipient, tokenIds, quantities, data);
                        }
                        /// @notice Mint tokens given a minter contract and minter arguments
                        /// @param minter The minter contract to use
                        /// @param tokenId The token ID to mint
                        /// @param quantity The quantity of tokens to mint
                        /// @param minterArguments The arguments to pass to the minter
                        function mint(IMinter1155 minter, uint256 tokenId, uint256 quantity, bytes calldata minterArguments) external payable nonReentrant {
                            // Require admin from the minter to mint
                            _requireAdminOrRole(address(minter), tokenId, PERMISSION_BIT_MINTER);
                            // Get value sent and handle mint fee
                            uint256 ethValueSent = _handleFeeAndGetValueSent(quantity);
                            // Execute commands returned from minter
                            _executeCommands(minter.requestMint(msg.sender, tokenId, quantity, ethValueSent, minterArguments).commands, ethValueSent, tokenId);
                            emit Purchased(msg.sender, address(minter), tokenId, quantity, msg.value);
                        }
                        /// @notice Get the creator reward recipient address
                        /// @dev The creator is not enforced to set a funds recipient address, so in that case the reward would be claimable by creator's contract
                        function getCreatorRewardRecipient() public view returns (address payable) {
                            return config.fundsRecipient != address(0) ? config.fundsRecipient : payable(address(this));
                        }
                        /// @notice Mint tokens and payout rewards given a minter contract, minter arguments, a finder, and a origin
                        /// @param minter The minter contract to use
                        /// @param tokenId The token ID to mint
                        /// @param quantity The quantity of tokens to mint
                        /// @param minterArguments The arguments to pass to the minter
                        /// @param mintReferral The referrer of the mint
                        function mintWithRewards(
                            IMinter1155 minter,
                            uint256 tokenId,
                            uint256 quantity,
                            bytes calldata minterArguments,
                            address mintReferral
                        ) external payable nonReentrant {
                            // Require admin from the minter to mint
                            _requireAdminOrRole(address(minter), tokenId, PERMISSION_BIT_MINTER);
                            // Get value sent and handle mint rewards
                            uint256 ethValueSent = _handleRewardsAndGetValueSent(msg.value, quantity, getCreatorRewardRecipient(), createReferrals[tokenId], mintReferral);
                            // Execute commands returned from minter
                            _executeCommands(minter.requestMint(msg.sender, tokenId, quantity, ethValueSent, minterArguments).commands, ethValueSent, tokenId);
                            emit Purchased(msg.sender, address(minter), tokenId, quantity, msg.value);
                        }
                        /// @notice Set a metadata renderer for a token
                        /// @param tokenId The token ID to set the renderer for
                        /// @param renderer The renderer to set
                        function setTokenMetadataRenderer(uint256 tokenId, IRenderer1155 renderer) external nonReentrant onlyAdminOrRole(tokenId, PERMISSION_BIT_METADATA) {
                            _setRenderer(tokenId, renderer);
                            if (tokenId == 0) {
                                emit ContractRendererUpdated(renderer);
                            } else {
                                // We don't know the uri from the renderer but can emit a notification to the indexer here
                                emit URI("", tokenId);
                            }
                        }
                        /// Execute Minter Commands ///
                        /// @notice Internal functions to execute commands returned by the minter
                        /// @param commands list of command structs
                        /// @param ethValueSent the ethereum value sent in the mint transaction into the contract
                        /// @param tokenId the token id the user requested to mint (0 if the token id is set by the minter itself across the whole contract)
                        function _executeCommands(ICreatorCommands.Command[] memory commands, uint256 ethValueSent, uint256 tokenId) internal {
                            for (uint256 i = 0; i < commands.length; ++i) {
                                ICreatorCommands.CreatorActions method = commands[i].method;
                                if (method == ICreatorCommands.CreatorActions.SEND_ETH) {
                                    (address recipient, uint256 amount) = abi.decode(commands[i].args, (address, uint256));
                                    if (ethValueSent > amount) {
                                        revert Mint_InsolventSaleTransfer();
                                    }
                                    if (!TransferHelperUtils.safeSendETH(recipient, amount, TransferHelperUtils.FUNDS_SEND_NORMAL_GAS_LIMIT)) {
                                        revert Mint_ValueTransferFail();
                                    }
                                } else if (method == ICreatorCommands.CreatorActions.MINT) {
                                    (address recipient, uint256 mintTokenId, uint256 quantity) = abi.decode(commands[i].args, (address, uint256, uint256));
                                    if (tokenId != 0 && mintTokenId != tokenId) {
                                        revert Mint_TokenIDMintNotAllowed();
                                    }
                                    _mint(recipient, tokenId, quantity, "");
                                } else {
                                    // no-op
                                }
                            }
                        }
                        /// @notice Token info getter
                        /// @param tokenId token id to get info for
                        /// @return TokenData struct returned
                        function getTokenInfo(uint256 tokenId) external view returns (TokenData memory) {
                            return tokens[tokenId];
                        }
                        /// @notice Proxy setter for sale contracts (only callable by SALES permission or admin)
                        /// @param tokenId The token ID to call the sale contract with
                        /// @param salesConfig The sales config contract to call
                        /// @param data The data to pass to the sales config contract
                        function callSale(uint256 tokenId, IMinter1155 salesConfig, bytes memory data) external onlyAdminOrRole(tokenId, PERMISSION_BIT_SALES) {
                            _requireAdminOrRole(address(salesConfig), tokenId, PERMISSION_BIT_MINTER);
                            if (!salesConfig.supportsInterface(type(IMinter1155).interfaceId)) {
                                revert Sale_CannotCallNonSalesContract(address(salesConfig));
                            }
                            (bool success, bytes memory why) = address(salesConfig).call(data);
                            if (!success) {
                                revert CallFailed(why);
                            }
                        }
                        /// @notice Proxy setter for renderer contracts (only callable by METADATA permission or admin)
                        /// @param tokenId The token ID to call the renderer contract with
                        /// @param data The data to pass to the renderer contract
                        function callRenderer(uint256 tokenId, bytes memory data) external onlyAdminOrRole(tokenId, PERMISSION_BIT_METADATA) {
                            // We assume any renderers set are checked for EIP165 signature during write stage.
                            (bool success, bytes memory why) = address(getCustomRenderer(tokenId)).call(data);
                            if (!success) {
                                revert CallFailed(why);
                            }
                        }
                        /// @notice Returns true if the contract implements the interface defined by interfaceId
                        /// @param interfaceId The interface to check for
                        /// @return if the interfaceId is marked as supported
                        function supportsInterface(
                            bytes4 interfaceId
                        ) public view virtual override(CreatorRoyaltiesControl, ERC1155Upgradeable, IERC165Upgradeable) returns (bool) {
                            return super.supportsInterface(interfaceId) || interfaceId == type(IZoraCreator1155).interfaceId || ERC1155Upgradeable.supportsInterface(interfaceId);
                        }
                        function _handleSupplyRoyalty(uint256 tokenId, uint256 mintAmount, bytes memory data) internal returns (uint256 totalRoyaltyMints) {
                            uint256 royaltyMintSchedule = royalties[tokenId].royaltyMintSchedule;
                            if (royaltyMintSchedule == 0) {
                                royaltyMintSchedule = royalties[CONTRACT_BASE_ID].royaltyMintSchedule;
                            }
                            if (royaltyMintSchedule == 0) {
                                // If we still have no schedule, return 0 supply royalty.
                                return 0;
                            }
                            uint256 maxSupply = tokens[tokenId].maxSupply;
                            uint256 totalMinted = tokens[tokenId].totalMinted;
                            totalRoyaltyMints = (mintAmount + (totalMinted % royaltyMintSchedule)) / (royaltyMintSchedule - 1);
                            totalRoyaltyMints = MathUpgradeable.min(totalRoyaltyMints, maxSupply - (mintAmount + totalMinted));
                            if (totalRoyaltyMints > 0) {
                                address royaltyRecipient = royalties[tokenId].royaltyRecipient;
                                if (royaltyRecipient == address(0)) {
                                    royaltyRecipient = royalties[CONTRACT_BASE_ID].royaltyRecipient;
                                }
                                // If we have no recipient set, return 0 supply royalty.
                                if (royaltyRecipient == address(0)) {
                                    return 0;
                                }
                                super._mint(royaltyRecipient, tokenId, totalRoyaltyMints, data);
                            }
                        }
                        /// Generic 1155 function overrides ///
                        /// @notice Mint function that 1) checks quantity and 2) handles supply royalty 3) keeps track of allowed tokens
                        /// @param to to mint to
                        /// @param id token id to mint
                        /// @param amount of tokens to mint
                        /// @param data as specified by 1155 standard
                        function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual override {
                            uint256 supplyRoyaltyMints = _handleSupplyRoyalty(id, amount, data);
                            _requireCanMintQuantity(id, amount + supplyRoyaltyMints);
                            super._mint(to, id, amount, data);
                            tokens[id].totalMinted += amount + supplyRoyaltyMints;
                        }
                        /// @notice Mint batch function that 1) checks quantity and 2) handles supply royalty 3) keeps track of allowed tokens
                        /// @param to to mint to
                        /// @param ids token ids to mint
                        /// @param amounts of tokens to mint
                        /// @param data as specified by 1155 standard
                        function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual override {
                            super._mintBatch(to, ids, amounts, data);
                            for (uint256 i = 0; i < ids.length; ++i) {
                                uint256 supplyRoyaltyMints = _handleSupplyRoyalty(ids[i], amounts[i], data);
                                _requireCanMintQuantity(ids[i], amounts[i] + supplyRoyaltyMints);
                                tokens[ids[i]].totalMinted += amounts[i] + supplyRoyaltyMints;
                            }
                        }
                        /// @notice Burns a batch of tokens
                        /// @dev Only the current owner is allowed to burn
                        /// @param from the user to burn from
                        /// @param tokenIds The token ID to burn
                        /// @param amounts The amount of tokens to burn
                        function burnBatch(address from, uint256[] calldata tokenIds, uint256[] calldata amounts) external {
                            if (from != msg.sender && !isApprovedForAll(from, msg.sender)) {
                                revert Burn_NotOwnerOrApproved(msg.sender, from);
                            }
                            _burnBatch(from, tokenIds, amounts);
                        }
                        function setTransferHook(ITransferHookReceiver transferHook) external onlyAdmin(CONTRACT_BASE_ID) {
                            if (address(transferHook) != address(0)) {
                                if (!transferHook.supportsInterface(type(ITransferHookReceiver).interfaceId)) {
                                    revert Config_TransferHookNotSupported(address(transferHook));
                                }
                            }
                            config.transferHook = transferHook;
                            emit ConfigUpdated(msg.sender, ConfigUpdate.TRANSFER_HOOK, config);
                        }
                        /// @notice Hook before token transfer that checks for a transfer hook integration
                        /// @param operator operator moving the tokens
                        /// @param from from address
                        /// @param to to address
                        /// @param ids token ids to move
                        /// @param amounts amounts of tokens
                        /// @param data data of tokens
                        function _beforeBatchTokenTransfer(
                            address operator,
                            address from,
                            address to,
                            uint256[] memory ids,
                            uint256[] memory amounts,
                            bytes memory data
                        ) internal override {
                            super._beforeBatchTokenTransfer(operator, from, to, ids, amounts, data);
                            if (address(config.transferHook) != address(0)) {
                                config.transferHook.onTokenTransferBatch({target: address(this), operator: operator, from: from, to: to, ids: ids, amounts: amounts, data: data});
                            }
                        }
                        /// @notice Returns the URI for the contract
                        function contractURI() external view returns (string memory) {
                            IRenderer1155 customRenderer = getCustomRenderer(CONTRACT_BASE_ID);
                            if (address(customRenderer) != address(0)) {
                                return customRenderer.contractURI();
                            }
                            return uri(0);
                        }
                        /// @notice Returns the URI for a token
                        /// @param tokenId The token ID to return the URI for
                        function uri(uint256 tokenId) public view override(ERC1155Upgradeable, IERC1155MetadataURIUpgradeable) returns (string memory) {
                            if (bytes(tokens[tokenId].uri).length > 0) {
                                return tokens[tokenId].uri;
                            }
                            return _render(tokenId);
                        }
                        /// @notice Internal setter for contract admin with no access checks
                        /// @param newOwner new owner address
                        function _setOwner(address newOwner) internal {
                            address lastOwner = config.owner;
                            config.owner = newOwner;
                            emit OwnershipTransferred(lastOwner, newOwner);
                            emit ConfigUpdated(msg.sender, ConfigUpdate.OWNER, config);
                        }
                        /// @notice Set funds recipient address
                        /// @param fundsRecipient new funds recipient address
                        function setFundsRecipient(address payable fundsRecipient) external onlyAdminOrRole(CONTRACT_BASE_ID, PERMISSION_BIT_FUNDS_MANAGER) {
                            _setFundsRecipient(fundsRecipient);
                        }
                        /// @notice Internal no-checks set funds recipient address
                        /// @param fundsRecipient new funds recipient address
                        function _setFundsRecipient(address payable fundsRecipient) internal {
                            config.fundsRecipient = fundsRecipient;
                            emit ConfigUpdated(msg.sender, ConfigUpdate.FUNDS_RECIPIENT, config);
                        }
                        /// @notice Allows the create referral to update the address that can claim their rewards
                        function updateCreateReferral(uint256 tokenId, address recipient) external {
                            if (msg.sender != createReferrals[tokenId]) revert ONLY_CREATE_REFERRAL();
                            _setCreateReferral(tokenId, recipient);
                        }
                        function _setCreateReferral(uint256 tokenId, address recipient) internal {
                            createReferrals[tokenId] = recipient;
                        }
                        /// @notice Withdraws all ETH from the contract to the funds recipient address
                        function withdraw() public onlyAdminOrRole(CONTRACT_BASE_ID, PERMISSION_BIT_FUNDS_MANAGER) {
                            uint256 contractValue = address(this).balance;
                            if (!TransferHelperUtils.safeSendETH(config.fundsRecipient, contractValue, TransferHelperUtils.FUNDS_SEND_NORMAL_GAS_LIMIT)) {
                                revert ETHWithdrawFailed(config.fundsRecipient, contractValue);
                            }
                        }
                        /// @notice Withdraws ETH from the Zora Rewards contract
                        function withdrawRewards(address to, uint256 amount) public onlyAdminOrRole(CONTRACT_BASE_ID, PERMISSION_BIT_FUNDS_MANAGER) {
                            bytes memory data = abi.encodeWithSelector(IProtocolRewards.withdraw.selector, to, amount);
                            (bool success, ) = address(protocolRewards).call(data);
                            if (!success) {
                                revert ProtocolRewardsWithdrawFailed(msg.sender, to, amount);
                            }
                        }
                        ///                                                          ///
                        ///                         MANAGER UPGRADE                  ///
                        ///                                                          ///
                        /// @notice Ensures the caller is authorized to upgrade the contract
                        /// @dev This function is called in `upgradeTo` & `upgradeToAndCall`
                        /// @param _newImpl The new implementation address
                        function _authorizeUpgrade(address _newImpl) internal view override onlyAdmin(CONTRACT_BASE_ID) {
                            if (!factory.isRegisteredUpgradePath(_getImplementation(), _newImpl)) {
                                revert();
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // Modifications from OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol):
                    // - Revert strings replaced with custom errors
                    // - Decoupled hooks 
                    //   - `_beforeTokenTransfer` --> `_beforeTokenTransfer` & `_beforeBatchTokenTransfer`
                    //   - `_afterTokenTransfer` --> `_afterTokenTransfer` & `_afterBatchTokenTransfer`
                    // - Minor gas optimizations (eg. array length caching, unchecked loop iteration)
                    pragma solidity ^0.8.0;
                    import "./IERC1155Upgradeable.sol";
                    import "./IERC1155ReceiverUpgradeable.sol";
                    import "./extensions/IERC1155MetadataURIUpgradeable.sol";
                    import "../../utils/AddressUpgradeable.sol";
                    import "../../utils/ContextUpgradeable.sol";
                    import "../../utils/introspection/ERC165Upgradeable.sol";
                    import "../../proxy/utils/Initializable.sol";
                    error ERC1155_ADDRESS_ZERO_IS_NOT_A_VALID_OWNER();
                    error ERC1155_ACCOUNTS_AND_IDS_LENGTH_MISMATCH();
                    error ERC1155_IDS_AND_AMOUNTS_LENGTH_MISMATCH();
                    error ERC1155_CALLER_IS_NOT_TOKEN_OWNER_OR_APPROVED();
                    error ERC1155_TRANSFER_TO_ZERO_ADDRESS();
                    error ERC1155_INSUFFICIENT_BALANCE_FOR_TRANSFER();
                    error ERC1155_MINT_TO_ZERO_ADDRESS();
                    error ERC1155_BURN_FROM_ZERO_ADDRESS();
                    error ERC1155_BURN_AMOUNT_EXCEEDS_BALANCE();
                    error ERC1155_SETTING_APPROVAL_FOR_SELF();
                    error ERC1155_ERC1155RECEIVER_REJECTED_TOKENS();
                    error ERC1155_TRANSFER_TO_NON_ERC1155RECEIVER_IMPLEMENTER();
                    /**
                     * @dev Implementation of the basic standard multi-token.
                     * See https://eips.ethereum.org/EIPS/eip-1155
                     * Originally based on code by Enjin: https://github.com/enjin/erc-1155
                     *
                     * _Available since v3.1._
                     */
                    contract ERC1155Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC1155Upgradeable, IERC1155MetadataURIUpgradeable {
                        using AddressUpgradeable for address;
                        // Mapping from token ID to account balances
                        mapping(uint256 => mapping(address => uint256)) private _balances;
                        // Mapping from account to operator approvals
                        mapping(address => mapping(address => bool)) private _operatorApprovals;
                        // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
                        string private _uri;
                        /**
                         * @dev See {_setURI}.
                         */
                        function __ERC1155_init(string memory uri_) internal onlyInitializing {
                            __ERC1155_init_unchained(uri_);
                        }
                        function __ERC1155_init_unchained(string memory uri_) internal onlyInitializing {
                            _setURI(uri_);
                        }
                        /**
                         * @dev See {IERC165-supportsInterface}.
                         */
                        function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) {
                            return
                                interfaceId == type(IERC1155Upgradeable).interfaceId ||
                                interfaceId == type(IERC1155MetadataURIUpgradeable).interfaceId ||
                                super.supportsInterface(interfaceId);
                        }
                        /**
                         * @dev See {IERC1155MetadataURI-uri}.
                         *
                         * This implementation returns the same URI for *all* token types. It relies
                         * on the token type ID substitution mechanism
                         * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
                         *
                         * Clients calling this function must replace the `\\{id\\}` substring with the
                         * actual token type ID.
                         */
                        function uri(uint256) public view virtual override returns (string memory) {
                            return _uri;
                        }
                        /**
                         * @dev See {IERC1155-balanceOf}.
                         *
                         * Requirements:
                         *
                         * - `account` cannot be the zero address.
                         */
                        function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
                            if (account == address(0)) {
                                revert ERC1155_ADDRESS_ZERO_IS_NOT_A_VALID_OWNER();
                            }
                            return _balances[id][account];
                        }
                        /**
                         * @dev See {IERC1155-balanceOfBatch}.
                         *
                         * Requirements:
                         *
                         * - `accounts` and `ids` must have the same length.
                         */
                        function balanceOfBatch(
                            address[] memory accounts,
                            uint256[] memory ids
                        ) public view virtual override returns (uint256[] memory batchBalances) {
                            uint256 numAccounts = accounts.length;
                            if (numAccounts != ids.length) {
                                revert ERC1155_ACCOUNTS_AND_IDS_LENGTH_MISMATCH();
                            }
                            batchBalances = new uint256[](numAccounts);
                            unchecked {
                                for (uint256 i; i < numAccounts; ++i) {
                                    batchBalances[i] = balanceOf(accounts[i], ids[i]);
                                }
                            }
                        }
                        /**
                         * @dev See {IERC1155-setApprovalForAll}.
                         */
                        function setApprovalForAll(address operator, bool approved) public virtual override {
                            _setApprovalForAll(_msgSender(), operator, approved);
                        }
                        /**
                         * @dev See {IERC1155-isApprovedForAll}.
                         */
                        function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
                            return _operatorApprovals[account][operator];
                        }
                        /**
                         * @dev See {IERC1155-safeTransferFrom}.
                         */
                        function safeTransferFrom(
                            address from,
                            address to,
                            uint256 id,
                            uint256 amount,
                            bytes memory data
                        ) public virtual override {
                            if (from != _msgSender() && !isApprovedForAll(from, _msgSender())) {
                                revert ERC1155_CALLER_IS_NOT_TOKEN_OWNER_OR_APPROVED();
                            }
                            _safeTransferFrom(from, to, id, amount, data);
                        }
                        /**
                         * @dev See {IERC1155-safeBatchTransferFrom}.
                         */
                        function safeBatchTransferFrom(
                            address from,
                            address to,
                            uint256[] memory ids,
                            uint256[] memory amounts,
                            bytes memory data
                        ) public virtual override {
                            if (from != _msgSender() && !isApprovedForAll(from, _msgSender())) {
                                revert ERC1155_CALLER_IS_NOT_TOKEN_OWNER_OR_APPROVED();
                            }
                            _safeBatchTransferFrom(from, to, ids, amounts, data);
                        }
                        /**
                         * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
                         *
                         * Emits a {TransferSingle} event.
                         *
                         * Requirements:
                         *
                         * - `to` cannot be the zero address.
                         * - `from` must have a balance of tokens of type `id` of at least `amount`.
                         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
                         * acceptance magic value.
                         */
                        function _safeTransferFrom(
                            address from,
                            address to,
                            uint256 id,
                            uint256 amount,
                            bytes memory data
                        ) internal virtual {
                            if (to == address(0)) {
                                revert ERC1155_TRANSFER_TO_ZERO_ADDRESS();
                            }
                            address operator = _msgSender();
                            _beforeTokenTransfer(operator, from, to, id, amount, data);
                            uint256 fromBalance = _balances[id][from];
                            if (fromBalance < amount) {
                                revert ERC1155_INSUFFICIENT_BALANCE_FOR_TRANSFER();
                            }
                            unchecked {
                                _balances[id][from] = fromBalance - amount;
                            }
                            _balances[id][to] += amount;
                            emit TransferSingle(operator, from, to, id, amount);
                            _afterTokenTransfer(operator, from, to, id, amount, data);
                            _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
                        }
                        /**
                         * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
                         *
                         * Emits a {TransferBatch} event.
                         *
                         * Requirements:
                         *
                         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
                         * acceptance magic value.
                         */
                        function _safeBatchTransferFrom(
                            address from,
                            address to,
                            uint256[] memory ids,
                            uint256[] memory amounts,
                            bytes memory data
                        ) internal virtual {
                            uint256 numIds = ids.length;
                            if (numIds != amounts.length) {
                                revert ERC1155_ACCOUNTS_AND_IDS_LENGTH_MISMATCH();
                            }
                            if (to == address(0)) {
                                revert ERC1155_TRANSFER_TO_ZERO_ADDRESS();
                            }
                            address operator = _msgSender();
                            _beforeBatchTokenTransfer(operator, from, to, ids, amounts, data);
                            uint256 id;
                            uint256 amount;
                            uint256 fromBalance;
                            for (uint256 i; i < numIds; ) {
                                id = ids[i];
                                amount = amounts[i];
                                fromBalance = _balances[id][from];
                                if (fromBalance < amount) {
                                    revert ERC1155_INSUFFICIENT_BALANCE_FOR_TRANSFER();
                                }
                                _balances[id][to] += amount;
                                unchecked {
                                    _balances[id][from] = fromBalance - amount;
                                    ++i;
                                }
                            }
                            emit TransferBatch(operator, from, to, ids, amounts);
                            _afterBatchTokenTransfer(operator, from, to, ids, amounts, data);
                            _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
                        }
                        /**
                         * @dev Sets a new URI for all token types, by relying on the token type ID
                         * substitution mechanism
                         * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
                         *
                         * By this mechanism, any occurrence of the `\\{id\\}` substring in either the
                         * URI or any of the amounts in the JSON file at said URI will be replaced by
                         * clients with the token type ID.
                         *
                         * For example, the `https://token-cdn-domain/\\{id\\}.json` URI would be
                         * interpreted by clients as
                         * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
                         * for token type ID 0x4cce0.
                         *
                         * See {uri}.
                         *
                         * Because these URIs cannot be meaningfully represented by the {URI} event,
                         * this function emits no events.
                         */
                        function _setURI(string memory newuri) internal virtual {
                            _uri = newuri;
                        }
                        /**
                         * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
                         *
                         * Emits a {TransferSingle} event.
                         *
                         * Requirements:
                         *
                         * - `to` cannot be the zero address.
                         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
                         * acceptance magic value.
                         */
                        function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual {
                            if (to == address(0)) {
                                revert ERC1155_MINT_TO_ZERO_ADDRESS();
                            }
                            address operator = _msgSender();
                            _beforeTokenTransfer(operator, address(0), to, id, amount, data);
                            _balances[id][to] += amount;
                            emit TransferSingle(operator, address(0), to, id, amount);
                            _afterTokenTransfer(operator, address(0), to, id, amount, data);
                            _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
                        }
                        /**
                         * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
                         *
                         * Emits a {TransferBatch} event.
                         *
                         * Requirements:
                         *
                         * - `ids` and `amounts` must have the same length.
                         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
                         * acceptance magic value.
                         */
                        function _mintBatch(
                            address to,
                            uint256[] memory ids,
                            uint256[] memory amounts,
                            bytes memory data
                        ) internal virtual {
                            if (to == address(0)) {
                                revert ERC1155_MINT_TO_ZERO_ADDRESS();
                            }
                            uint256 numIds = ids.length;
                            if (numIds != amounts.length) {
                                revert ERC1155_IDS_AND_AMOUNTS_LENGTH_MISMATCH();
                            }
                            address operator = _msgSender();
                            _beforeBatchTokenTransfer(operator, address(0), to, ids, amounts, data);
                            for (uint256 i; i < numIds; ) {
                                _balances[ids[i]][to] += amounts[i];
                                unchecked {
                                    ++i;
                                }
                            }
                            emit TransferBatch(operator, address(0), to, ids, amounts);
                            _afterBatchTokenTransfer(operator, address(0), to, ids, amounts, data);
                            _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
                        }
                        /**
                         * @dev Destroys `amount` tokens of token type `id` from `from`
                         *
                         * Emits a {TransferSingle} event.
                         *
                         * Requirements:
                         *
                         * - `from` cannot be the zero address.
                         * - `from` must have at least `amount` tokens of token type `id`.
                         */
                        function _burn(address from, uint256 id, uint256 amount) internal virtual {
                            if (from == address(0)) {
                                revert ERC1155_BURN_FROM_ZERO_ADDRESS();
                            }
                            address operator = _msgSender();
                            _beforeTokenTransfer(operator, from, address(0), id, amount, "");
                            uint256 fromBalance = _balances[id][from];
                            if (fromBalance < amount) {
                                revert ERC1155_BURN_AMOUNT_EXCEEDS_BALANCE();
                            }
                            unchecked {
                                _balances[id][from] = fromBalance - amount;
                            }
                            emit TransferSingle(operator, from, address(0), id, amount);
                            _afterTokenTransfer(operator, from, address(0), id, amount, "");
                        }
                        /**
                         * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
                         *
                         * Emits a {TransferBatch} event.
                         *
                         * Requirements:
                         *
                         * - `ids` and `amounts` must have the same length.
                         */
                        function _burnBatch(address from, uint256[] memory ids, uint256[] memory amounts) internal virtual {
                            if (from == address(0)) {
                                revert ERC1155_BURN_FROM_ZERO_ADDRESS();
                            }
                            uint256 numIds = ids.length;
                            if (numIds != amounts.length) {
                                revert ERC1155_IDS_AND_AMOUNTS_LENGTH_MISMATCH();
                            }
                            address operator = _msgSender();
                            _beforeBatchTokenTransfer(operator, from, address(0), ids, amounts, "");
                            uint256 id;
                            uint256 amount;
                            uint256 fromBalance;
                            for (uint256 i; i < numIds; ) {
                                id = ids[i];
                                amount = amounts[i];
                                fromBalance = _balances[id][from];
                                if (fromBalance < amount) {
                                    revert ERC1155_BURN_AMOUNT_EXCEEDS_BALANCE();
                                }
                                unchecked {
                                    _balances[id][from] = fromBalance - amount;
                                    ++i;
                                }
                            }
                            emit TransferBatch(operator, from, address(0), ids, amounts);
                            _afterBatchTokenTransfer(operator, from, address(0), ids, amounts, "");
                        }
                        /**
                         * @dev Approve `operator` to operate on all of `owner` tokens
                         *
                         * Emits an {ApprovalForAll} event.
                         */
                        function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
                            if (owner == operator) {
                                revert ERC1155_SETTING_APPROVAL_FOR_SELF();
                            }
                            _operatorApprovals[owner][operator] = approved;
                            emit ApprovalForAll(owner, operator, approved);
                        }
                        /**
                         * @dev Hook that is called before a single token transfer.
                         */
                        function _beforeTokenTransfer(
                            address operator,
                            address from,
                            address to,
                            uint256 id,
                            uint256 amount,
                            bytes memory data
                        ) internal virtual { }
                        /**
                         * @dev Hook that is called before a batch token transfer.
                         */
                        function _beforeBatchTokenTransfer(
                            address operator,
                            address from,
                            address to,
                            uint256[] memory ids,
                            uint256[] memory amounts,
                            bytes memory data
                        ) internal virtual {}
                        /**
                         * @dev Hook that is called after a single token transfer.
                         */
                        function _afterTokenTransfer(
                            address operator,
                            address from,
                            address to,
                            uint256 id,
                            uint256 amount,
                            bytes memory data
                        ) internal virtual {}
                        /**
                         * @dev Hook that is called after a batch token transfer.
                         */
                        function _afterBatchTokenTransfer(
                            address operator,
                            address from,
                            address to,
                            uint256[] memory ids,
                            uint256[] memory amounts,
                            bytes memory data
                        ) internal virtual {}
                        function _doSafeTransferAcceptanceCheck(
                            address operator,
                            address from,
                            address to,
                            uint256 id,
                            uint256 amount,
                            bytes memory data
                        ) private {
                            if (to.isContract()) {
                                try IERC1155ReceiverUpgradeable(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
                                    if (response != IERC1155ReceiverUpgradeable.onERC1155Received.selector) {
                                        revert ERC1155_ERC1155RECEIVER_REJECTED_TOKENS();
                                    }
                                } catch Error(string memory reason) {
                                    revert(reason);
                                } catch {
                                    revert ERC1155_TRANSFER_TO_NON_ERC1155RECEIVER_IMPLEMENTER();
                                }
                            }
                        }
                        function _doSafeBatchTransferAcceptanceCheck(
                            address operator,
                            address from,
                            address to,
                            uint256[] memory ids,
                            uint256[] memory amounts,
                            bytes memory data
                        ) private {
                            if (to.isContract()) {
                                try IERC1155ReceiverUpgradeable(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
                                    bytes4 response
                                ) {
                                    if (response != IERC1155ReceiverUpgradeable.onERC1155BatchReceived.selector) {
                                        revert ERC1155_ERC1155RECEIVER_REJECTED_TOKENS();
                                    }
                                } catch Error(string memory reason) {
                                    revert(reason);
                                } catch {
                                    revert ERC1155_TRANSFER_TO_NON_ERC1155RECEIVER_IMPLEMENTER();
                                }
                            }
                        }
                        /**
                         * @dev This empty reserved space is put in place to allow future versions to add new
                         * variables without shifting down storage in the inheritance chain.
                         * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                         */
                        uint256[47] private __gap;
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
                    pragma solidity ^0.8.0;
                    import "../proxy/utils/Initializable.sol";
                    /**
                     * @dev Contract module that helps prevent reentrant calls to a function.
                     *
                     * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
                     * available, which can be applied to functions to make sure there are no nested
                     * (reentrant) calls to them.
                     *
                     * Note that because there is a single `nonReentrant` guard, functions marked as
                     * `nonReentrant` may not call one another. This can be worked around by making
                     * those functions `private`, and then adding `external` `nonReentrant` entry
                     * points to them.
                     *
                     * TIP: If you would like to learn more about reentrancy and alternative ways
                     * to protect against it, check out our blog post
                     * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
                     */
                    abstract contract ReentrancyGuardUpgradeable is Initializable {
                        // Booleans are more expensive than uint256 or any type that takes up a full
                        // word because each write operation emits an extra SLOAD to first read the
                        // slot's contents, replace the bits taken up by the boolean, and then write
                        // back. This is the compiler's defense against contract upgrades and
                        // pointer aliasing, and it cannot be disabled.
                        // The values being non-zero value makes deployment a bit more expensive,
                        // but in exchange the refund on every call to nonReentrant will be lower in
                        // amount. Since refunds are capped to a percentage of the total
                        // transaction's gas, it is best to keep them low in cases like this one, to
                        // increase the likelihood of the full refund coming into effect.
                        uint256 private constant _NOT_ENTERED = 1;
                        uint256 private constant _ENTERED = 2;
                        uint256 private _status;
                        function __ReentrancyGuard_init() internal onlyInitializing {
                            __ReentrancyGuard_init_unchained();
                        }
                        function __ReentrancyGuard_init_unchained() internal onlyInitializing {
                            _status = _NOT_ENTERED;
                        }
                        /**
                         * @dev Prevents a contract from calling itself, directly or indirectly.
                         * Calling a `nonReentrant` function from another `nonReentrant`
                         * function is not supported. It is possible to prevent this from happening
                         * by making the `nonReentrant` function external, and making it call a
                         * `private` function that does the actual work.
                         */
                        modifier nonReentrant() {
                            _nonReentrantBefore();
                            _;
                            _nonReentrantAfter();
                        }
                        function _nonReentrantBefore() private {
                            // On the first call to nonReentrant, _status will be _NOT_ENTERED
                            require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                            // Any calls to nonReentrant after this point will fail
                            _status = _ENTERED;
                        }
                        function _nonReentrantAfter() private {
                            // By storing the original value once again, a refund is triggered (see
                            // https://eips.ethereum.org/EIPS/eip-2200)
                            _status = _NOT_ENTERED;
                        }
                        /**
                         * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
                         * `nonReentrant` function in the call stack.
                         */
                        function _reentrancyGuardEntered() internal view returns (bool) {
                            return _status == _ENTERED;
                        }
                        /**
                         * @dev This empty reserved space is put in place to allow future versions to add new
                         * variables without shifting down storage in the inheritance chain.
                         * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                         */
                        uint256[49] private __gap;
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol)
                    pragma solidity ^0.8.0;
                    import "../../interfaces/draft-IERC1822Upgradeable.sol";
                    import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
                    import "./Initializable.sol";
                    error FUNCTION_MUST_BE_CALLED_THROUGH_DELEGATECALL();
                    error FUNCTION_MUST_BE_CALLED_THROUGH_ACTIVE_PROXY();
                    error UUPS_UPGRADEABLE_MUST_NOT_BE_CALLED_THROUGH_DELEGATECALL();
                    /**
                     * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
                     * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
                     *
                     * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
                     * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
                     * `UUPSUpgradeable` with a custom implementation of upgrades.
                     *
                     * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
                     *
                     * _Available since v4.1._
                     */
                    abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
                        function __UUPSUpgradeable_init() internal onlyInitializing {
                        }
                        function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
                        }
                        /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
                        address private immutable __self = address(this);
                        /**
                         * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
                         * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
                         * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
                         * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
                         * fail.
                         */
                        modifier onlyProxy() {
                            if (address(this) == __self) {
                                revert FUNCTION_MUST_BE_CALLED_THROUGH_DELEGATECALL();
                            }
                            if (_getImplementation() != __self) {
                                revert FUNCTION_MUST_BE_CALLED_THROUGH_ACTIVE_PROXY();
                            }
                            _;
                        }
                        /**
                         * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
                         * callable on the implementing contract but not through proxies.
                         */
                        modifier notDelegated() {
                            if (address(this) != __self) {
                                revert UUPS_UPGRADEABLE_MUST_NOT_BE_CALLED_THROUGH_DELEGATECALL();
                            }
                            _;
                        }
                        /**
                         * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
                         * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
                         *
                         * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                         * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                         * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
                         */
                        function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
                            return _IMPLEMENTATION_SLOT;
                        }
                        /**
                         * @dev Upgrade the implementation of the proxy to `newImplementation`.
                         *
                         * Calls {_authorizeUpgrade}.
                         *
                         * Emits an {Upgraded} event.
                         *
                         * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                         */
                        function upgradeTo(address newImplementation) public virtual onlyProxy {
                            _authorizeUpgrade(newImplementation);
                            _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
                        }
                        /**
                         * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
                         * encoded in `data`.
                         *
                         * Calls {_authorizeUpgrade}.
                         *
                         * Emits an {Upgraded} event.
                         *
                         * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                         */
                        function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
                            _authorizeUpgrade(newImplementation);
                            _upgradeToAndCallUUPS(newImplementation, data, true);
                        }
                        /**
                         * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                         * {upgradeTo} and {upgradeToAndCall}.
                         *
                         * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
                         *
                         * ```solidity
                         * function _authorizeUpgrade(address) internal override onlyOwner {}
                         * ```
                         */
                        function _authorizeUpgrade(address newImplementation) internal virtual;
                        /**
                         * @dev This empty reserved space is put in place to allow future versions to add new
                         * variables without shifting down storage in the inheritance chain.
                         * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                         */
                        uint256[50] private __gap;
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155MetadataURI.sol)
                    pragma solidity ^0.8.0;
                    import "../token/ERC1155/extensions/IERC1155MetadataURIUpgradeable.sol";
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)
                    pragma solidity ^0.8.0;
                    import "../utils/introspection/IERC165Upgradeable.sol";
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    /// @title IProtocolRewards
                    /// @notice The interface for deposits & withdrawals of protocol rewards
                    interface IProtocolRewards {
                        event RewardsDeposit(
                            address indexed creator,
                            address indexed createReferral,
                            address indexed mintReferral,
                            address firstMinter,
                            address zora,
                            address from,
                            uint256 creatorReward,
                            uint256 createReferralReward,
                            uint256 mintReferralReward,
                            uint256 firstMinterReward,
                            uint256 zoraReward
                        );
                        event Deposit(address indexed from, address indexed to, uint256 amount, string comment);
                        event Withdraw(address indexed from, address indexed to, uint256 amount);
                        error ADDRESS_ZERO();
                        error ARRAY_LENGTH_MISMATCH();
                        error INVALID_DEPOSIT();
                        error INVALID_SIGNATURE();
                        error INVALID_WITHDRAW();
                        error SIGNATURE_DEADLINE_EXPIRED();
                        error TRANSFER_FAILED();
                        function deposit(address to, string calldata comment) external payable;
                        function depositBatch(address[] calldata recipients, uint256[] calldata amounts, string calldata comment) external payable;
                        function depositRewards(
                            address creator,
                            uint256 creatorReward,
                            address createReferral,
                            uint256 createReferralReward,
                            address mintReferral,
                            uint256 mintReferralReward,
                            address firstMinter,
                            uint256 firstMinterReward,
                            address zora,
                            uint256 zoraReward
                        ) external payable;
                        function withdraw(address to, uint256 amount) external;
                        function withdrawWithSig(address from, address to, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {RewardSplits} from "../RewardSplits.sol";
                    /// @notice The base logic for handling Zora ERC-1155 protocol rewards
                    /// @dev Used in https://github.com/ourzora/zora-1155-contracts/blob/main/src/nft/ZoraCreator1155Impl.sol
                    abstract contract ERC1155Rewards is RewardSplits {
                        constructor(address _protocolRewards, address _zoraRewardRecipient) payable RewardSplits(_protocolRewards, _zoraRewardRecipient) {}
                        function _handleRewardsAndGetValueSent(
                            uint256 msgValue,
                            uint256 numTokens,
                            address creator,
                            address createReferral,
                            address mintReferral
                        ) internal returns (uint256) {
                            uint256 totalReward = computeTotalReward(numTokens);
                            if (msgValue < totalReward) {
                                revert INVALID_ETH_AMOUNT();
                            } else if (msgValue == totalReward) {
                                _depositFreeMintRewards(totalReward, numTokens, creator, createReferral, mintReferral);
                                return 0;
                            } else {
                                _depositPaidMintRewards(totalReward, numTokens, creator, createReferral, mintReferral);
                                unchecked {
                                    return msgValue - totalReward;
                                }
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    contract ERC1155RewardsStorageV1 {
                        mapping(uint256 => address) public createReferrals;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IERC165Upgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC165Upgradeable.sol";
                    import {IERC1155MetadataURIUpgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC1155MetadataURIUpgradeable.sol";
                    import {IZoraCreator1155TypesV1} from "../nft/IZoraCreator1155TypesV1.sol";
                    import {IRenderer1155} from "../interfaces/IRenderer1155.sol";
                    import {IMinter1155} from "../interfaces/IMinter1155.sol";
                    import {IOwnable} from "../interfaces/IOwnable.sol";
                    import {IVersionedContract} from "./IVersionedContract.sol";
                    import {ICreatorRoyaltiesControl} from "../interfaces/ICreatorRoyaltiesControl.sol";
                    /*
                                 ░░░░░░░░░░░░░░              
                            ░░▒▒░░░░░░░░░░░░░░░░░░░░        
                          ░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░      
                        ░░▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░    
                       ░▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░    
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░░  
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░░░  
                      ░▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░  
                      ░▓▓▓▓▓▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░  
                       ░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░  
                        ░░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░    
                        ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▒░░    
                          ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░      
                              ░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░          
                                   OURS TRULY,
                     */
                    /// @notice Main interface for the ZoraCreator1155 contract
                    /// @author @iainnash / @tbtstl
                    interface IZoraCreator1155 is IZoraCreator1155TypesV1, IVersionedContract, IOwnable, IERC1155MetadataURIUpgradeable {
                        function PERMISSION_BIT_ADMIN() external returns (uint256);
                        function PERMISSION_BIT_MINTER() external returns (uint256);
                        function PERMISSION_BIT_SALES() external returns (uint256);
                        function PERMISSION_BIT_METADATA() external returns (uint256);
                        /// @notice Used to label the configuration update type
                        enum ConfigUpdate {
                            OWNER,
                            FUNDS_RECIPIENT,
                            TRANSFER_HOOK
                        }
                        event ConfigUpdated(address indexed updater, ConfigUpdate indexed updateType, ContractConfig newConfig);
                        event UpdatedToken(address indexed from, uint256 indexed tokenId, TokenData tokenData);
                        event SetupNewToken(uint256 indexed tokenId, address indexed sender, string newURI, uint256 maxSupply);
                        function setOwner(address newOwner) external;
                        event ContractRendererUpdated(IRenderer1155 renderer);
                        event ContractMetadataUpdated(address indexed updater, string uri, string name);
                        event Purchased(address indexed sender, address indexed minter, uint256 indexed tokenId, uint256 quantity, uint256 value);
                        error TokenIdMismatch(uint256 expected, uint256 actual);
                        error UserMissingRoleForToken(address user, uint256 tokenId, uint256 role);
                        error Config_TransferHookNotSupported(address proposedAddress);
                        error Mint_InsolventSaleTransfer();
                        error Mint_ValueTransferFail();
                        error Mint_TokenIDMintNotAllowed();
                        error Mint_UnknownCommand();
                        error Burn_NotOwnerOrApproved(address operator, address user);
                        error NewOwnerNeedsToBeAdmin();
                        error Sale_CannotCallNonSalesContract(address targetContract);
                        error CallFailed(bytes reason);
                        error Renderer_NotValidRendererContract();
                        error ETHWithdrawFailed(address recipient, uint256 amount);
                        error FundsWithdrawInsolvent(uint256 amount, uint256 contractValue);
                        error ProtocolRewardsWithdrawFailed(address caller, address recipient, uint256 amount);
                        error CannotMintMoreTokens(uint256 tokenId, uint256 quantity, uint256 totalMinted, uint256 maxSupply);
                        /// @notice Only allow minting one token id at time
                        /// @dev Mint contract function that calls the underlying sales function for commands
                        /// @param minter Address for the minter
                        /// @param tokenId tokenId to mint, set to 0 for new tokenId
                        /// @param quantity to mint
                        /// @param minterArguments calldata for the minter contracts
                        function mint(IMinter1155 minter, uint256 tokenId, uint256 quantity, bytes calldata minterArguments) external payable;
                        function adminMint(address recipient, uint256 tokenId, uint256 quantity, bytes memory data) external;
                        function adminMintBatch(address recipient, uint256[] memory tokenIds, uint256[] memory quantities, bytes memory data) external;
                        function burnBatch(address user, uint256[] calldata tokenIds, uint256[] calldata amounts) external;
                        /// @notice Contract call to setupNewToken
                        /// @param tokenURI URI for the token
                        /// @param maxSupply maxSupply for the token, set to 0 for open edition
                        function setupNewToken(string memory tokenURI, uint256 maxSupply) external returns (uint256 tokenId);
                        function updateTokenURI(uint256 tokenId, string memory _newURI) external;
                        function updateContractMetadata(string memory _newURI, string memory _newName) external;
                        // Public interface for `setTokenMetadataRenderer(uint256, address) has been deprecated.
                        function contractURI() external view returns (string memory);
                        function assumeLastTokenIdMatches(uint256 tokenId) external;
                        function updateRoyaltiesForToken(uint256 tokenId, ICreatorRoyaltiesControl.RoyaltyConfiguration memory royaltyConfiguration) external;
                        function addPermission(uint256 tokenId, address user, uint256 permissionBits) external;
                        function removePermission(uint256 tokenId, address user, uint256 permissionBits) external;
                        function isAdminOrRole(address user, uint256 tokenId, uint256 role) external view returns (bool);
                        function getTokenInfo(uint256 tokenId) external view returns (TokenData memory);
                        function callRenderer(uint256 tokenId, bytes memory data) external;
                        function callSale(uint256 tokenId, IMinter1155 salesConfig, bytes memory data) external;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {ICreatorRoyaltiesControl} from "../interfaces/ICreatorRoyaltiesControl.sol";
                    interface IZoraCreator1155Initializer {
                        function initialize(
                            string memory contractName,
                            string memory newContractURI,
                            ICreatorRoyaltiesControl.RoyaltyConfiguration memory defaultRoyaltyConfiguration,
                            address payable defaultAdmin,
                            bytes[] calldata setupActions
                        ) external;
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
                    pragma solidity ^0.8.0;
                    /**
                     * @dev Standard math utilities missing in the Solidity language.
                     */
                    library MathUpgradeable {
                        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, "Math: mulDiv overflow");
                                ///////////////////////////////////////////////
                                // 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 256, following the selected rounding direction, of a positive value.
                         * Returns 0 if given 0.
                         */
                        function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
                            unchecked {
                                uint256 result = log256(value);
                                return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IVersionedContract} from "../interfaces/IVersionedContract.sol";
                    /// @title ContractVersionBase
                    /// @notice Base contract for versioning contracts
                    contract ContractVersionBase is IVersionedContract {
                        /// @notice The version of the contract
                        function contractVersion() external pure override returns (string memory) {
                            return "1.4.0";
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {CreatorPermissionStorageV1} from "./CreatorPermissionStorageV1.sol";
                    import {ICreatorPermissionControl} from "../interfaces/ICreatorPermissionControl.sol";
                    /// Imagine. Mint. Enjoy.
                    /// @author @iainnash / @tbtstl
                    contract CreatorPermissionControl is CreatorPermissionStorageV1, ICreatorPermissionControl {
                        /// @notice Check if the user has the given permissions
                        /// @dev if multiple permissions are passed in this checks for all the permissions requested
                        /// @return true or false if all of the passed in permissions apply
                        function _hasPermissions(uint256 tokenId, address user, uint256 permissionBits) internal view returns (bool) {
                            // Does a bitwise and and checks if any of those permissions match
                            return permissions[tokenId][user] & permissionBits == permissionBits;
                        }
                        /// @notice Check if the user has any of the given permissions
                        /// @dev if multiple permissions are passed in this checks for any one of those permissions
                        /// @return true or false if any of the passed in permissions apply
                        function _hasAnyPermission(uint256 tokenId, address user, uint256 permissionBits) internal view returns (bool) {
                            // Does a bitwise and and checks if any of those permissions match
                            return permissions[tokenId][user] & permissionBits > 0;
                        }
                        /// @return raw permission bits for the given user
                        function getPermissions(uint256 tokenId, address user) external view returns (uint256) {
                            return permissions[tokenId][user];
                        }
                        /// @notice addPermission – internal function to add a set of permission bits to a user
                        /// @param tokenId token id to add the permission to (0 indicates contract-wide add)
                        /// @param user user to update permissions for
                        /// @param permissionBits bits to add permissions to
                        function _addPermission(uint256 tokenId, address user, uint256 permissionBits) internal {
                            uint256 tokenPermissions = permissions[tokenId][user];
                            tokenPermissions |= permissionBits;
                            permissions[tokenId][user] = tokenPermissions;
                            emit UpdatedPermissions(tokenId, user, tokenPermissions);
                        }
                        /// @notice _clearPermission clear permissions for user
                        /// @param tokenId token id to clear permission from (0 indicates contract-wide action)
                        function _clearPermissions(uint256 tokenId, address user) internal {
                            permissions[tokenId][user] = 0;
                            emit UpdatedPermissions(tokenId, user, 0);
                        }
                        /// @notice _removePermission removes permissions for user
                        /// @param tokenId token id to clear permission from (0 indicates contract-wide action)
                        /// @param user user to manage permissions for
                        /// @param permissionBits set of permission bits to remove
                        function _removePermission(uint256 tokenId, address user, uint256 permissionBits) internal {
                            uint256 tokenPermissions = permissions[tokenId][user];
                            tokenPermissions &= ~permissionBits;
                            permissions[tokenId][user] = tokenPermissions;
                            emit UpdatedPermissions(tokenId, user, tokenPermissions);
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {CreatorRendererStorageV1} from "./CreatorRendererStorageV1.sol";
                    import {IRenderer1155} from "../interfaces/IRenderer1155.sol";
                    import {ITransferHookReceiver} from "../interfaces/ITransferHookReceiver.sol";
                    import {SharedBaseConstants} from "../shared/SharedBaseConstants.sol";
                    /// @title CreatorRendererControl
                    /// @notice Contract for managing the renderer of an 1155 contract
                    abstract contract CreatorRendererControl is CreatorRendererStorageV1, SharedBaseConstants {
                        function _setRenderer(uint256 tokenId, IRenderer1155 renderer) internal {
                            customRenderers[tokenId] = renderer;
                            if (address(renderer) != address(0)) {
                                if (!renderer.supportsInterface(type(IRenderer1155).interfaceId)) {
                                    revert RendererNotValid(address(renderer));
                                }
                            }
                            emit RendererUpdated({tokenId: tokenId, renderer: address(renderer), user: msg.sender});
                        }
                        /// @notice Return the renderer for a given token
                        /// @dev Returns address 0 for no results
                        /// @param tokenId The token to get the renderer for
                        function getCustomRenderer(uint256 tokenId) public view returns (IRenderer1155 customRenderer) {
                            customRenderer = customRenderers[tokenId];
                            if (address(customRenderer) == address(0)) {
                                customRenderer = customRenderers[CONTRACT_BASE_ID];
                            }
                        }
                        /// @notice Function called to render when an empty tokenURI exists on the contract
                        function _render(uint256 tokenId) internal view returns (string memory) {
                            return getCustomRenderer(tokenId).uri(tokenId);
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {CreatorRoyaltiesStorageV1} from "./CreatorRoyaltiesStorageV1.sol";
                    import {ICreatorRoyaltiesControl} from "../interfaces/ICreatorRoyaltiesControl.sol";
                    import {SharedBaseConstants} from "../shared/SharedBaseConstants.sol";
                    import {IERC2981} from "@openzeppelin/contracts/interfaces/IERC2981.sol";
                    /// Imagine. Mint. Enjoy.
                    /// @title CreatorRoyaltiesControl
                    /// @author ZORA @iainnash / @tbtstl
                    /// @notice Contract for managing the royalties of an 1155 contract
                    abstract contract CreatorRoyaltiesControl is CreatorRoyaltiesStorageV1, SharedBaseConstants {
                        uint256 immutable ROYALTY_BPS_TO_PERCENT = 10_000;
                        /// @notice The royalty information for a given token.
                        /// @param tokenId The token ID to get the royalty information for.
                        function getRoyalties(uint256 tokenId) public view returns (RoyaltyConfiguration memory) {
                            if (royalties[tokenId].royaltyRecipient != address(0)) {
                                return royalties[tokenId];
                            }
                            // Otherwise, return default.
                            return royalties[CONTRACT_BASE_ID];
                        }
                        /// @notice Returns the royalty information for a given token.
                        /// @param tokenId The token ID to get the royalty information for.
                        /// @param salePrice The sale price of the NFT asset specified by tokenId
                        function royaltyInfo(uint256 tokenId, uint256 salePrice) public view returns (address receiver, uint256 royaltyAmount) {
                            RoyaltyConfiguration memory config = getRoyalties(tokenId);
                            royaltyAmount = (config.royaltyBPS * salePrice) / ROYALTY_BPS_TO_PERCENT;
                            receiver = config.royaltyRecipient;
                        }
                        /// @notice Returns the supply royalty information for a given token.
                        /// @param tokenId The token ID to get the royalty information for.
                        /// @param mintAmount The amount of tokens being minted.
                        /// @param totalSupply The total supply of the token,
                        function supplyRoyaltyInfo(uint256 tokenId, uint256 totalSupply, uint256 mintAmount) public view returns (address receiver, uint256 royaltyAmount) {
                            RoyaltyConfiguration memory config = getRoyalties(tokenId);
                            if (config.royaltyMintSchedule == 0) {
                                return (config.royaltyRecipient, 0);
                            }
                            uint256 totalRoyaltyMints = (mintAmount + (totalSupply % config.royaltyMintSchedule)) / (config.royaltyMintSchedule - 1);
                            return (config.royaltyRecipient, totalRoyaltyMints);
                        }
                        function _updateRoyalties(uint256 tokenId, RoyaltyConfiguration memory configuration) internal {
                            // Don't allow 100% supply royalties
                            if (configuration.royaltyMintSchedule == 1) {
                                revert InvalidMintSchedule();
                            }
                            // Don't allow setting royalties to burn address
                            if (configuration.royaltyRecipient == address(0) && (configuration.royaltyMintSchedule > 0 || configuration.royaltyBPS > 0)) {
                                revert InvalidMintSchedule();
                            }
                            royalties[tokenId] = configuration;
                            emit UpdatedRoyalties(tokenId, msg.sender, configuration);
                        }
                        function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
                            return interfaceId == type(IERC2981).interfaceId;
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    /// @notice Creator Commands used by minter modules passed back to the main modules
                    interface ICreatorCommands {
                        /// @notice This enum is used to define supported creator action types.
                        /// This can change in the future
                        enum CreatorActions {
                            // No operation - also the default for mintings that may not return a command
                            NO_OP,
                            // Send ether
                            SEND_ETH,
                            // Mint operation
                            MINT
                        }
                        /// @notice This command is for
                        struct Command {
                            // Method for operation
                            CreatorActions method;
                            // Arguments used for this operation
                            bytes args;
                        }
                        /// @notice This command set is returned from the minter back to the user
                        struct CommandSet {
                            Command[] commands;
                            uint256 at;
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IERC165Upgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC165Upgradeable.sol";
                    import {ICreatorCommands} from "./ICreatorCommands.sol";
                    /// @notice Minter standard interface
                    /// @dev Minters need to confirm to the ERC165 selector of type(IMinter1155).interfaceId
                    interface IMinter1155 is IERC165Upgradeable {
                        function requestMint(
                            address sender,
                            uint256 tokenId,
                            uint256 quantity,
                            uint256 ethValueSent,
                            bytes calldata minterArguments
                        ) external returns (ICreatorCommands.CommandSet memory commands);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IERC165Upgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC165Upgradeable.sol";
                    /// @dev IERC165 type required
                    interface IRenderer1155 is IERC165Upgradeable {
                        /// @notice Called for assigned tokenId, or when token id is globally set to a renderer
                        /// @dev contract target is assumed to be msg.sender
                        /// @param tokenId token id to get uri for
                        function uri(uint256 tokenId) external view returns (string memory);
                        /// @notice Only called for tokenId == 0
                        /// @dev contract target is assumed to be msg.sender
                        function contractURI() external view returns (string memory);
                        /// @notice Sets up renderer from contract
                        /// @param initData data to setup renderer with
                        /// @dev contract target is assumed to be msg.sender
                        function setup(bytes memory initData) external;
                        // IERC165 type required – set in base helper
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IERC165Upgradeable} from "@zoralabs/openzeppelin-contracts-upgradeable/contracts/interfaces/IERC165Upgradeable.sol";
                    interface ITransferHookReceiver is IERC165Upgradeable {
                        /// @notice Token transfer batch callback
                        /// @param target target contract for transfer
                        /// @param operator operator address for transfer
                        /// @param from user address for amount transferred
                        /// @param to user address for amount transferred
                        /// @param ids list of token ids transferred
                        /// @param amounts list of values transferred
                        /// @param data data as perscribed by 1155 standard
                        function onTokenTransferBatch(
                            address target,
                            address operator,
                            address from,
                            address to,
                            uint256[] memory ids,
                            uint256[] memory amounts,
                            bytes memory data
                        ) external;
                        // IERC165 type required
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    /// @notice Factory Upgrade Gate Admin Factory Implementation – Allows specific contract upgrades as a safety measure
                    interface IFactoryManagedUpgradeGate {
                        /// @notice If an implementation is registered by the Builder DAO as an optional upgrade
                        /// @param baseImpl The base implementation address
                        /// @param upgradeImpl The upgrade implementation address
                        function isRegisteredUpgradePath(address baseImpl, address upgradeImpl) external view returns (bool);
                        /// @notice Called by the Builder DAO to offer implementation upgrades for created DAOs
                        /// @param baseImpls The base implementation addresses
                        /// @param upgradeImpl The upgrade implementation address
                        function registerUpgradePath(address[] memory baseImpls, address upgradeImpl) external;
                        /// @notice Called by the Builder DAO to remove an upgrade
                        /// @param baseImpl The base implementation address
                        /// @param upgradeImpl The upgrade implementation address
                        function removeUpgradePath(address baseImpl, address upgradeImpl) external;
                        event UpgradeRegistered(address indexed baseImpl, address indexed upgradeImpl);
                        event UpgradeRemoved(address indexed baseImpl, address indexed upgradeImpl);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {ILegacyNaming} from "../interfaces/ILegacyNaming.sol";
                    import {LegacyNamingStorageV1} from "./LegacyNamingStorageV1.sol";
                    /// @title LegacyNamingControl
                    /// @notice Contract for managing the name and symbol of an 1155 contract in the legacy naming scheme
                    contract LegacyNamingControl is LegacyNamingStorageV1, ILegacyNaming {
                        /// @notice The name of the contract
                        function name() external view returns (string memory) {
                            return _name;
                        }
                        /// @notice The token symbol of the contract
                        function symbol() external pure returns (string memory) {}
                        function _setName(string memory _newName) internal {
                            _name = _newName;
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {TransferHelperUtils} from "../utils/TransferHelperUtils.sol";
                    import {IMintFeeManager} from "../interfaces/IMintFeeManager.sol";
                    /// @title MintFeeManager
                    /// @notice Manages mint fees for an 1155 contract
                    contract MintFeeManager is IMintFeeManager {
                        uint256 public immutable mintFee;
                        address public immutable mintFeeRecipient;
                        constructor(uint256 _mintFee, address _mintFeeRecipient) {
                            // Set fixed finders fee
                            if (_mintFee >= 0.1 ether) {
                                revert MintFeeCannotBeMoreThanZeroPointOneETH(_mintFee);
                            }
                            if (_mintFeeRecipient == address(0) && _mintFee > 0) {
                                revert CannotSetMintFeeToZeroAddress();
                            }
                            mintFeeRecipient = _mintFeeRecipient;
                            mintFee = _mintFee;
                        }
                        /// @notice Sends the mint fee to the mint fee recipient and returns the amount of ETH remaining that can be used in this transaction
                        /// @param _quantity The amount of toknens being minted
                        function _handleFeeAndGetValueSent(uint256 _quantity) internal returns (uint256 ethValueSent) {
                            ethValueSent = msg.value;
                            // Handle mint fee
                            if (mintFeeRecipient != address(0)) {
                                uint256 totalFee = mintFee * _quantity;
                                ethValueSent -= totalFee;
                                if (!TransferHelperUtils.safeSendETH(mintFeeRecipient, totalFee, TransferHelperUtils.FUNDS_SEND_LOW_GAS_LIMIT)) {
                                    revert CannotSendMintFee(mintFeeRecipient, totalFee);
                                }
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity ^0.8.17;
                    import "@openzeppelin/contracts/utils/Address.sol";
                    /// @title PublicMulticall
                    /// @notice Contract for executing a batch of function calls on this contract
                    abstract contract PublicMulticall {
                        /**
                         * @notice Receives and executes a batch of function calls on this contract.
                         */
                        function multicall(bytes[] calldata data) public virtual returns (bytes[] memory results) {
                            results = new bytes[](data.length);
                            for (uint256 i = 0; i < data.length; i++) {
                                results[i] = Address.functionDelegateCall(address(this), data[i]);
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    contract SharedBaseConstants {
                        uint256 public constant CONTRACT_BASE_ID = 0;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    /// @title TransferHelperUtils
                    /// @notice Helper functions for sending ETH
                    library TransferHelperUtils {
                        /// @dev Gas limit to send funds
                        uint256 internal constant FUNDS_SEND_LOW_GAS_LIMIT = 110_000;
                        // @dev Gas limit to send funds – usable for splits, can use with withdraws
                        uint256 internal constant FUNDS_SEND_NORMAL_GAS_LIMIT = 310_000;
                        /// @notice Sends ETH to a recipient, making conservative estimates to not run out of gas
                        /// @param recipient The address to send ETH to
                        /// @param value The amount of ETH to send
                        function safeSendETH(address recipient, uint256 value, uint256 gasLimit) internal returns (bool success) {
                            (success, ) = recipient.call{value: value, gas: gasLimit}("");
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IZoraCreator1155TypesV1} from "./IZoraCreator1155TypesV1.sol";
                    /*
                                 ░░░░░░░░░░░░░░              
                            ░░▒▒░░░░░░░░░░░░░░░░░░░░        
                          ░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░      
                        ░░▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░    
                       ░▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░    
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░░  
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░░░  
                      ░▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░  
                      ░▓▓▓▓▓▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░  
                       ░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░  
                        ░░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░    
                        ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▒░░    
                          ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░      
                              ░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░          
                                   OURS TRULY,
                        github.com/ourzora/zora-1155-contracts
                     */
                    /// Imagine. Mint. Enjoy.
                    /// @notice Storage for 1155 contract
                    /// @author @iainnash / @tbtstl
                    contract ZoraCreator1155StorageV1 is IZoraCreator1155TypesV1 {
                        /// @notice token data stored for each token
                        mapping(uint256 => TokenData) internal tokens;
                        /// @notice metadata renderer contract for each token
                        mapping(uint256 => address) public metadataRendererContract;
                        /// @notice next token id available when using a linear mint style (default for launch)
                        uint256 public nextTokenId;
                        /// @notice Global contract configuration
                        ContractConfig public config;
                        /**
                         * @dev This empty reserved space is put in place to allow future versions to add new
                         * variables without shifting down storage in the inheritance chain.
                         * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                         */
                        uint256[50] private __gap;
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)
                    pragma solidity ^0.8.0;
                    import "../../utils/introspection/IERC165Upgradeable.sol";
                    /**
                     * @dev Required interface of an ERC1155 compliant contract, as defined in the
                     * https://eips.ethereum.org/EIPS/eip-1155[EIP].
                     *
                     * _Available since v3.1._
                     */
                    interface IERC1155Upgradeable is IERC165Upgradeable {
                        /**
                         * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
                         */
                        event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
                        /**
                         * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
                         * transfers.
                         */
                        event TransferBatch(
                            address indexed operator,
                            address indexed from,
                            address indexed to,
                            uint256[] ids,
                            uint256[] values
                        );
                        /**
                         * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
                         * `approved`.
                         */
                        event ApprovalForAll(address indexed account, address indexed operator, bool approved);
                        /**
                         * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
                         *
                         * If an {URI} event was emitted for `id`, the standard
                         * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
                         * returned by {IERC1155MetadataURI-uri}.
                         */
                        event URI(string value, uint256 indexed id);
                        /**
                         * @dev Returns the amount of tokens of token type `id` owned by `account`.
                         *
                         * Requirements:
                         *
                         * - `account` cannot be the zero address.
                         */
                        function balanceOf(address account, uint256 id) external view returns (uint256);
                        /**
                         * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
                         *
                         * Requirements:
                         *
                         * - `accounts` and `ids` must have the same length.
                         */
                        function balanceOfBatch(
                            address[] calldata accounts,
                            uint256[] calldata ids
                        ) external view returns (uint256[] memory);
                        /**
                         * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
                         *
                         * Emits an {ApprovalForAll} event.
                         *
                         * Requirements:
                         *
                         * - `operator` cannot be the caller.
                         */
                        function setApprovalForAll(address operator, bool approved) external;
                        /**
                         * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
                         *
                         * See {setApprovalForAll}.
                         */
                        function isApprovedForAll(address account, address operator) external view returns (bool);
                        /**
                         * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
                         *
                         * Emits a {TransferSingle} event.
                         *
                         * Requirements:
                         *
                         * - `to` cannot be the zero address.
                         * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
                         * - `from` must have a balance of tokens of type `id` of at least `amount`.
                         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
                         * acceptance magic value.
                         */
                        function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
                        /**
                         * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
                         *
                         * Emits a {TransferBatch} event.
                         *
                         * Requirements:
                         *
                         * - `ids` and `amounts` must have the same length.
                         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
                         * acceptance magic value.
                         */
                        function safeBatchTransferFrom(
                            address from,
                            address to,
                            uint256[] calldata ids,
                            uint256[] calldata amounts,
                            bytes calldata data
                        ) external;
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
                    pragma solidity ^0.8.0;
                    import "../../utils/introspection/IERC165Upgradeable.sol";
                    /**
                     * @dev _Available since v3.1._
                     */
                    interface IERC1155ReceiverUpgradeable is IERC165Upgradeable {
                        /**
                         * @dev Handles the receipt of a single ERC1155 token type. This function is
                         * called at the end of a `safeTransferFrom` after the balance has been updated.
                         *
                         * NOTE: To accept the transfer, this must return
                         * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
                         * (i.e. 0xf23a6e61, or its own function selector).
                         *
                         * @param operator The address which initiated the transfer (i.e. msg.sender)
                         * @param from The address which previously owned the token
                         * @param id The ID of the token being transferred
                         * @param value The amount of tokens being transferred
                         * @param data Additional data with no specified format
                         * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
                         */
                        function onERC1155Received(
                            address operator,
                            address from,
                            uint256 id,
                            uint256 value,
                            bytes calldata data
                        ) external returns (bytes4);
                        /**
                         * @dev Handles the receipt of a multiple ERC1155 token types. This function
                         * is called at the end of a `safeBatchTransferFrom` after the balances have
                         * been updated.
                         *
                         * NOTE: To accept the transfer(s), this must return
                         * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
                         * (i.e. 0xbc197c81, or its own function selector).
                         *
                         * @param operator The address which initiated the batch transfer (i.e. msg.sender)
                         * @param from The address which previously owned the token
                         * @param ids An array containing ids of each token being transferred (order and length must match values array)
                         * @param values An array containing amounts of each token being transferred (order and length must match ids array)
                         * @param data Additional data with no specified format
                         * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
                         */
                        function onERC1155BatchReceived(
                            address operator,
                            address from,
                            uint256[] calldata ids,
                            uint256[] calldata values,
                            bytes calldata data
                        ) external returns (bytes4);
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)
                    pragma solidity ^0.8.0;
                    import "../IERC1155Upgradeable.sol";
                    /**
                     * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
                     * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
                     *
                     * _Available since v3.1._
                     */
                    interface IERC1155MetadataURIUpgradeable is IERC1155Upgradeable {
                        /**
                         * @dev Returns the URI for token type `id`.
                         *
                         * If the `\\{id\\}` substring is present in the URI, it must be replaced by
                         * clients with the actual token type ID.
                         */
                        function uri(uint256 id) external view returns (string memory);
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
                    pragma solidity ^0.8.1;
                    error ADDRESS_INSUFFICIENT_BALANCE();
                    error ADDRESS_UNABLE_TO_SEND_VALUE();
                    error ADDRESS_LOW_LEVEL_CALL_FAILED();
                    error ADDRESS_LOW_LEVEL_CALL_WITH_VALUE_FAILED();
                    error ADDRESS_INSUFFICIENT_BALANCE_FOR_CALL();
                    error ADDRESS_LOW_LEVEL_STATIC_CALL_FAILED();
                    error ADDRESS_CALL_TO_NON_CONTRACT();
                    /**
                     * @dev Collection of functions related to the address type
                     */
                    library AddressUpgradeable {
                        /**
                         * @dev Returns true if `account` is a contract.
                         *
                         * [IMPORTANT]
                         * ====
                         * It is unsafe to assume that an address for which this function returns
                         * false is an externally-owned account (EOA) and not a contract.
                         *
                         * Among others, `isContract` will return false for the following
                         * types of addresses:
                         *
                         *  - an externally-owned account
                         *  - a contract in construction
                         *  - an address where a contract will be created
                         *  - an address where a contract lived, but was destroyed
                         *
                         * Furthermore, `isContract` will also return true if the target contract within
                         * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                         * which only has an effect at the end of a transaction.
                         * ====
                         *
                         * [IMPORTANT]
                         * ====
                         * You shouldn't rely on `isContract` to protect against flash loan attacks!
                         *
                         * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                         * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                         * constructor.
                         * ====
                         */
                        function isContract(address account) internal view returns (bool) {
                            // This method relies on extcodesize/address.code.length, which returns 0
                            // for contracts in construction, since the code is only stored at the end
                            // of the constructor execution.
                            return account.code.length > 0;
                        }
                        /**
                         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                         * `recipient`, forwarding all available gas and reverting on errors.
                         *
                         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                         * of certain opcodes, possibly making contracts go over the 2300 gas limit
                         * imposed by `transfer`, making them unable to receive funds via
                         * `transfer`. {sendValue} removes this limitation.
                         *
                         * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                         *
                         * IMPORTANT: because control is transferred to `recipient`, care must be
                         * taken to not create reentrancy vulnerabilities. Consider using
                         * {ReentrancyGuard} or the
                         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                         */
                        function sendValue(address payable recipient, uint256 amount) internal {
                            if (address(this).balance > amount) {
                                revert ADDRESS_INSUFFICIENT_BALANCE();
                            }
                            (bool success, ) = recipient.call{value: amount}("");
                            if (!success) {
                                revert ADDRESS_UNABLE_TO_SEND_VALUE();
                            }
                        }
                        /**
                         * @dev Performs a Solidity function call using a low level `call`. A
                         * plain `call` is an unsafe replacement for a function call: use this
                         * function instead.
                         *
                         * If `target` reverts with a revert reason, it is bubbled up by this
                         * function (like regular Solidity function calls).
                         *
                         * Returns the raw returned data. To convert to the expected return value,
                         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                         *
                         * Requirements:
                         *
                         * - `target` must be a contract.
                         * - calling `target` with `data` must not revert.
                         *
                         * _Available since v3.1._
                         */
                        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                            return functionCallWithValue(target, data, 0);
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                         * but also transferring `value` wei to `target`.
                         *
                         * Requirements:
                         *
                         * - the calling contract must have an ETH balance of at least `value`.
                         * - the called Solidity function must be `payable`.
                         *
                         * _Available since v3.1._
                         */
                        function functionCallWithValue(
                            address target,
                            bytes memory data,
                            uint256 value
                        ) internal returns (bytes memory) {
                            if (address(this).balance < value) {
                                revert ADDRESS_INSUFFICIENT_BALANCE();
                            }
                            (bool success, bytes memory returndata) = target.call{value: value}(data);
                            return verifyCallResultFromTarget(target, success, returndata);
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                         * but performing a static call.
                         *
                         * _Available since v3.3._
                         */
                        function functionStaticCall(
                            address target,
                            bytes memory data
                        ) internal view returns (bytes memory) {
                            (bool success, bytes memory returndata) = target.staticcall(data);
                            return verifyCallResultFromTarget(target, success, returndata);
                        }
                        /**
                         * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                         * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                         *
                         * _Available since v4.8._
                         */
                        function verifyCallResultFromTarget(
                            address target,
                            bool success,
                            bytes memory returndata
                        ) internal view returns (bytes memory) {
                            if (success) {
                                if (returndata.length == 0) {
                                    // only check isContract if the call was successful and the return data is empty
                                    // otherwise we already know that it was a contract
                                    if (!isContract(target)) {
                                        revert ADDRESS_CALL_TO_NON_CONTRACT();
                                    }
                                }
                                return returndata;
                            } else {
                                _revert(returndata);
                            }
                        }
                        /**
                         * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                         * revert reason or using the provided one.
                         *
                         * _Available since v4.3._
                         */
                        function verifyCallResult(
                            bool success,
                            bytes memory returndata
                        ) internal pure returns (bytes memory) {
                            if (success) {
                                return returndata;
                            } else {
                                _revert(returndata);
                            }
                        }
                        function _revert(bytes memory returndata) private pure {
                            // Look for revert reason and bubble it up if present
                            if (returndata.length > 0) {
                                // The easiest way to bubble the revert reason is using memory via assembly
                                /// @solidity memory-safe-assembly
                                assembly {
                                    let returndata_size := mload(returndata)
                                    revert(add(32, returndata), returndata_size)
                                }
                            } else {
                                revert ADDRESS_LOW_LEVEL_CALL_FAILED();
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
                    pragma solidity ^0.8.0;
                    import "../proxy/utils/Initializable.sol";
                    /**
                     * @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 ContextUpgradeable is Initializable {
                        function __Context_init() internal onlyInitializing {
                        }
                        function __Context_init_unchained() internal onlyInitializing {
                        }
                        function _msgSender() internal view virtual returns (address) {
                            return msg.sender;
                        }
                        function _msgData() internal view virtual returns (bytes calldata) {
                            return msg.data;
                        }
                        /**
                         * @dev This empty reserved space is put in place to allow future versions to add new
                         * variables without shifting down storage in the inheritance chain.
                         * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                         */
                        uint256[50] private __gap;
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
                    pragma solidity ^0.8.0;
                    import "./IERC165Upgradeable.sol";
                    import "../../proxy/utils/Initializable.sol";
                    /**
                     * @dev Implementation of the {IERC165} interface.
                     *
                     * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
                     * for the additional interface id that will be supported. For example:
                     *
                     * ```solidity
                     * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                     *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
                     * }
                     * ```
                     *
                     * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
                     */
                    abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
                        function __ERC165_init() internal onlyInitializing {
                        }
                        function __ERC165_init_unchained() internal onlyInitializing {
                        }
                        /**
                         * @dev See {IERC165-supportsInterface}.
                         */
                        function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                            return interfaceId == type(IERC165Upgradeable).interfaceId;
                        }
                        /**
                         * @dev This empty reserved space is put in place to allow future versions to add new
                         * variables without shifting down storage in the inheritance chain.
                         * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                         */
                        uint256[50] private __gap;
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol)
                    pragma solidity ^0.8.2;
                    import "../../utils/AddressUpgradeable.sol";
                    error INITIALIZABLE_CONTRACT_ALREADY_INITIALIZED();
                    error INITIALIZABLE_CONTRACT_IS_NOT_INITIALIZING();
                    error INITIALIZABLE_CONTRACT_IS_INITIALIZING();
                    /**
                     * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                     * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
                     * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                     * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                     *
                     * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
                     * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
                     * case an upgrade adds a module that needs to be initialized.
                     *
                     * For example:
                     *
                     * [.hljs-theme-light.nopadding]
                     * ```solidity
                     * contract MyToken is ERC20Upgradeable {
                     *     function initialize() initializer public {
                     *         __ERC20_init("MyToken", "MTK");
                     *     }
                     * }
                     *
                     * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
                     *     function initializeV2() reinitializer(2) public {
                     *         __ERC20Permit_init("MyToken");
                     *     }
                     * }
                     * ```
                     *
                     * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                     * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                     *
                     * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                     * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                     *
                     * [CAUTION]
                     * ====
                     * Avoid leaving a contract uninitialized.
                     *
                     * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
                     * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
                     * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
                     *
                     * [.hljs-theme-light.nopadding]
                     * ```
                     * /// @custom:oz-upgrades-unsafe-allow constructor
                     * constructor() {
                     *     _disableInitializers();
                     * }
                     * ```
                     * ====
                     */
                    abstract contract Initializable {
                        /**
                         * @dev Indicates that the contract has been initialized.
                         * @custom:oz-retyped-from bool
                         */
                        uint8 private _initialized;
                        /**
                         * @dev Indicates that the contract is in the process of being initialized.
                         */
                        bool private _initializing;
                        /**
                         * @dev Triggered when the contract has been initialized or reinitialized.
                         */
                        event Initialized(uint8 version);
                        /**
                         * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                         * `onlyInitializing` functions can be used to initialize parent contracts.
                         *
                         * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
                         * constructor.
                         *
                         * Emits an {Initialized} event.
                         */
                        modifier initializer() {
                            bool isTopLevelCall = !_initializing;
                            if ((!isTopLevelCall || _initialized != 0) && (AddressUpgradeable.isContract(address(this)) || _initialized != 1)) {
                                revert INITIALIZABLE_CONTRACT_ALREADY_INITIALIZED();
                            }
                            _initialized = 1;
                            if (isTopLevelCall) {
                                _initializing = true;
                            }
                            _;
                            if (isTopLevelCall) {
                                _initializing = false;
                                emit Initialized(1);
                            }
                        }
                        /**
                         * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                         * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                         * used to initialize parent contracts.
                         *
                         * A reinitializer may be used after the original initialization step. This is essential to configure modules that
                         * are added through upgrades and that require initialization.
                         *
                         * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
                         * cannot be nested. If one is invoked in the context of another, execution will revert.
                         *
                         * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                         * a contract, executing them in the right order is up to the developer or operator.
                         *
                         * WARNING: setting the version to 255 will prevent any future reinitialization.
                         *
                         * Emits an {Initialized} event.
                         */
                        modifier reinitializer(uint8 version) {
                            if (_initializing || _initialized >= version) {
                                revert INITIALIZABLE_CONTRACT_ALREADY_INITIALIZED();
                            }
                            _initialized = version;
                            _initializing = true;
                            _;
                            _initializing = false;
                            emit Initialized(version);
                        }
                        /**
                         * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                         * {initializer} and {reinitializer} modifiers, directly or indirectly.
                         */
                        modifier onlyInitializing() {
                            if (!_initializing) {
                                revert INITIALIZABLE_CONTRACT_IS_NOT_INITIALIZING();
                            }
                            _;
                        }
                        /**
                         * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                         * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                         * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                         * through proxies.
                         *
                         * Emits an {Initialized} event the first time it is successfully executed.
                         */
                        function _disableInitializers() internal virtual {
                            if (_initializing) {
                                revert INITIALIZABLE_CONTRACT_IS_INITIALIZING();
                            }
                            if (_initialized != type(uint8).max) {
                                _initialized = type(uint8).max;
                                emit Initialized(type(uint8).max);
                            }
                        }
                        /**
                         * @dev Returns the highest version that has been initialized. See {reinitializer}.
                         */
                        function _getInitializedVersion() internal view returns (uint8) {
                            return _initialized;
                        }
                        /**
                         * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
                         */
                        function _isInitializing() internal view returns (bool) {
                            return _initializing;
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
                    pragma solidity ^0.8.0;
                    /**
                     * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
                     * proxy whose upgrades are fully controlled by the current implementation.
                     */
                    interface IERC1822ProxiableUpgradeable {
                        /**
                         * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
                         * address.
                         *
                         * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                         * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                         * function revert if invoked through a proxy.
                         */
                        function proxiableUUID() external view returns (bytes32);
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
                    pragma solidity ^0.8.2;
                    import "../beacon/IBeaconUpgradeable.sol";
                    import "../../interfaces/draft-IERC1822Upgradeable.sol";
                    import "../../utils/AddressUpgradeable.sol";
                    import "../../utils/StorageSlotUpgradeable.sol";
                    import "../utils/Initializable.sol";
                    error ERC1967_NEW_IMPL_NOT_CONTRACT();
                    error ERC1967_UNSUPPORTED_PROXIABLEUUID();
                    error ERC1967_NEW_IMPL_NOT_UUPS();
                    error ERC1967_NEW_ADMIN_IS_ZERO_ADDRESS();
                    error ERC1967_NEW_BEACON_IS_NOT_CONTRACT();
                    error ERC1967_BEACON_IMPL_IS_NOT_CONTRACT();
                    error ADDRESS_DELEGATECALL_TO_NON_CONTRACT();
                    /**
                     * @dev This abstract contract provides getters and event emitting update functions for
                     * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                     *
                     * _Available since v4.1._
                     */
                    abstract contract ERC1967UpgradeUpgradeable is Initializable {
                        function __ERC1967Upgrade_init() internal onlyInitializing {
                        }
                        function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
                        }
                        // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                        bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                        /**
                         * @dev Storage slot with the address of the current implementation.
                         * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                         * validated in the constructor.
                         */
                        bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                        /**
                         * @dev Emitted when the implementation is upgraded.
                         */
                        event Upgraded(address indexed implementation);
                        /**
                         * @dev Returns the current implementation address.
                         */
                        function _getImplementation() internal view returns (address) {
                            return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                        }
                        /**
                         * @dev Stores a new address in the EIP1967 implementation slot.
                         */
                        function _setImplementation(address newImplementation) private {
                            if (!AddressUpgradeable.isContract(newImplementation)) {
                                revert ERC1967_NEW_IMPL_NOT_CONTRACT();
                            } 
                            StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                        }
                        /**
                         * @dev Perform implementation upgrade
                         *
                         * Emits an {Upgraded} event.
                         */
                        function _upgradeTo(address newImplementation) internal {
                            _setImplementation(newImplementation);
                            emit Upgraded(newImplementation);
                        }
                        /**
                         * @dev Perform implementation upgrade with additional setup call.
                         *
                         * Emits an {Upgraded} event.
                         */
                        function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                            _upgradeTo(newImplementation);
                            if (data.length > 0 || forceCall) {
                                _functionDelegateCall(newImplementation, data);
                            }
                        }
                        /**
                         * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                         *
                         * Emits an {Upgraded} event.
                         */
                        function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
                            // Upgrades from old implementations will perform a rollback test. This test requires the new
                            // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
                            // this special case will break upgrade paths from old UUPS implementation to new ones.
                            if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
                                _setImplementation(newImplementation);
                            } else {
                                try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                                    if (slot != _IMPLEMENTATION_SLOT) {
                                        revert ERC1967_UNSUPPORTED_PROXIABLEUUID();
                                    }
                                } catch {
                                    revert ERC1967_NEW_IMPL_NOT_UUPS();
                                }
                                _upgradeToAndCall(newImplementation, data, forceCall);
                            }
                        }
                        /**
                         * @dev Storage slot with the admin of the contract.
                         * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                         * validated in the constructor.
                         */
                        bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                        /**
                         * @dev Emitted when the admin account has changed.
                         */
                        event AdminChanged(address previousAdmin, address newAdmin);
                        /**
                         * @dev Returns the current admin.
                         */
                        function _getAdmin() internal view returns (address) {
                            return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
                        }
                        /**
                         * @dev Stores a new address in the EIP1967 admin slot.
                         */
                        function _setAdmin(address newAdmin) private {
                            if (newAdmin == address(0)) {
                                revert ERC1967_NEW_ADMIN_IS_ZERO_ADDRESS();
                            }
                            StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                        }
                        /**
                         * @dev Changes the admin of the proxy.
                         *
                         * Emits an {AdminChanged} event.
                         */
                        function _changeAdmin(address newAdmin) internal {
                            emit AdminChanged(_getAdmin(), newAdmin);
                            _setAdmin(newAdmin);
                        }
                        /**
                         * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                         * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                         */
                        bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                        /**
                         * @dev Emitted when the beacon is upgraded.
                         */
                        event BeaconUpgraded(address indexed beacon);
                        /**
                         * @dev Returns the current beacon.
                         */
                        function _getBeacon() internal view returns (address) {
                            return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
                        }
                        /**
                         * @dev Stores a new beacon in the EIP1967 beacon slot.
                         */
                        function _setBeacon(address newBeacon) private {
                            if (!AddressUpgradeable.isContract(newBeacon)) {
                                revert ERC1967_NEW_BEACON_IS_NOT_CONTRACT();
                            }
                            if (!AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation())) {
                                revert ERC1967_BEACON_IMPL_IS_NOT_CONTRACT();
                            }
                            StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                        }
                        /**
                         * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                         * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                         *
                         * Emits a {BeaconUpgraded} event.
                         */
                        function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                            _setBeacon(newBeacon);
                            emit BeaconUpgraded(newBeacon);
                            if (data.length > 0 || forceCall) {
                                _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
                            }
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                         * but performing a delegate call.
                         *
                         * _Available since v3.4._
                         */
                        function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {
                            if (!AddressUpgradeable.isContract(target)) {
                                revert ADDRESS_DELEGATECALL_TO_NON_CONTRACT();
                            }
                            // solhint-disable-next-line avoid-low-level-calls
                            (bool success, bytes memory returndata) = target.delegatecall(data);
                            return AddressUpgradeable.verifyCallResult(success, returndata);
                        }
                        /**
                         * @dev This empty reserved space is put in place to allow future versions to add new
                         * variables without shifting down storage in the inheritance chain.
                         * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                         */
                        uint256[50] private __gap;
                    }
                    // 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 IERC165Upgradeable {
                        /**
                         * @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.17;
                    import {IProtocolRewards} from "../interfaces/IProtocolRewards.sol";
                    struct RewardsSettings {
                        uint256 creatorReward;
                        uint256 createReferralReward;
                        uint256 mintReferralReward;
                        uint256 firstMinterReward;
                        uint256 zoraReward;
                    }
                    /// @notice Common logic for between Zora ERC-721 & ERC-1155 contracts for protocol reward splits & deposits
                    abstract contract RewardSplits {
                        error CREATOR_FUNDS_RECIPIENT_NOT_SET();
                        error INVALID_ADDRESS_ZERO();
                        error INVALID_ETH_AMOUNT();
                        error ONLY_CREATE_REFERRAL();
                        uint256 internal constant TOTAL_REWARD_PER_MINT = 0.000777 ether;
                        uint256 internal constant CREATOR_REWARD = 0.000333 ether;
                        uint256 internal constant FIRST_MINTER_REWARD = 0.000111 ether;
                        uint256 internal constant CREATE_REFERRAL_FREE_MINT_REWARD = 0.000111 ether;
                        uint256 internal constant MINT_REFERRAL_FREE_MINT_REWARD = 0.000111 ether;
                        uint256 internal constant ZORA_FREE_MINT_REWARD = 0.000111 ether;
                        uint256 internal constant MINT_REFERRAL_PAID_MINT_REWARD = 0.000222 ether;
                        uint256 internal constant CREATE_REFERRAL_PAID_MINT_REWARD = 0.000222 ether;
                        uint256 internal constant ZORA_PAID_MINT_REWARD = 0.000222 ether;
                        address internal immutable zoraRewardRecipient;
                        IProtocolRewards internal immutable protocolRewards;
                        constructor(address _protocolRewards, address _zoraRewardRecipient) payable {
                            if (_protocolRewards == address(0) || _zoraRewardRecipient == address(0)) {
                                revert INVALID_ADDRESS_ZERO();
                            }
                            protocolRewards = IProtocolRewards(_protocolRewards);
                            zoraRewardRecipient = _zoraRewardRecipient;
                        }
                        function computeTotalReward(uint256 numTokens) public pure returns (uint256) {
                            return numTokens * TOTAL_REWARD_PER_MINT;
                        }
                        function computeFreeMintRewards(uint256 numTokens) public pure returns (RewardsSettings memory) {
                            return
                                RewardsSettings({
                                    creatorReward: numTokens * CREATOR_REWARD,
                                    createReferralReward: numTokens * CREATE_REFERRAL_FREE_MINT_REWARD,
                                    mintReferralReward: numTokens * MINT_REFERRAL_FREE_MINT_REWARD,
                                    firstMinterReward: numTokens * FIRST_MINTER_REWARD,
                                    zoraReward: numTokens * ZORA_FREE_MINT_REWARD
                                });
                        }
                        function computePaidMintRewards(uint256 numTokens) public pure returns (RewardsSettings memory) {
                            return
                                RewardsSettings({
                                    creatorReward: 0,
                                    createReferralReward: numTokens * CREATE_REFERRAL_PAID_MINT_REWARD,
                                    mintReferralReward: numTokens * MINT_REFERRAL_PAID_MINT_REWARD,
                                    firstMinterReward: numTokens * FIRST_MINTER_REWARD,
                                    zoraReward: numTokens * ZORA_PAID_MINT_REWARD
                                });
                        }
                        function _depositFreeMintRewards(uint256 totalReward, uint256 numTokens, address creator, address createReferral, address mintReferral) internal {
                            RewardsSettings memory settings = computeFreeMintRewards(numTokens);
                            if (createReferral == address(0)) {
                                createReferral = zoraRewardRecipient;
                            }
                            if (mintReferral == address(0)) {
                                mintReferral = zoraRewardRecipient;
                            }
                            protocolRewards.depositRewards{value: totalReward}(
                                creator,
                                settings.creatorReward,
                                createReferral,
                                settings.createReferralReward,
                                mintReferral,
                                settings.mintReferralReward,
                                creator,
                                settings.firstMinterReward,
                                zoraRewardRecipient,
                                settings.zoraReward
                            );
                        }
                        function _depositPaidMintRewards(uint256 totalReward, uint256 numTokens, address creator, address createReferral, address mintReferral) internal {
                            RewardsSettings memory settings = computePaidMintRewards(numTokens);
                            if (createReferral == address(0)) {
                                createReferral = zoraRewardRecipient;
                            }
                            if (mintReferral == address(0)) {
                                mintReferral = zoraRewardRecipient;
                            }
                            protocolRewards.depositRewards{value: totalReward}(
                                address(0),
                                0,
                                createReferral,
                                settings.createReferralReward,
                                mintReferral,
                                settings.mintReferralReward,
                                creator,
                                settings.firstMinterReward,
                                zoraRewardRecipient,
                                settings.zoraReward
                            );
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {ITransferHookReceiver} from "../interfaces/ITransferHookReceiver.sol";
                    /*
                                 ░░░░░░░░░░░░░░              
                            ░░▒▒░░░░░░░░░░░░░░░░░░░░        
                          ░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░      
                        ░░▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░    
                       ░▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░    
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░░  
                      ░▓▓▓▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░░░  
                      ░▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░  
                      ░▓▓▓▓▓▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░  
                       ░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░  
                        ░░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░    
                        ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▒░░    
                          ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░      
                              ░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░          
                                   OURS TRULY,
                     */
                    /// Imagine. Mint. Enjoy.
                    /// @notice Interface for types used across the ZoraCreator1155 contract
                    /// @author @iainnash / @tbtstl
                    interface IZoraCreator1155TypesV1 {
                        /// @notice Used to store individual token data
                        struct TokenData {
                            string uri;
                            uint256 maxSupply;
                            uint256 totalMinted;
                        }
                        /// @notice Used to store contract-level configuration
                        struct ContractConfig {
                            address owner;
                            uint96 __gap1;
                            address payable fundsRecipient;
                            uint96 __gap2;
                            ITransferHookReceiver transferHook;
                            uint96 __gap3;
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    interface IOwnable {
                        function owner() external returns (address);
                        event OwnershipTransferred(address lastOwner, address newOwner);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    interface IVersionedContract {
                        function contractVersion() external returns (string memory);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IERC2981} from "@openzeppelin/contracts/interfaces/IERC2981.sol";
                    interface ICreatorRoyaltiesControl is IERC2981 {
                        /// @notice The RoyaltyConfiguration struct is used to store the royalty configuration for a given token.
                        /// @param royaltyMintSchedule Every nth token will go to the royalty recipient.
                        /// @param royaltyBPS The royalty amount in basis points for secondary sales.
                        /// @param royaltyRecipient The address that will receive the royalty payments.
                        struct RoyaltyConfiguration {
                            uint32 royaltyMintSchedule;
                            uint32 royaltyBPS;
                            address royaltyRecipient;
                        }
                        /// @notice Thrown when a user tries to have 100% supply royalties
                        error InvalidMintSchedule();
                        /// @notice Event emitted when royalties are updated
                        event UpdatedRoyalties(uint256 indexed tokenId, address indexed user, RoyaltyConfiguration configuration);
                        /// @notice External data getter to get royalties for a token
                        /// @param tokenId tokenId to get royalties configuration for
                        function getRoyalties(uint256 tokenId) external view returns (RoyaltyConfiguration memory);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    /// Imagine. Mint. Enjoy.
                    /// @author @iainnash / @tbtstl
                    contract CreatorPermissionStorageV1 {
                        mapping(uint256 => mapping(address => uint256)) public permissions;
                        uint256[50] private __gap;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    /// @notice Generic control interface for bit-based permissions-control
                    interface ICreatorPermissionControl {
                        /// @notice Emitted when permissions are updated
                        event UpdatedPermissions(uint256 indexed tokenId, address indexed user, uint256 indexed permissions);
                        /// @notice Public interface to get permissions given a token id and a user address
                        /// @return Returns raw permission bits
                        function getPermissions(uint256 tokenId, address user) external view returns (uint256);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {ICreatorRendererControl} from "../interfaces/ICreatorRendererControl.sol";
                    import {IRenderer1155} from "../interfaces/IRenderer1155.sol";
                    /// @notice Creator Renderer Storage Configuration Contract V1
                    abstract contract CreatorRendererStorageV1 is ICreatorRendererControl {
                        /// @notice Mapping for custom renderers
                        mapping(uint256 => IRenderer1155) public customRenderers;
                        uint256[50] private __gap;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {ICreatorRoyaltiesControl} from "../interfaces/ICreatorRoyaltiesControl.sol";
                    /// Imagine. Mint. Enjoy.
                    /// @title CreatorRoyaltiesControl
                    /// @author ZORA @iainnash / @tbtstl
                    /// @notice Royalty storage contract pattern
                    abstract contract CreatorRoyaltiesStorageV1 is ICreatorRoyaltiesControl {
                        mapping(uint256 => RoyaltyConfiguration) public royalties;
                        uint256[50] private __gap;
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.9.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
                    pragma solidity 0.8.17;
                    interface ILegacyNaming {
                        function name() external returns (string memory);
                        function symbol() external returns (string memory);
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    contract LegacyNamingStorageV1 {
                        string internal _name;
                        uint256[50] private __gap;
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    interface IMintFeeManager {
                        error MintFeeCannotBeMoreThanZeroPointOneETH(uint256 mintFeeBPS);
                        error CannotSendMintFee(address mintFeeRecipient, uint256 mintFee);
                        error CannotSetMintFeeToZeroAddress();
                        function mintFee() external view returns (uint256);
                        function mintFeeRecipient() external view returns (address);
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
                    pragma solidity ^0.8.1;
                    /**
                     * @dev Collection of functions related to the address type
                     */
                    library Address {
                        /**
                         * @dev Returns true if `account` is a contract.
                         *
                         * [IMPORTANT]
                         * ====
                         * It is unsafe to assume that an address for which this function returns
                         * false is an externally-owned account (EOA) and not a contract.
                         *
                         * Among others, `isContract` will return false for the following
                         * types of addresses:
                         *
                         *  - an externally-owned account
                         *  - a contract in construction
                         *  - an address where a contract will be created
                         *  - an address where a contract lived, but was destroyed
                         *
                         * Furthermore, `isContract` will also return true if the target contract within
                         * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                         * which only has an effect at the end of a transaction.
                         * ====
                         *
                         * [IMPORTANT]
                         * ====
                         * You shouldn't rely on `isContract` to protect against flash loan attacks!
                         *
                         * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                         * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                         * constructor.
                         * ====
                         */
                        function isContract(address account) internal view returns (bool) {
                            // This method relies on extcodesize/address.code.length, which returns 0
                            // for contracts in construction, since the code is only stored at the end
                            // of the constructor execution.
                            return account.code.length > 0;
                        }
                        /**
                         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                         * `recipient`, forwarding all available gas and reverting on errors.
                         *
                         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                         * of certain opcodes, possibly making contracts go over the 2300 gas limit
                         * imposed by `transfer`, making them unable to receive funds via
                         * `transfer`. {sendValue} removes this limitation.
                         *
                         * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                         *
                         * IMPORTANT: because control is transferred to `recipient`, care must be
                         * taken to not create reentrancy vulnerabilities. Consider using
                         * {ReentrancyGuard} or the
                         * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                         */
                        function sendValue(address payable recipient, uint256 amount) internal {
                            require(address(this).balance >= amount, "Address: insufficient balance");
                            (bool success, ) = recipient.call{value: amount}("");
                            require(success, "Address: unable to send value, recipient may have reverted");
                        }
                        /**
                         * @dev Performs a Solidity function call using a low level `call`. A
                         * plain `call` is an unsafe replacement for a function call: use this
                         * function instead.
                         *
                         * If `target` reverts with a revert reason, it is bubbled up by this
                         * function (like regular Solidity function calls).
                         *
                         * Returns the raw returned data. To convert to the expected return value,
                         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                         *
                         * Requirements:
                         *
                         * - `target` must be a contract.
                         * - calling `target` with `data` must not revert.
                         *
                         * _Available since v3.1._
                         */
                        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                            return functionCallWithValue(target, data, 0, "Address: low-level call failed");
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                         * `errorMessage` as a fallback revert reason when `target` reverts.
                         *
                         * _Available since v3.1._
                         */
                        function functionCall(
                            address target,
                            bytes memory data,
                            string memory errorMessage
                        ) internal returns (bytes memory) {
                            return functionCallWithValue(target, data, 0, errorMessage);
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                         * but also transferring `value` wei to `target`.
                         *
                         * Requirements:
                         *
                         * - the calling contract must have an ETH balance of at least `value`.
                         * - the called Solidity function must be `payable`.
                         *
                         * _Available since v3.1._
                         */
                        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                        }
                        /**
                         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                         * with `errorMessage` as a fallback revert reason when `target` reverts.
                         *
                         * _Available since v3.1._
                         */
                        function functionCallWithValue(
                            address target,
                            bytes memory data,
                            uint256 value,
                            string memory errorMessage
                        ) internal returns (bytes memory) {
                            require(address(this).balance >= value, "Address: insufficient balance for call");
                            (bool success, bytes memory returndata) = target.call{value: value}(data);
                            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                         * but performing a static call.
                         *
                         * _Available since v3.3._
                         */
                        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                            return functionStaticCall(target, data, "Address: low-level static call failed");
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                         * but performing a static call.
                         *
                         * _Available since v3.3._
                         */
                        function functionStaticCall(
                            address target,
                            bytes memory data,
                            string memory errorMessage
                        ) internal view returns (bytes memory) {
                            (bool success, bytes memory returndata) = target.staticcall(data);
                            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                         * but performing a delegate call.
                         *
                         * _Available since v3.4._
                         */
                        function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                            return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                        }
                        /**
                         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                         * but performing a delegate call.
                         *
                         * _Available since v3.4._
                         */
                        function functionDelegateCall(
                            address target,
                            bytes memory data,
                            string memory errorMessage
                        ) internal returns (bytes memory) {
                            (bool success, bytes memory returndata) = target.delegatecall(data);
                            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                        }
                        /**
                         * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                         * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                         *
                         * _Available since v4.8._
                         */
                        function verifyCallResultFromTarget(
                            address target,
                            bool success,
                            bytes memory returndata,
                            string memory errorMessage
                        ) internal view returns (bytes memory) {
                            if (success) {
                                if (returndata.length == 0) {
                                    // only check isContract if the call was successful and the return data is empty
                                    // otherwise we already know that it was a contract
                                    require(isContract(target), "Address: call to non-contract");
                                }
                                return returndata;
                            } else {
                                _revert(returndata, errorMessage);
                            }
                        }
                        /**
                         * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                         * revert reason or using the provided one.
                         *
                         * _Available since v4.3._
                         */
                        function verifyCallResult(
                            bool success,
                            bytes memory returndata,
                            string memory errorMessage
                        ) internal pure returns (bytes memory) {
                            if (success) {
                                return returndata;
                            } else {
                                _revert(returndata, errorMessage);
                            }
                        }
                        function _revert(bytes memory returndata, string memory errorMessage) private pure {
                            // Look for revert reason and bubble it up if present
                            if (returndata.length > 0) {
                                // The easiest way to bubble the revert reason is using memory via assembly
                                /// @solidity memory-safe-assembly
                                assembly {
                                    let returndata_size := mload(returndata)
                                    revert(add(32, returndata), returndata_size)
                                }
                            } else {
                                revert(errorMessage);
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
                    pragma solidity ^0.8.0;
                    /**
                     * @dev This is the interface that {BeaconProxy} expects of its beacon.
                     */
                    interface IBeaconUpgradeable {
                        /**
                         * @dev Must return an address that can be used as a delegate call target.
                         *
                         * {BeaconProxy} will check that this address is a contract.
                         */
                        function implementation() external view returns (address);
                    }
                    // SPDX-License-Identifier: MIT
                    // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)
                    // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
                    pragma solidity ^0.8.0;
                    /**
                     * @dev Library for reading and writing primitive types to specific storage slots.
                     *
                     * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                     * This library helps with reading and writing to such slots without the need for inline assembly.
                     *
                     * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                     *
                     * Example usage to set ERC1967 implementation slot:
                     * ```solidity
                     * contract ERC1967 {
                     *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                     *
                     *     function _getImplementation() internal view returns (address) {
                     *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                     *     }
                     *
                     *     function _setImplementation(address newImplementation) internal {
                     *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                     *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                     *     }
                     * }
                     * ```
                     *
                     * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
                     * _Available since v4.9 for `string`, `bytes`._
                     */
                    library StorageSlotUpgradeable {
                        struct AddressSlot {
                            address value;
                        }
                        struct BooleanSlot {
                            bool value;
                        }
                        struct Bytes32Slot {
                            bytes32 value;
                        }
                        struct Uint256Slot {
                            uint256 value;
                        }
                        struct StringSlot {
                            string value;
                        }
                        struct BytesSlot {
                            bytes value;
                        }
                        /**
                         * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                         */
                        function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                         */
                        function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                         */
                        function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                         */
                        function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `StringSlot` with member `value` located at `slot`.
                         */
                        function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                         */
                        function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := store.slot
                            }
                        }
                        /**
                         * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                         */
                        function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := slot
                            }
                        }
                        /**
                         * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                         */
                        function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                            /// @solidity memory-safe-assembly
                            assembly {
                                r.slot := store.slot
                            }
                        }
                    }
                    // SPDX-License-Identifier: MIT
                    pragma solidity 0.8.17;
                    import {IRenderer1155} from "./IRenderer1155.sol";
                    /// @notice Interface for creator renderer controls
                    interface ICreatorRendererControl {
                        /// @notice Get the custom renderer contract (if any) for the given token id
                        /// @dev Reverts if not custom renderer is set for this token
                        function getCustomRenderer(uint256 tokenId) external view returns (IRenderer1155 renderer);
                        error NoRendererForToken(uint256 tokenId);
                        error RendererNotValid(address renderer);
                        event RendererUpdated(uint256 indexed tokenId, address indexed renderer, address indexed user);
                    }
                    // 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);
                    }