Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x442295de8A31d65026dBc09c29d469F6854f188a
Balance 0 ETH
Nonce 141
Code Size 7637 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

7637 bytes
0x6080604052600436106100ef5760003560e01c806308c73259146100f457806318a071ad1461013e578063256929621461015e5780633f4ba83a146101685780633fafa1271461017d57806354d1f13d146101b55780635c60da1b146101bd5780635c975abb146101e2578063715018a6146102055780637d8983cf1461020d5780637ecebe001461024d5780638456cb59146102885780638da5cb5b1461029d57806394a37936146102b6578063abb1ab94146102ec578063b8d7b6691461030c578063d784d4261461032c578063f04e283e1461034c578063f2fde38b1461035f578063fee81cf414610372575b600080fd5b34801561010057600080fd5b506101287f00000000000000000000000022b9dd17ba1132c027d780bc0a784f08f244022b81565b6040516101359190610ade565b60405180910390f35b34801561014a57600080fd5b5061012861015936600461117a565b6103a5565b610166610574565b005b34801561017457600080fd5b506101666105c3565b34801561018957600080fd5b5060015461019d906001600160601b031681565b6040516001600160601b039091168152602001610135565b6101666105d5565b3480156101c957600080fd5b506000546101289061010090046001600160a01b031681565b3480156101ee57600080fd5b5060005460ff166040519015158152602001610135565b610166610611565b34801561021957600080fd5b5061022d6102283660046112ca565b610623565b604080516001600160a01b03938416815292909116602083015201610135565b34801561025957600080fd5b5061027a61026836600461134d565b60026020526000908152604090205481565b604051908152602001610135565b34801561029457600080fd5b506101666106ed565b3480156102a957600080fd5b50638b78c6d81954610128565b3480156102c257600080fd5b506101286102d136600461136a565b6003602052600090815260409020546001600160a01b031681565b3480156102f857600080fd5b50610128610307366004611387565b6106fd565b34801561031857600080fd5b5061012861032736600461134d565b61074d565b34801561033857600080fd5b5061016661034736600461134d565b6107ba565b61016661035a36600461134d565b6107ce565b61016661036d36600461134d565b61080b565b34801561037e57600080fd5b5061027a61038d36600461134d565b63389a75e1600c908152600091909152602090205490565b60006103af610832565b6001600160a01b0389166103d6576040516349e27cff60e01b815260040160405180910390fd5b33600081815260026020908152604080832054905192936103f9939092016113c3565b604051602081830303815290604052805190602001209050610430600060019054906101000a90046001600160a01b03168261087d565b33600090815260026020526040812080549294509061044e836113f2565b9091555050600180548391600391600091908290610474906001600160601b031661140b565b82546001600160601b039182166101009390930a8381029083021990911617909255825260208201929092526040908101600090812080546001600160a01b039586166001600160a01b031990911617905560015491518e85169487169392909216917f546bc3cd5ff4b322df8339c6833b99285a6333e5e5f90a88ced57d9de7c345fc9190a4604051634e313ed160e01b81526001600160a01b03831690634e313ed190610535908d908d908d908d908d908d908d908d90600401611612565b600060405180830381600087803b15801561054f57600080fd5b505af1158015610563573d6000803e3d6000fd5b505050505098975050505050505050565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b6105cb6108d4565b6105d36108ef565b565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b6106196108d4565b6105d3600061093b565b60008061062e610832565b61066d87878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506106fd92505050565b604051632a31243d60e21b81529092506001600160a01b0384169063a8c490f49061069e90889088906004016117cf565b6020604051808303816000875af11580156106bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e19190611809565b90509550959350505050565b6106f56108d4565b6105d3610979565b60008060008060008060008060008980602001905181019061071f9190611ca5565b9750975097509750975097509750975061073f88888888888888886103a5565b9a9950505050505050505050565b6001600160a01b0381166000908152600260209081526040808320549051839261077b9286929091016113c3565b6040516020818303038152906040528051906020012090506107b3600060019054906101000a90046001600160a01b031682306109b6565b9392505050565b6107c26108d4565b6107cb81610a13565b50565b6107d66108d4565b63389a75e1600c52806000526020600c2080544211156107fe57636f5e88186000526004601cfd5b600090556107cb8161093b565b6108136108d4565b8060601b61082957637448fbae6000526004601cfd5b6107cb8161093b565b60005460ff16156105d35760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064015b60405180910390fd5b60006c5af43d3d93803e602a57fd5bf36021528260145273602c3d8160093d39f33d3d3d3d363d3d37363d73600052816035600c6000f590506000602152806108ce5763301164256000526004601cfd5b92915050565b638b78c6d8195433146105d3576382b429006000526004601cfd5b6108f7610a66565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516109319190610ade565b60405180910390a1565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b610981610832565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586109243390565b6000806109fd8560006c5af43d3d93803e602a57fd5bf36021528160145273602c3d8160093d39f33d3d3d3d363d3d37363d736000526035600c2090506000602152919050565b9050610a0a818585610aaf565b95945050505050565b60008054610100600160a81b0319166101006001600160a01b038416908102919091178255604051909133917faa3f731066a578e5f39b4215468d826cdd15373cbc0dfc9cb9bdc649718ef7da9190a350565b60005460ff166105d35760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610874565b600060ff60005350603592835260601b60015260155260556000908120915290565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b6001600160a01b03811681146107cb57600080fd5b8035610b1281610af2565b919050565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b0381118282101715610b5057610b50610b17565b60405290565b60405160a081016001600160401b0381118282101715610b5057610b50610b17565b604080519081016001600160401b0381118282101715610b5057610b50610b17565b604051606081016001600160401b0381118282101715610b5057610b50610b17565b604051601f8201601f191681016001600160401b0381118282101715610be457610be4610b17565b604052919050565b60006001600160401b03821115610c0557610c05610b17565b50601f01601f191660200190565b600082601f830112610c2457600080fd5b8135610c37610c3282610bec565b610bbc565b818152846020838601011115610c4c57600080fd5b816020850160208301376000918101602001919091529392505050565b60006001600160401b03821115610c8257610c82610b17565b5060051b60200190565b600082601f830112610c9d57600080fd5b81356020610cad610c3283610c69565b8083825260208201915060208460051b870101935086841115610ccf57600080fd5b602086015b84811015610cf4578035610ce781610af2565b8352918301918301610cd4565b509695505050505050565b63ffffffff811681146107cb57600080fd5b600082601f830112610d2257600080fd5b81356020610d32610c3283610c69565b8083825260208201915060208460051b870101935086841115610d5457600080fd5b602086015b84811015610cf4578035610d6c81610cff565b8352918301918301610d59565b600082601f830112610d8a57600080fd5b81356020610d9a610c3283610c69565b8083825260208201915060208460051b870101935086841115610dbc57600080fd5b602086015b84811015610cf45780358352918301918301610dc1565b60006101008284031215610deb57600080fd5b610df3610b2d565b905081356001600160401b0380821115610e0c57600080fd5b610e1885838601610c13565b83526020840135915080821115610e2e57600080fd5b610e3a85838601610c13565b60208401526040840135915080821115610e5357600080fd5b610e5f85838601610c8c565b60408401526060840135915080821115610e7857600080fd5b610e8485838601610d11565b6060840152610e9560808501610b07565b6080840152610ea660a08501610b07565b60a084015260c0840135915080821115610ebf57600080fd5b610ecb85838601610d79565b60c084015260e0840135915080821115610ee457600080fd5b50610ef184828501610c13565b60e08301525092915050565b80151581146107cb57600080fd5b6001600160781b03811681146107cb57600080fd5b6001600160581b03811681146107cb57600080fd5b600060a08284031215610f4757600080fd5b610f4f610b56565b90508135610f5c81610efd565b81526020820135610f6c81610efd565b60208201526040820135610f7f81610f0b565b60408201526060820135610f9281610f20565b60608201526080820135610fa581610cff565b608082015292915050565b600060408284031215610fc257600080fd5b610fca610b78565b905081356001600160401b03811115610fe257600080fd5b610fee84828501610c13565b8252506020820135610fff81610af2565b602082015292915050565b6001600160401b03811681146107cb57600080fd5b6001600160801b03811681146107cb57600080fd5b600082601f83011261104557600080fd5b81356020611055610c3283610c69565b82815260059290921b8401810191818101908684111561107457600080fd5b8286015b84811015610cf45780356001600160401b03808211156110985760008081fd5b90880190818a0360a0601f1982018113156110b35760008081fd5b6110bb610b9a565b888501356110c881610af2565b815260406060603f1985018113156110e05760008081fd5b6110e8610b9a565b9450818701356110f78161100a565b85528601356111058161100a565b848b015260808601356111178161101f565b84820152818a019390935284820135928484111561113757600092508283fd5b6111458e8b86890101610c13565b90820152875250505092840192508301611078565b6001600160601b03811681146107cb57600080fd5b8035610b128161115a565b600080600080600080600080610180898b03121561119757600080fd5b6111a089610b07565b975060208901356001600160401b03808211156111bc57600080fd5b6111c88c838d01610dd8565b98506111d78c60408d01610f35565b975060e08b01359150808211156111ed57600080fd5b6111f98c838d01610fb0565b96506101008b013591508082111561121057600080fd5b61121c8c838d01611034565b95506101208b013591508082111561123357600080fd5b61123f8c838d01610c8c565b94506101408b013591508082111561125657600080fd5b506112638b828c01610d11565b9250506112736101608a0161116f565b90509295985092959890939650565b60008083601f84011261129457600080fd5b5081356001600160401b038111156112ab57600080fd5b6020830191508360208285010111156112c357600080fd5b9250929050565b6000806000806000606086880312156112e257600080fd5b85356001600160401b03808211156112f957600080fd5b61130589838a01611282565b9097509550602088013591508082111561131e57600080fd5b5061132b88828901611282565b909450925050604086013561133f81610af2565b809150509295509295909350565b60006020828403121561135f57600080fd5b81356107b381610af2565b60006020828403121561137c57600080fd5b81356107b38161115a565b60006020828403121561139957600080fd5b81356001600160401b038111156113af57600080fd5b6113bb84828501610c13565b949350505050565b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052601160045260246000fd5b600060018201611404576114046113dc565b5060010190565b60006001600160601b038281166002600160601b0319810161142f5761142f6113dc565b6001019392505050565b60005b8381101561145457818101518382015260200161143c565b50506000910152565b60008151808452611475816020860160208601611439565b601f01601f19169290920160200192915050565b60008151808452602080850194506020840160005b838110156114c35781516001600160a01b03168752958201959082019060010161149e565b509495945050505050565b60008151808452602080850194506020840160005b838110156114c357815163ffffffff16875295820195908201906001016114e3565b60008151808452602080850194506020840160005b838110156114c35781518752958201959082019060010161151a565b600081516040845261154b604085018261145d565b6020938401516001600160a01b0316949093019390935250919050565b600082825180855260208086019550808260051b84010181860160005b8481101561160557858303601f19018952815180516001600160a01b031684528481015180516001600160401b03908116878701528187015116604080870191909152908101516001600160801b03166060860152015160a0608085018190526115f18186018361145d565b9a86019a9450505090830190600101611585565b5090979650505050505050565b600061018060018060a01b038b1683528060208401528951610100808386015261164061028086018361145d565b925060208c0151915061017f1980868503016101a0870152611662848461145d565b935060408d0151925080868503016101c08701526116808484611489565b935060608d0151925080868503016101e087015261169e84846114ce565b935060808d015192506116b5610200870184610ad1565b60a08d015192506116ca610220870184610ad1565b60c08d0151925080868503016102408701526116e68484611505565b935060e08d01519250808685030161026087015250611705838361145d565b9250611758604086018c8051151582526020808201511515908301526040808201516001600160781b0316908301526060808201516001600160581b03169083015260809081015163ffffffff16910152565b84830360e086015261176a838b611536565b925084830381860152505061177f8188611568565b90508281036101208401526117948187611489565b90508281036101408401526117a981866114ce565b9150506117c26101608301846001600160601b03169052565b9998505050505050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b8051610b1281610af2565b60006020828403121561181b57600080fd5b81516107b381610af2565b600082601f83011261183757600080fd5b8151611845610c3282610bec565b81815284602083860101111561185a57600080fd5b6113bb826020830160208701611439565b600082601f83011261187c57600080fd5b8151602061188c610c3283610c69565b8083825260208201915060208460051b8701019350868411156118ae57600080fd5b602086015b84811015610cf45780516118c681610af2565b83529183019183016118b3565b600082601f8301126118e457600080fd5b815160206118f4610c3283610c69565b8083825260208201915060208460051b87010193508684111561191657600080fd5b602086015b84811015610cf457805161192e81610cff565b835291830191830161191b565b600082601f83011261194c57600080fd5b8151602061195c610c3283610c69565b8083825260208201915060208460051b87010193508684111561197e57600080fd5b602086015b84811015610cf45780518352918301918301611983565b600061010082840312156119ad57600080fd5b6119b5610b2d565b82519091506001600160401b03808211156119cf57600080fd5b6119db85838601611826565b835260208401519150808211156119f157600080fd5b6119fd85838601611826565b60208401526040840151915080821115611a1657600080fd5b611a228583860161186b565b60408401526060840151915080821115611a3b57600080fd5b611a47858386016118d3565b6060840152611a58608085016117fe565b6080840152611a6960a085016117fe565b60a084015260c0840151915080821115611a8257600080fd5b611a8e8583860161193b565b60c084015260e0840151915080821115611aa757600080fd5b50610ef184828501611826565b600060a08284031215611ac657600080fd5b611ace610b56565b90508151611adb81610efd565b81526020820151611aeb81610efd565b60208201526040820151611afe81610f0b565b60408201526060820151611b1181610f20565b60608201526080820151610fa581610cff565b600060408284031215611b3657600080fd5b611b3e610b78565b82519091506001600160401b03811115611b5757600080fd5b611b6384828501611826565b8252506020820151610fff81610af2565b600082601f830112611b8557600080fd5b81516020611b95610c3283610c69565b82815260059290921b84018101918181019086841115611bb457600080fd5b8286015b84811015610cf45780516001600160401b0380821115611bd85760008081fd5b90880190818a0360a0601f198201811315611bf35760008081fd5b611bfb610b9a565b88850151611c0881610af2565b815260406060603f198501811315611c205760008081fd5b611c28610b9a565b945081870151611c378161100a565b8552860151611c458161100a565b848b01526080860151611c578161101f565b84820152818a0193909352848201519284841115611c7757600092508283fd5b611c858e8b86890101611826565b90820152875250505092840192508301611bb8565b8051610b128161115a565b600080600080600080600080610180898b031215611cc257600080fd5b611ccb896117fe565b60208a01519098506001600160401b0380821115611ce857600080fd5b611cf48c838d0161199a565b9850611d038c60408d01611ab4565b975060e08b0151915080821115611d1957600080fd5b611d258c838d01611b24565b96506101008b0151915080821115611d3c57600080fd5b611d488c838d01611b74565b95506101208b0151915080821115611d5f57600080fd5b611d6b8c838d0161186b565b94506101408b0151915080821115611d8257600080fd5b50611d8f8b828c016118d3565b9250506112736101608a01611c9a56fea264697066735822122088452299894e2156906d8869b76bf0df97e957f933df0105e98618d606e68bc164736f6c63430008170033

Verified Source Code Full Match

Compiler: v0.8.23+commit.f704f362 EVM: paris Optimization: Yes (2 runs)
Structs.sol 179 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

/*//////////////////////////////////////////////////////////////////////////
                                  STRUCTS
//////////////////////////////////////////////////////////////////////////*/

/**
 * @notice Struct of dutch auction information
 * - `refunded` Flag indicating if refunds are enabled
 * - `stepLength` Duration (in seconds) of each auction step
 * - `prices` Array of prices for each step of the auction
 */
struct AuctionInfo {
    bool refunded;
    uint248 stepLength;
    uint256[] prices;
}

/**
 * @notice Struct of system config information
 * - `feeReceiver` Address receiving platform fees
 * - `primaryFeeAllocation` Amount of basis points allocated to calculate platform fees on primary sale proceeds
 * - `secondaryFeeAllocation` Amount of basis points allocated to calculate platform fees on royalty payments
 * - `lockTime` Locked time duration added to mint start time for unverified creators
 * - `referrerShare` Share amount distributed to accounts referring tokens
 * - `defaultMetadataURI` Default base URI of token metadata
 * - `externalURI` External URI for displaying tokens
 */
struct ConfigInfo {
    address feeReceiver;
    uint32 primaryFeeAllocation;
    uint32 secondaryFeeAllocation;
    uint32 lockTime;
    uint64 referrerShare;
    string defaultMetadataURI;
    string externalURI;
}

/**
 * @notice Struct of generative art information
 * - `minter` Address of initial token owner
 * - `seed` Hash of randomly generated seed
 * - `fxParams` Random sequence of fixed-length bytes used as token input
 */
struct GenArtInfo {
    address minter;
    bytes32 seed;
    bytes fxParams;
}

/**
 * @notice Struct of initialization information used on project creation
 * - `name` Name of project
 * - `symbol` Symbol of project
 * - `primaryReceiver` Address of splitter contract receiving primary sales
 * - `randomizer` Address of Randomizer contract
 * - `renderer` Address of Renderer contract
 * - `tagIds` Array of tag IDs describing the project
 * - 'onchainData' Onchain data to be stored using SSTORE2 and available to renderers
 */
struct InitInfo {
    string name;
    string symbol;
    address[] primaryReceivers;
    uint32[] allocations;
    address randomizer;
    address renderer;
    uint256[] tagIds;
    bytes onchainData;
}

/**
 * @notice Struct of issuer information
 * - `primaryReceiver` Address of splitter contract receiving primary sales
 * - `projectInfo` Project information
 * - `activeMinters` Array of authorized minter contracts used for enumeration
 * - `minters` Mapping of minter contract to authorization status
 */
struct IssuerInfo {
    address primaryReceiver;
    ProjectInfo projectInfo;
    address[] activeMinters;
    mapping(address => uint8) minters;
}

/**
 * @notice Struct of metadata information
 * - `baseURI` Decoded URI of content identifier
 * - `onchainPointer` Address of bytes-encoded data rendered onchain
 */
struct MetadataInfo {
    bytes baseURI;
    address onchainPointer;
}

/**
 * @notice Struct of mint information
 * - `minter` Address of the minter contract
 * - `reserveInfo` Reserve information
 * - `params` Optional bytes data decoded inside minter
 */
struct MintInfo {
    address minter;
    ReserveInfo reserveInfo;
    bytes params;
}

/**
 * @notice Struct of minter information
 * - `totalMints` Total number of mints executed by the minter
 * - `totalPaid` Total amount paid by the minter
 */
struct MinterInfo {
    uint128 totalMints;
    uint128 totalPaid;
}

/**
 * @notice Struct of project information
 * - `mintEnabled` Flag inidicating if minting is enabled
 * - `burnEnabled` Flag inidicating if burning is enabled
 * - `maxSupply` Maximum supply of tokens
 * - `inputSize` Maximum input size of fxParams bytes data
 * - `earliestStartTime` Earliest possible start time for registering minters
 */
struct ProjectInfo {
    bool mintEnabled;
    bool burnEnabled;
    uint120 maxSupply;
    uint88 inputSize;
    uint32 earliestStartTime;
}

/**
 * @notice Struct of refund information
 * - `lastPrice` Price of last sale before selling out
 * - `minterInfo` Mapping of minter address to struct of minter information
 */
struct RefundInfo {
    uint256 lastPrice;
    mapping(address minter => MinterInfo) minterInfo;
}

/**
 * @notice Struct of reserve information
 * - `startTime` Start timestamp of minter
 * - `endTime` End timestamp of minter
 * - `allocation` Allocation amount for minter
 */
struct ReserveInfo {
    uint64 startTime;
    uint64 endTime;
    uint128 allocation;
}

/**
 * @notice Struct of royalty information
 * - `receiver` Address receiving royalties
 * - `basisPoints` Points used to calculate the royalty payment (0.01%)
 */
struct RoyaltyInfo {
    address receiver;
    uint96 basisPoints;
}

/**
 * @notice Struct of tax information
 * - `startTime` Timestamp of when harberger taxation begins
 * - `foreclosureTime` Timestamp of token foreclosure
 * - `currentPrice` Current listing price of token
 * - `depositAmount` Total amount of taxes deposited
 */
struct TaxInfo {
    uint48 startTime;
    uint48 foreclosureTime;
    uint80 currentPrice;
    uint80 depositAmount;
}
IToken.sol 27 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

/**
 * @title IToken
 * @author fx(hash)
 * @notice Interface for minters to interact with tokens
 */
interface IToken {
    /*//////////////////////////////////////////////////////////////////////////
                                  FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @notice Mints arbitrary number of tokens
     * @dev Only callable by registered minter contracts
     * @param _to Address receiving tokens
     * @param _amount Number of tokens being minted
     * @param _payment Total payment amount of the transaction
     */
    function mint(address _to, uint256 _amount, uint256 _payment) external;

    /**
     * @notice Returns address of primary receiver for token sales
     */
    function primaryReceiver() external view returns (address);
}
Ownable.sol 240 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The caller is not authorized to call the function.
    error Unauthorized();

    /// @dev The `newOwner` cannot be the zero address.
    error NewOwnerIsZeroAddress();

    /// @dev The `pendingOwner` does not have a valid handover request.
    error NoHandoverRequest();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
    /// despite it not being as lightweight as a single argument event.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev An ownership handover to `pendingOwner` has been requested.
    event OwnershipHandoverRequested(address indexed pendingOwner);

    /// @dev The ownership handover to `pendingOwner` has been canceled.
    event OwnershipHandoverCanceled(address indexed pendingOwner);

    /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;

    /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
        0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;

    /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
        0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`.
    /// It is intentionally chosen to be a high value
    /// to avoid collision with lower slots.
    /// The choice of manual storage layout is to enable compatibility
    /// with both regular and upgradeable contracts.
    uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8;

    /// The ownership handover slot of `newOwner` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
    ///     let handoverSlot := keccak256(0x00, 0x20)
    /// ```
    /// It stores the expiry timestamp of the two-step ownership handover.
    uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Initializes the owner directly without authorization guard.
    /// This function must be called upon initialization,
    /// regardless of whether the contract is upgradeable or not.
    /// This is to enable generalization to both regular and upgradeable contracts,
    /// and to save gas in case the initial owner is not the caller.
    /// For performance reasons, this function will not check if there
    /// is an existing owner.
    function _initializeOwner(address newOwner) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Clean the upper 96 bits.
            newOwner := shr(96, shl(96, newOwner))
            // Store the new value.
            sstore(not(_OWNER_SLOT_NOT), newOwner)
            // Emit the {OwnershipTransferred} event.
            log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
        }
    }

    /// @dev Sets the owner directly without authorization guard.
    function _setOwner(address newOwner) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            let ownerSlot := not(_OWNER_SLOT_NOT)
            // Clean the upper 96 bits.
            newOwner := shr(96, shl(96, newOwner))
            // Emit the {OwnershipTransferred} event.
            log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
            // Store the new value.
            sstore(ownerSlot, newOwner)
        }
    }

    /// @dev Throws if the sender is not the owner.
    function _checkOwner() internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner, revert.
            if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns how long a two-step ownership handover is valid for in seconds.
    /// Override to return a different value if needed.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
        return 48 * 3600;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to transfer the ownership to `newOwner`.
    function transferOwnership(address newOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(shl(96, newOwner)) {
                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
        }
        _setOwner(newOwner);
    }

    /// @dev Allows the owner to renounce their ownership.
    function renounceOwnership() public payable virtual onlyOwner {
        _setOwner(address(0));
    }

    /// @dev Request a two-step ownership handover to the caller.
    /// The request will automatically expire in 48 hours (172800 seconds) by default.
    function requestOwnershipHandover() public payable virtual {
        unchecked {
            uint256 expires = block.timestamp + _ownershipHandoverValidFor();
            /// @solidity memory-safe-assembly
            assembly {
                // Compute and set the handover slot to `expires`.
                mstore(0x0c, _HANDOVER_SLOT_SEED)
                mstore(0x00, caller())
                sstore(keccak256(0x0c, 0x20), expires)
                // Emit the {OwnershipHandoverRequested} event.
                log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
            }
        }
    }

    /// @dev Cancels the two-step ownership handover to the caller, if any.
    function cancelOwnershipHandover() public payable virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x20), 0)
            // Emit the {OwnershipHandoverCanceled} event.
            log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
        }
    }

    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            let handoverSlot := keccak256(0x0c, 0x20)
            // If the handover does not exist, or has expired.
            if gt(timestamp(), sload(handoverSlot)) {
                mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                revert(0x1c, 0x04)
            }
            // Set the handover slot to 0.
            sstore(handoverSlot, 0)
        }
        _setOwner(pendingOwner);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the owner of the contract.
    function owner() public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(not(_OWNER_SLOT_NOT))
        }
    }

    /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
    function ownershipHandoverExpiresAt(address pendingOwner)
        public
        view
        virtual
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the handover slot.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            // Load the handover slot.
            result := sload(keccak256(0x0c, 0x20))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         MODIFIERS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Marks a function as only callable by the owner.
    modifier onlyOwner() virtual {
        _checkOwner();
        _;
    }
}
IFxGenArt721.sol 418 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {GenArtInfo, InitInfo, IssuerInfo, MetadataInfo, MintInfo, ProjectInfo, ReserveInfo} from "src/lib/Structs.sol";
import {ISeedConsumer} from "src/interfaces/ISeedConsumer.sol";
import {IToken} from "src/interfaces/IToken.sol";

/**
 * @title IFxGenArt721
 * @author fx(hash)
 * @notice ERC-721 token for generative art projects created on fxhash
 */
interface IFxGenArt721 is ISeedConsumer, IToken {
    /*//////////////////////////////////////////////////////////////////////////
                                  EVENTS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @notice Event emitted when the base URI is updated
     * @param _uri Decoded content identifier of metadata pointer
     */
    event BaseURIUpdated(bytes _uri);

    /**
     * @notice Event emitted when public burn is enabled or disabled
     * @param _flag Status of burn
     */
    event BurnEnabled(bool indexed _flag);

    /**
     * @notice Event emitted when public mint is enabled or disabled
     * @param _flag Status of mint
     */
    event MintEnabled(bool indexed _flag);

    /**
     * @notice Event emitted when project is deleted only once supply is set to zero
     */
    event ProjectDeleted();

    /**
     * @notice Event emitted when new project is initialized
     * @param _primaryReceiver Address of splitter contract receiving primary sales
     * @param _projectInfo Project information
     * @param _metadataInfo Metadata information of token
     * @param _mintInfo Array of authorized minter contracts and their reserves
     */
    event ProjectInitialized(
        address indexed _primaryReceiver,
        ProjectInfo _projectInfo,
        MetadataInfo _metadataInfo,
        MintInfo[] _mintInfo
    );

    /**
     * @notice Event emitted when the primary receiver address is updated
     * @param _receiver The split address receiving funds on behalf of the users
     * @param _receivers Array of addresses receiving a portion of the funds in a split
     * @param _allocations Array of allocation shares for the split
     */
    event PrimaryReceiverUpdated(address indexed _receiver, address[] _receivers, uint32[] _allocations);

    /**
     * @notice Event emitted when project tags are set
     * @param _tagIds Array of tag IDs describing the project
     */
    event ProjectTags(uint256[] indexed _tagIds);

    /**
     * @notice Event emitted when Randomizer contract is updated
     * @param _randomizer Address of new Randomizer contract
     */
    event RandomizerUpdated(address indexed _randomizer);

    /**
     * @notice Event emitted when Renderer contract is updated
     * @param _renderer Address of new Renderer contract
     */
    event RendererUpdated(address indexed _renderer);

    /**
     * @notice Event emitted when onchain data of project is updated
     * @param _pointer SSTORE2 pointer to the onchain data
     */
    event OnchainPointerUpdated(address _pointer);

    /**
     * @notice Event emitted when maximum supply is reduced
     * @param _prevSupply Amount of previous supply
     * @param _newSupply Amount of new supply
     */
    event SupplyReduced(uint120 indexed _prevSupply, uint120 indexed _newSupply);

    /*//////////////////////////////////////////////////////////////////////////
                                  ERRORS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @notice Error thrown when total minter allocation exceeds maximum supply
     */
    error AllocationExceeded();

    /**
     *  @notice Error thrown when burning is inactive
     */
    error BurnInactive();

    /**
     * @notice Error thrown when the fee receiver address is not included in the receiver allocations
     */
    error FeeReceiverMissing();

    /**
     * @notice Error thrown when remaining supply is zero
     */
    error InsufficientSupply();

    /**
     * @notice Error thrown when max supply amount is invalid
     */
    error InvalidAmount();

    /**
     * @notice Error thrown when input size does not match actual byte size of params data
     */
    error InvalidInputSize();

    /**
     * @notice Error thrown when reserve start time is invalid
     */
    error InvalidStartTime();

    /**
     * @notice Error thrown when reserve end time is invalid
     */
    error InvalidEndTime();

    /**
     * @notice Error thrown when the configured fee receiver is not valid
     */
    error InvalidFeeReceiver();

    /**
     * @notice Error thrown when minting is active
     */
    error MintActive();

    /**
     *  @notice Error thrown when minting is inactive
     */
    error MintInactive();

    /**
     * @notice Error thrown when caller is not authorized to execute transaction
     */
    error NotAuthorized();

    /**
     * @notice Error thrown when signer is not the owner
     */
    error NotOwner();

    /**
     * @notice Error thrown when supply is remaining
     */
    error SupplyRemaining();

    /**
     * @notice Error thrown when caller does not have the specified role
     */
    error UnauthorizedAccount();

    /**
     * @notice Error thrown when caller does not have minter role
     */
    error UnauthorizedMinter();

    /**
     * @notice Error thrown when minter is not registered on token contract
     */
    error UnregisteredMinter();

    /*//////////////////////////////////////////////////////////////////////////
                                  FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /*
     * @notice Returns the list of minter contracts currently active on the token
     */
    function activeMinters() external view returns (address[] memory);

    /**
     * @notice Burns token ID from the circulating supply
     * @param _tokenId ID of the token
     */
    function burn(uint256 _tokenId) external;

    /**
     * @notice Returns address of the FxContractRegistry contract
     */
    function contractRegistry() external view returns (address);

    /**
     * @notice Returns contract-level metadata for storefront marketplaces
     */
    function contractURI() external view returns (string memory);

    /**
     * @inheritdoc ISeedConsumer
     */
    function fulfillSeedRequest(uint256 _tokenId, bytes32 _seed) external;

    /**
     * @notice Mapping of token ID to GenArtInfo struct (minter, seed, fxParams)
     */
    function genArtInfo(uint256 _tokenId) external view returns (address, bytes32, bytes memory);

    /**
     * @notice Generates typed data hash for setting project metadata onchain
     * @param _data Bytes-encoded onchain data
     * @return Typed data hash
     */
    function generateOnchainPointerHash(bytes calldata _data) external view returns (bytes32);

    /**
     * @notice Generates typed data hash for setting the primary receiver address
     * @param _renderer Address of the new renderer contract
     * @return Typed data hash
     */
    function generateRendererHash(address _renderer) external view returns (bytes32);

    /**
     * @notice Initializes new generative art project
     * @param _owner Address of token proxy owner
     * @param _initInfo Initialization information set on project creation
     * @param _projectInfo Project information
     * @param _metadataInfo Metadata information
     * @param _mintInfo Array of authorized minter contracts and their reserves
     * @param _royaltyReceivers Array of addresses receiving royalties
     * @param _allocations Array of allocation amounts for calculating royalty shares
     * @param _basisPoints Total allocation scalar for calculating royalty shares
     */
    function initialize(
        address _owner,
        InitInfo calldata _initInfo,
        ProjectInfo calldata _projectInfo,
        MetadataInfo calldata _metadataInfo,
        MintInfo[] calldata _mintInfo,
        address[] calldata _royaltyReceivers,
        uint32[] calldata _allocations,
        uint96 _basisPoints
    ) external;

    /**
     * @notice Gets the authorization status for the given minter contract
     * @param _minter Address of the minter contract
     * @return Authorization status
     */
    function isMinter(address _minter) external view returns (bool);

    /**
     * @notice Returns the issuer information of the project (primaryReceiver, ProjectInfo)
     */
    function issuerInfo() external view returns (address, ProjectInfo memory);

    /**
     * @notice Returns the metadata information of the project (baseURI, onchainPointer)
     */
    function metadataInfo() external view returns (bytes memory, address);

    /**
     * @inheritdoc IToken
     */
    function mint(address _to, uint256 _amount, uint256 _payment) external;

    /**
     * @notice Mints single fxParams token
     * @dev Only callable by registered minter contracts
     * @param _to Address receiving minted token
     * @param _fxParams Random sequence of fixed-length bytes used as input
     */
    function mintParams(address _to, bytes calldata _fxParams) external;

    /**
     * @notice Current nonce for admin signatures
     */
    function nonce() external returns (uint96);

    /**
     * @notice Mints single token with randomly generated seed
     * @dev Only callable by contract owner
     * @param _to Address receiving token
     */
    function ownerMint(address _to) external;

    /**
     * @notice Mints single fxParams token
     * @dev Only callable by contract owner
     * @param _to Address receiving minted token
     * @param _fxParams Random sequence of fixed-length bytes used as input
     */
    function ownerMintParams(address _to, bytes calldata _fxParams) external;

    /**
     * @notice Pauses all function executions where modifier is applied
     */
    function pause() external;

    /**
     * @inheritdoc IToken
     */
    function primaryReceiver() external view returns (address);

    /**
     * @notice Returns the address of the randomizer contract
     */
    function randomizer() external view returns (address);

    /**
     * @notice Reduces maximum supply of collection
     * @param _supply Maximum supply amount
     */
    function reduceSupply(uint120 _supply) external;

    /**
     * @notice Registers minter contracts with resereve info
     * @param _mintInfo Mint information of token reserves
     */
    function registerMinters(MintInfo[] memory _mintInfo) external;

    /**
     * @notice Returns the remaining supply of tokens left to mint
     */
    function remainingSupply() external view returns (uint256);

    /**
     * @notice Returns the address of the Renderer contract
     */
    function renderer() external view returns (address);

    /**
     * @notice Returns the address of the FxRoleRegistry contract
     */
    function roleRegistry() external view returns (address);

    /**
     * @notice Sets the base royalties for all secondary token sales
     * @param _receivers Array of addresses receiving royalties
     * @param _allocations Array of allocations used to calculate royalty payments
     * @param _basisPoints basis points used to calculate royalty payments
     */
    function setBaseRoyalties(
        address[] calldata _receivers,
        uint32[] calldata _allocations,
        uint96 _basisPoints
    ) external;

    /**
     * @notice Sets the new URI of the token metadata
     * @param _uri Decoded content identifier of metadata pointer
     */
    function setBaseURI(bytes calldata _uri) external;

    /**
     * @notice Sets flag status of public burn to enabled or disabled
     * @param _flag Status of burn
     */
    function setBurnEnabled(bool _flag) external;

    /**
     * @notice Sets flag status of public mint to enabled or disabled
     * @param _flag Status of mint
     */
    function setMintEnabled(bool _flag) external;

    /**
     * @notice Sets the onchain pointer for reconstructing project metadata onchain
     * @param _onchainData Bytes-encoded metadata
     * @param _signature Signature of creator used to verify metadata update
     */
    function setOnchainPointer(bytes calldata _onchainData, bytes calldata _signature) external;

    /**
     * @notice Sets the primary receiver address for primary sale proceeds
     * @param _receivers Array of addresses receiving shares from primary sales
     * @param _allocations Array of allocation amounts for calculating primary sales shares
     */
    function setPrimaryReceivers(address[] calldata _receivers, uint32[] calldata _allocations) external;

    /**
     * @notice Sets the new randomizer contract
     * @param _randomizer Address of the randomizer contract
     */
    function setRandomizer(address _randomizer) external;

    /**
     * @notice Sets the new renderer contract
     * @param _renderer Address of the renderer contract
     * @param _signature Signature of creator used to verify renderer update
     */
    function setRenderer(address _renderer, bytes calldata _signature) external;

    /**
     * @notice Emits an event for setting tag descriptions for the project
     * @param _tagIds Array of tag IDs describing the project
     */
    function setTags(uint256[] calldata _tagIds) external;

    /**
     * @notice Returns the current circulating supply of tokens
     */
    function totalSupply() external view returns (uint96);

    /**
     * @notice Unpauses all function executions where modifier is applied
     */
    function unpause() external;
}
ISeedConsumer.sol 32 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

/**
 * @title ISeedConsumer
 * @author fx(hash)
 * @notice Interface for randomizers to interact with FxGenArt721 tokens
 */
interface ISeedConsumer {
    /*//////////////////////////////////////////////////////////////////////////
                                  EVENTS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @notice Event emitted when a seed request is fulfilled for a specific token
     * @param _randomizer Address of the randomizer contract
     * @param _tokenId ID of the token
     * @param _seed Hash of the random seed
     */
    event SeedFulfilled(address indexed _randomizer, uint256 indexed _tokenId, bytes32 _seed);

    /*//////////////////////////////////////////////////////////////////////////
                                  FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @notice Fullfills the random seed request on the FxGenArt721 token contract
     * @param _tokenId ID of the token
     * @param _seed Hash of the random seed
     */
    function fulfillSeedRequest(uint256 _tokenId, bytes32 _seed) external;
}
LibClone.sol 592 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Minimal proxy library.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibClone.sol)
/// @author Minimal proxy by 0age (https://github.com/0age)
/// @author Clones with immutable args by wighawag, zefram.eth, Saw-mon & Natalie
/// (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args)
///
/// @dev Minimal proxy:
/// Although the sw0nt pattern saves 5 gas over the erc-1167 pattern during runtime,
/// it is not supported out-of-the-box on Etherscan. Hence, we choose to use the 0age pattern,
/// which saves 4 gas over the erc-1167 pattern during runtime, and has the smallest bytecode.
///
/// @dev Minimal proxy (PUSH0 variant):
/// This is a new minimal proxy that uses the PUSH0 opcode introduced during Shanghai.
/// It is optimized first for minimal runtime gas, then for minimal bytecode.
/// The PUSH0 clone functions are intentionally postfixed with a jarring "_PUSH0" as
/// many EVM chains may not support the PUSH0 opcode in the early months after Shanghai.
/// Please use with caution.
///
/// @dev Clones with immutable args (CWIA):
/// The implementation of CWIA here implements a `receive()` method that emits the
/// `ReceiveETH(uint256)` event. This skips the `DELEGATECALL` when there is no calldata,
/// enabling us to accept hard gas-capped `sends` & `transfers` for maximum backwards
/// composability. The minimal proxy implementation does not offer this feature.
library LibClone {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Unable to deploy the clone.
    error DeploymentFailed();

    /// @dev The salt must start with either the zero address or the caller.
    error SaltDoesNotStartWithCaller();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  MINIMAL PROXY OPERATIONS                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Deploys a clone of `implementation`.
    function clone(address implementation) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            /**
             * --------------------------------------------------------------------------+
             * CREATION (9 bytes)                                                        |
             * --------------------------------------------------------------------------|
             * Opcode     | Mnemonic          | Stack     | Memory                       |
             * --------------------------------------------------------------------------|
             * 60 runSize | PUSH1 runSize     | r         |                              |
             * 3d         | RETURNDATASIZE    | 0 r       |                              |
             * 81         | DUP2              | r 0 r     |                              |
             * 60 offset  | PUSH1 offset      | o r 0 r   |                              |
             * 3d         | RETURNDATASIZE    | 0 o r 0 r |                              |
             * 39         | CODECOPY          | 0 r       | [0..runSize): runtime code   |
             * f3         | RETURN            |           | [0..runSize): runtime code   |
             * --------------------------------------------------------------------------|
             * RUNTIME (44 bytes)                                                        |
             * --------------------------------------------------------------------------|
             * Opcode  | Mnemonic       | Stack                  | Memory                |
             * --------------------------------------------------------------------------|
             *                                                                           |
             * ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: |
             * 3d      | RETURNDATASIZE | 0                      |                       |
             * 3d      | RETURNDATASIZE | 0 0                    |                       |
             * 3d      | RETURNDATASIZE | 0 0 0                  |                       |
             * 3d      | RETURNDATASIZE | 0 0 0 0                |                       |
             *                                                                           |
             * ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: |
             * 36      | CALLDATASIZE   | cds 0 0 0 0            |                       |
             * 3d      | RETURNDATASIZE | 0 cds 0 0 0 0          |                       |
             * 3d      | RETURNDATASIZE | 0 0 cds 0 0 0 0        |                       |
             * 37      | CALLDATACOPY   | 0 0 0 0                | [0..cds): calldata    |
             *                                                                           |
             * ::: delegate call to the implementation contract :::::::::::::::::::::::: |
             * 36      | CALLDATASIZE   | cds 0 0 0 0            | [0..cds): calldata    |
             * 3d      | RETURNDATASIZE | 0 cds 0 0 0 0          | [0..cds): calldata    |
             * 73 addr | PUSH20 addr    | addr 0 cds 0 0 0 0     | [0..cds): calldata    |
             * 5a      | GAS            | gas addr 0 cds 0 0 0 0 | [0..cds): calldata    |
             * f4      | DELEGATECALL   | success 0 0            | [0..cds): calldata    |
             *                                                                           |
             * ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: |
             * 3d      | RETURNDATASIZE | rds success 0 0        | [0..cds): calldata    |
             * 3d      | RETURNDATASIZE | rds rds success 0 0    | [0..cds): calldata    |
             * 93      | SWAP4          | 0 rds success 0 rds    | [0..cds): calldata    |
             * 80      | DUP1           | 0 0 rds success 0 rds  | [0..cds): calldata    |
             * 3e      | RETURNDATACOPY | success 0 rds          | [0..rds): returndata  |
             *                                                                           |
             * 60 0x2a | PUSH1 0x2a     | 0x2a success 0 rds     | [0..rds): returndata  |
             * 57      | JUMPI          | 0 rds                  | [0..rds): returndata  |
             *                                                                           |
             * ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * fd      | REVERT         |                        | [0..rds): returndata  |
             *                                                                           |
             * ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 5b      | JUMPDEST       | 0 rds                  | [0..rds): returndata  |
             * f3      | RETURN         |                        | [0..rds): returndata  |
             * --------------------------------------------------------------------------+
             */

            mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
            mstore(0x14, implementation)
            mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
            instance := create(0, 0x0c, 0x35)
            // Restore the part of the free memory pointer that has been overwritten.
            mstore(0x21, 0)
            // If `instance` is zero, revert.
            if iszero(instance) {
                // Store the function selector of `DeploymentFailed()`.
                mstore(0x00, 0x30116425)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Deploys a deterministic clone of `implementation` with `salt`.
    function cloneDeterministic(address implementation, bytes32 salt)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
            mstore(0x14, implementation)
            mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
            instance := create2(0, 0x0c, 0x35, salt)
            // Restore the part of the free memory pointer that has been overwritten.
            mstore(0x21, 0)
            // If `instance` is zero, revert.
            if iszero(instance) {
                // Store the function selector of `DeploymentFailed()`.
                mstore(0x00, 0x30116425)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns the initialization code hash of the clone of `implementation`.
    /// Used for mining vanity addresses with create2crunch.
    function initCodeHash(address implementation) internal pure returns (bytes32 hash) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
            mstore(0x14, implementation)
            mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
            hash := keccak256(0x0c, 0x35)
            // Restore the part of the free memory pointer that has been overwritten.
            mstore(0x21, 0)
        }
    }

    /// @dev Returns the address of the deterministic clone of `implementation`,
    /// with `salt` by `deployer`.
    function predictDeterministicAddress(address implementation, bytes32 salt, address deployer)
        internal
        pure
        returns (address predicted)
    {
        bytes32 hash = initCodeHash(implementation);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*          MINIMAL PROXY OPERATIONS (PUSH0 VARIANT)          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Deploys a PUSH0 clone of `implementation`.
    function clone_PUSH0(address implementation) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            /**
             * --------------------------------------------------------------------------+
             * CREATION (9 bytes)                                                        |
             * --------------------------------------------------------------------------|
             * Opcode     | Mnemonic          | Stack     | Memory                       |
             * --------------------------------------------------------------------------|
             * 60 runSize | PUSH1 runSize     | r         |                              |
             * 5f         | PUSH0             | 0 r       |                              |
             * 81         | DUP2              | r 0 r     |                              |
             * 60 offset  | PUSH1 offset      | o r 0 r   |                              |
             * 5f         | PUSH0             | 0 o r 0 r |                              |
             * 39         | CODECOPY          | 0 r       | [0..runSize): runtime code   |
             * f3         | RETURN            |           | [0..runSize): runtime code   |
             * --------------------------------------------------------------------------|
             * RUNTIME (45 bytes)                                                        |
             * --------------------------------------------------------------------------|
             * Opcode  | Mnemonic       | Stack                  | Memory                |
             * --------------------------------------------------------------------------|
             *                                                                           |
             * ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: |
             * 5f      | PUSH0          | 0                      |                       |
             * 5f      | PUSH0          | 0 0                    |                       |
             *                                                                           |
             * ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: |
             * 36      | CALLDATASIZE   | cds 0 0                |                       |
             * 5f      | PUSH0          | 0 cds 0 0              |                       |
             * 5f      | PUSH0          | 0 0 cds 0 0            |                       |
             * 37      | CALLDATACOPY   | 0 0                    | [0..cds): calldata    |
             *                                                                           |
             * ::: delegate call to the implementation contract :::::::::::::::::::::::: |
             * 36      | CALLDATASIZE   | cds 0 0                | [0..cds): calldata    |
             * 5f      | PUSH0          | 0 cds 0 0              | [0..cds): calldata    |
             * 73 addr | PUSH20 addr    | addr 0 cds 0 0         | [0..cds): calldata    |
             * 5a      | GAS            | gas addr 0 cds 0 0     | [0..cds): calldata    |
             * f4      | DELEGATECALL   | success                | [0..cds): calldata    |
             *                                                                           |
             * ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: |
             * 3d      | RETURNDATASIZE | rds success            | [0..cds): calldata    |
             * 5f      | PUSH0          | 0 rds success          | [0..cds): calldata    |
             * 5f      | PUSH0          | 0 0 rds success        | [0..cds): calldata    |
             * 3e      | RETURNDATACOPY | success                | [0..rds): returndata  |
             *                                                                           |
             * 60 0x29 | PUSH1 0x29     | 0x29 success           | [0..rds): returndata  |
             * 57      | JUMPI          |                        | [0..rds): returndata  |
             *                                                                           |
             * ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d      | RETURNDATASIZE | rds                    | [0..rds): returndata  |
             * 5f      | PUSH0          | 0 rds                  | [0..rds): returndata  |
             * fd      | REVERT         |                        | [0..rds): returndata  |
             *                                                                           |
             * ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 5b      | JUMPDEST       |                        | [0..rds): returndata  |
             * 3d      | RETURNDATASIZE | rds                    | [0..rds): returndata  |
             * 5f      | PUSH0          | 0 rds                  | [0..rds): returndata  |
             * f3      | RETURN         |                        | [0..rds): returndata  |
             * --------------------------------------------------------------------------+
             */

            mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
            mstore(0x14, implementation) // 20
            mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
            instance := create(0, 0x0e, 0x36)
            // Restore the part of the free memory pointer that has been overwritten.
            mstore(0x24, 0)
            // If `instance` is zero, revert.
            if iszero(instance) {
                // Store the function selector of `DeploymentFailed()`.
                mstore(0x00, 0x30116425)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Deploys a deterministic PUSH0 clone of `implementation` with `salt`.
    function cloneDeterministic_PUSH0(address implementation, bytes32 salt)
        internal
        returns (address instance)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
            mstore(0x14, implementation) // 20
            mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
            instance := create2(0, 0x0e, 0x36, salt)
            // Restore the part of the free memory pointer that has been overwritten.
            mstore(0x24, 0)
            // If `instance` is zero, revert.
            if iszero(instance) {
                // Store the function selector of `DeploymentFailed()`.
                mstore(0x00, 0x30116425)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns the initialization code hash of the PUSH0 clone of `implementation`.
    /// Used for mining vanity addresses with create2crunch.
    function initCodeHash_PUSH0(address implementation) internal pure returns (bytes32 hash) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
            mstore(0x14, implementation) // 20
            mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
            hash := keccak256(0x0e, 0x36)
            // Restore the part of the free memory pointer that has been overwritten.
            mstore(0x24, 0)
        }
    }

    /// @dev Returns the address of the deterministic PUSH0 clone of `implementation`,
    /// with `salt` by `deployer`.
    function predictDeterministicAddress_PUSH0(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes32 hash = initCodeHash_PUSH0(implementation);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*           CLONES WITH IMMUTABLE ARGS OPERATIONS            */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Deploys a minimal proxy with `implementation`,
    /// using immutable arguments encoded in `data`.
    function clone(address implementation, bytes memory data) internal returns (address instance) {
        assembly {
            // Compute the boundaries of the data and cache the memory slots around it.
            let mBefore3 := mload(sub(data, 0x60))
            let mBefore2 := mload(sub(data, 0x40))
            let mBefore1 := mload(sub(data, 0x20))
            let dataLength := mload(data)
            let dataEnd := add(add(data, 0x20), dataLength)
            let mAfter1 := mload(dataEnd)

            // +2 bytes for telling how much data there is appended to the call.
            let extraLength := add(dataLength, 2)
            // The `creationSize` is `extraLength + 108`
            // The `runSize` is `creationSize - 10`.

            /**
             * ---------------------------------------------------------------------------------------------------+
             * CREATION (10 bytes)                                                                                |
             * ---------------------------------------------------------------------------------------------------|
             * Opcode     | Mnemonic          | Stack     | Memory                                                |
             * ---------------------------------------------------------------------------------------------------|
             * 61 runSize | PUSH2 runSize     | r         |                                                       |
             * 3d         | RETURNDATASIZE    | 0 r       |                                                       |
             * 81         | DUP2              | r 0 r     |                                                       |
             * 60 offset  | PUSH1 offset      | o r 0 r   |                                                       |
             * 3d         | RETURNDATASIZE    | 0 o r 0 r |                                                       |
             * 39         | CODECOPY          | 0 r       | [0..runSize): runtime code                            |
             * f3         | RETURN            |           | [0..runSize): runtime code                            |
             * ---------------------------------------------------------------------------------------------------|
             * RUNTIME (98 bytes + extraLength)                                                                   |
             * ---------------------------------------------------------------------------------------------------|
             * Opcode   | Mnemonic       | Stack                    | Memory                                      |
             * ---------------------------------------------------------------------------------------------------|
             *                                                                                                    |
             * ::: if no calldata, emit event & return w/o `DELEGATECALL` ::::::::::::::::::::::::::::::::::::::: |
             * 36       | CALLDATASIZE   | cds                      |                                             |
             * 60 0x2c  | PUSH1 0x2c     | 0x2c cds                 |                                             |
             * 57       | JUMPI          |                          |                                             |
             * 34       | CALLVALUE      | cv                       |                                             |
             * 3d       | RETURNDATASIZE | 0 cv                     |                                             |
             * 52       | MSTORE         |                          | [0..0x20): callvalue                        |
             * 7f sig   | PUSH32 0x9e..  | sig                      | [0..0x20): callvalue                        |
             * 59       | MSIZE          | 0x20 sig                 | [0..0x20): callvalue                        |
             * 3d       | RETURNDATASIZE | 0 0x20 sig               | [0..0x20): callvalue                        |
             * a1       | LOG1           |                          | [0..0x20): callvalue                        |
             * 00       | STOP           |                          | [0..0x20): callvalue                        |
             * 5b       | JUMPDEST       |                          |                                             |
             *                                                                                                    |
             * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 36       | CALLDATASIZE   | cds                      |                                             |
             * 3d       | RETURNDATASIZE | 0 cds                    |                                             |
             * 3d       | RETURNDATASIZE | 0 0 cds                  |                                             |
             * 37       | CALLDATACOPY   |                          | [0..cds): calldata                          |
             *                                                                                                    |
             * ::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d       | RETURNDATASIZE | 0                        | [0..cds): calldata                          |
             * 3d       | RETURNDATASIZE | 0 0                      | [0..cds): calldata                          |
             * 3d       | RETURNDATASIZE | 0 0 0                    | [0..cds): calldata                          |
             * 3d       | RETURNDATASIZE | 0 0 0 0                  | [0..cds): calldata                          |
             * 61 extra | PUSH2 extra    | e 0 0 0 0                | [0..cds): calldata                          |
             *                                                                                                    |
             * ::: copy extra data to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 80       | DUP1           | e e 0 0 0 0              | [0..cds): calldata                          |
             * 60 0x62  | PUSH1 0x62     | 0x62 e e 0 0 0 0         | [0..cds): calldata                          |
             * 36       | CALLDATASIZE   | cds 0x62 e e 0 0 0 0     | [0..cds): calldata                          |
             * 39       | CODECOPY       | e 0 0 0 0                | [0..cds): calldata, [cds..cds+e): extraData |
             *                                                                                                    |
             * ::: delegate call to the implementation contract ::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 36       | CALLDATASIZE   | cds e 0 0 0 0            | [0..cds): calldata, [cds..cds+e): extraData |
             * 01       | ADD            | cds+e 0 0 0 0            | [0..cds): calldata, [cds..cds+e): extraData |
             * 3d       | RETURNDATASIZE | 0 cds+e 0 0 0 0          | [0..cds): calldata, [cds..cds+e): extraData |
             * 73 addr  | PUSH20 addr    | addr 0 cds+e 0 0 0 0     | [0..cds): calldata, [cds..cds+e): extraData |
             * 5a       | GAS            | gas addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
             * f4       | DELEGATECALL   | success 0 0              | [0..cds): calldata, [cds..cds+e): extraData |
             *                                                                                                    |
             * ::: copy return data to memory ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 3d       | RETURNDATASIZE | rds success 0 0          | [0..cds): calldata, [cds..cds+e): extraData |
             * 3d       | RETURNDATASIZE | rds rds success 0 0      | [0..cds): calldata, [cds..cds+e): extraData |
             * 93       | SWAP4          | 0 rds success 0 rds      | [0..cds): calldata, [cds..cds+e): extraData |
             * 80       | DUP1           | 0 0 rds success 0 rds    | [0..cds): calldata, [cds..cds+e): extraData |
             * 3e       | RETURNDATACOPY | success 0 rds            | [0..rds): returndata                        |
             *                                                                                                    |
             * 60 0x60  | PUSH1 0x60     | 0x60 success 0 rds       | [0..rds): returndata                        |
             * 57       | JUMPI          | 0 rds                    | [0..rds): returndata                        |
             *                                                                                                    |
             * ::: revert ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * fd       | REVERT         |                          | [0..rds): returndata                        |
             *                                                                                                    |
             * ::: return ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
             * 5b       | JUMPDEST       | 0 rds                    | [0..rds): returndata                        |
             * f3       | RETURN         |                          | [0..rds): returndata                        |
             * ---------------------------------------------------------------------------------------------------+
             */
            // Write the bytecode before the data.
            mstore(data, 0x5af43d3d93803e606057fd5bf3)
            // Write the address of the implementation.
            mstore(sub(data, 0x0d), implementation)
            // Write the rest of the bytecode.
            mstore(
                sub(data, 0x21),
                or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)
            )
            // `keccak256("ReceiveETH(uint256)")`
            mstore(
                sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff
            )
            mstore(
                sub(data, 0x5a),
                or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f)
            )
            mstore(dataEnd, shl(0xf0, extraLength))

            // Create the instance.
            instance := create(0, sub(data, 0x4c), add(extraLength, 0x6c))

            // If `instance` is zero, revert.
            if iszero(instance) {
                // Store the function selector of `DeploymentFailed()`.
                mstore(0x00, 0x30116425)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Restore the overwritten memory surrounding `data`.
            mstore(dataEnd, mAfter1)
            mstore(data, dataLength)
            mstore(sub(data, 0x20), mBefore1)
            mstore(sub(data, 0x40), mBefore2)
            mstore(sub(data, 0x60), mBefore3)
        }
    }

    /// @dev Deploys a deterministic clone of `implementation`,
    /// using immutable arguments encoded in `data`, with `salt`.
    function cloneDeterministic(address implementation, bytes memory data, bytes32 salt)
        internal
        returns (address instance)
    {
        assembly {
            // Compute the boundaries of the data and cache the memory slots around it.
            let mBefore3 := mload(sub(data, 0x60))
            let mBefore2 := mload(sub(data, 0x40))
            let mBefore1 := mload(sub(data, 0x20))
            let dataLength := mload(data)
            let dataEnd := add(add(data, 0x20), dataLength)
            let mAfter1 := mload(dataEnd)

            // +2 bytes for telling how much data there is appended to the call.
            let extraLength := add(dataLength, 2)

            // Write the bytecode before the data.
            mstore(data, 0x5af43d3d93803e606057fd5bf3)
            // Write the address of the implementation.
            mstore(sub(data, 0x0d), implementation)
            // Write the rest of the bytecode.
            mstore(
                sub(data, 0x21),
                or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)
            )
            // `keccak256("ReceiveETH(uint256)")`
            mstore(
                sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff
            )
            mstore(
                sub(data, 0x5a),
                or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f)
            )
            mstore(dataEnd, shl(0xf0, extraLength))

            // Create the instance.
            instance := create2(0, sub(data, 0x4c), add(extraLength, 0x6c), salt)

            // If `instance` is zero, revert.
            if iszero(instance) {
                // Store the function selector of `DeploymentFailed()`.
                mstore(0x00, 0x30116425)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Restore the overwritten memory surrounding `data`.
            mstore(dataEnd, mAfter1)
            mstore(data, dataLength)
            mstore(sub(data, 0x20), mBefore1)
            mstore(sub(data, 0x40), mBefore2)
            mstore(sub(data, 0x60), mBefore3)
        }
    }

    /// @dev Returns the initialization code hash of the clone of `implementation`
    /// using immutable arguments encoded in `data`.
    /// Used for mining vanity addresses with create2crunch.
    function initCodeHash(address implementation, bytes memory data)
        internal
        pure
        returns (bytes32 hash)
    {
        assembly {
            // Compute the boundaries of the data and cache the memory slots around it.
            let mBefore3 := mload(sub(data, 0x60))
            let mBefore2 := mload(sub(data, 0x40))
            let mBefore1 := mload(sub(data, 0x20))
            let dataLength := mload(data)
            let dataEnd := add(add(data, 0x20), dataLength)
            let mAfter1 := mload(dataEnd)

            // +2 bytes for telling how much data there is appended to the call.
            let extraLength := add(dataLength, 2)

            // Write the bytecode before the data.
            mstore(data, 0x5af43d3d93803e606057fd5bf3)
            // Write the address of the implementation.
            mstore(sub(data, 0x0d), implementation)
            // Write the rest of the bytecode.
            mstore(
                sub(data, 0x21),
                or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)
            )
            // `keccak256("ReceiveETH(uint256)")`
            mstore(
                sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff
            )
            mstore(
                sub(data, 0x5a),
                or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f)
            )
            mstore(dataEnd, shl(0xf0, extraLength))

            // Compute and store the bytecode hash.
            hash := keccak256(sub(data, 0x4c), add(extraLength, 0x6c))

            // Restore the overwritten memory surrounding `data`.
            mstore(dataEnd, mAfter1)
            mstore(data, dataLength)
            mstore(sub(data, 0x20), mBefore1)
            mstore(sub(data, 0x40), mBefore2)
            mstore(sub(data, 0x60), mBefore3)
        }
    }

    /// @dev Returns the address of the deterministic clone of
    /// `implementation` using immutable arguments encoded in `data`, with `salt`, by `deployer`.
    function predictDeterministicAddress(
        address implementation,
        bytes memory data,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes32 hash = initCodeHash(implementation, data);
        predicted = predictDeterministicAddress(hash, salt, deployer);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      OTHER OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the address when a contract with initialization code hash,
    /// `hash`, is deployed with `salt`, by `deployer`.
    function predictDeterministicAddress(bytes32 hash, bytes32 salt, address deployer)
        internal
        pure
        returns (address predicted)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and store the bytecode hash.
            mstore8(0x00, 0xff) // Write the prefix.
            mstore(0x35, hash)
            mstore(0x01, shl(96, deployer))
            mstore(0x15, salt)
            predicted := keccak256(0x00, 0x55)
            // Restore the part of the free memory pointer that has been overwritten.
            mstore(0x35, 0)
        }
    }

    /// @dev Reverts if `salt` does not start with either the zero address or the caller.
    function checkStartsWithCaller(bytes32 salt) internal view {
        /// @solidity memory-safe-assembly
        assembly {
            // If the salt does not start with the zero address or the caller.
            if iszero(or(iszero(shr(96, salt)), eq(caller(), shr(96, salt)))) {
                // Store the function selector of `SaltDoesNotStartWithCaller()`.
                mstore(0x00, 0x2f634836)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
        }
    }
}
FxIssuerFactory.sol 190 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {LibClone} from "solady/src/utils/LibClone.sol";
import {Ownable} from "solady/src/auth/Ownable.sol";
import {Pausable} from "openzeppelin-contracts/contracts/security/Pausable.sol";

import {IAccessControl} from "openzeppelin/contracts/access/IAccessControl.sol";
import {IFxGenArt721, InitInfo, MetadataInfo, MintInfo, ProjectInfo} from "src/interfaces/IFxGenArt721.sol";
import {IFxIssuerFactory} from "src/interfaces/IFxIssuerFactory.sol";
import {IFxTicketFactory} from "src/interfaces/IFxTicketFactory.sol";

/**
 * @title FxIssuerFactory
 * @author fx(hash)
 * @dev See the documentation in {IFxIssuerFactory}
 */
contract FxIssuerFactory is IFxIssuerFactory, Ownable, Pausable {
    /*//////////////////////////////////////////////////////////////////////////
                                    STORAGE
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @inheritdoc IFxIssuerFactory
     */
    address public immutable roleRegistry;

    /**
     * @inheritdoc IFxIssuerFactory
     */
    address public implementation;

    /**
     * @inheritdoc IFxIssuerFactory
     */
    uint96 public projectId;

    /**
     * @inheritdoc IFxIssuerFactory
     */
    mapping(address => uint256) public nonces;

    /**
     * @inheritdoc IFxIssuerFactory
     */
    mapping(uint96 => address) public projects;

    /*//////////////////////////////////////////////////////////////////////////
                                    CONSTRUCTOR
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @dev Initializes factory owner, FxRoleRegistry and FxGenArt721 implementation
     */
    constructor(address _admin, address _roleRegistry, address _implementation) {
        _pause();
        roleRegistry = _roleRegistry;
        _initializeOwner(_admin);
        _setImplementation(_implementation);
    }

    /*//////////////////////////////////////////////////////////////////////////
                                EXTERNAL FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @inheritdoc IFxIssuerFactory
     */
    function createProjectWithTicket(
        bytes calldata _projectCreationInfo,
        bytes calldata _ticketCreationInfo,
        address _ticketFactory
    ) external whenNotPaused returns (address genArtToken, address mintTicket) {
        genArtToken = createProject(_projectCreationInfo);
        mintTicket = IFxTicketFactory(_ticketFactory).createTicket(_ticketCreationInfo);
    }

    /**
     * @inheritdoc IFxIssuerFactory
     */
    function unpause() external onlyOwner {
        _unpause();
    }

    /**
     * @inheritdoc IFxIssuerFactory
     */
    function pause() external onlyOwner {
        _pause();
    }

    /**
     * @inheritdoc IFxIssuerFactory
     */
    function setImplementation(address _implementation) external onlyOwner {
        _setImplementation(_implementation);
    }

    /*//////////////////////////////////////////////////////////////////////////
                                PUBLIC FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @inheritdoc IFxIssuerFactory
     */
    function createProject(bytes memory _creationInfo) public returns (address genArt721) {
        (
            address _owner,
            InitInfo memory _initInfo,
            ProjectInfo memory _projectInfo,
            MetadataInfo memory _metadataInfo,
            MintInfo[] memory _mintInfo,
            address[] memory _royaltyReceivers,
            uint32[] memory _allocations,
            uint96 _basisPoints
        ) = abi.decode(
                _creationInfo,
                (address, InitInfo, ProjectInfo, MetadataInfo, MintInfo[], address[], uint32[], uint96)
            );

        genArt721 = createProjectWithParams(
            _owner,
            _initInfo,
            _projectInfo,
            _metadataInfo,
            _mintInfo,
            _royaltyReceivers,
            _allocations,
            _basisPoints
        );
    }

    /**
     * @inheritdoc IFxIssuerFactory
     */
    function createProjectWithParams(
        address _owner,
        InitInfo memory _initInfo,
        ProjectInfo memory _projectInfo,
        MetadataInfo memory _metadataInfo,
        MintInfo[] memory _mintInfo,
        address[] memory _royaltyReceivers,
        uint32[] memory _allocations,
        uint96 _basisPoints
    ) public whenNotPaused returns (address genArtToken) {
        if (_owner == address(0)) revert InvalidOwner();

        bytes32 salt = keccak256(abi.encode(msg.sender, nonces[msg.sender]));
        genArtToken = LibClone.cloneDeterministic(implementation, salt);
        nonces[msg.sender]++;
        projects[++projectId] = genArtToken;

        emit ProjectCreated(projectId, genArtToken, _owner);

        IFxGenArt721(genArtToken).initialize(
            _owner,
            _initInfo,
            _projectInfo,
            _metadataInfo,
            _mintInfo,
            _royaltyReceivers,
            _allocations,
            _basisPoints
        );
    }

    /*//////////////////////////////////////////////////////////////////////////
                                VIEW FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @inheritdoc IFxIssuerFactory
     */
    function getTokenAddress(address _sender) external view returns (address) {
        bytes32 salt = keccak256(abi.encode(_sender, nonces[_sender]));
        return LibClone.predictDeterministicAddress(implementation, salt, address(this));
    }

    /*//////////////////////////////////////////////////////////////////////////
                                INTERNAL FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @dev Sets the FxGenArt721 implementation contract
     */
    function _setImplementation(address _implementation) internal {
        implementation = _implementation;
        emit ImplementationUpdated(msg.sender, _implementation);
    }
}
IFxIssuerFactory.sol 143 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {InitInfo, MetadataInfo, MintInfo, ProjectInfo} from "src/lib/Structs.sol";

/**
 * @title IFxIssuerFactory
 * @author fx(hash)
 * @notice Factory for managing newly deployed FxGenArt721 tokens
 */
interface IFxIssuerFactory {
    /*//////////////////////////////////////////////////////////////////////////
                                  EVENTS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @notice Event emitted when the FxGenArt721 implementation contract is updated
     * @param _owner Address of the factory owner
     * @param _implementation Address of the new FxGenArt721 implementation contract
     */
    event ImplementationUpdated(address indexed _owner, address indexed _implementation);

    /**
     * @notice Event emitted when a new generative art project is created
     * @param _projectId ID of the project
     * @param _genArtToken Address of newly deployed FxGenArt721 token contract
     * @param _owner Address of project owner
     */
    event ProjectCreated(uint96 indexed _projectId, address indexed _genArtToken, address indexed _owner);

    /*//////////////////////////////////////////////////////////////////////////
                                  ERRORS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @notice Error thrown when owner is zero address
     */
    error InvalidOwner();

    /**
     * @notice Error thrown when primary receiver is zero address
     */
    error InvalidPrimaryReceiver();

    /**
     * @notice Error thrown when caller is not authorized to execute transaction
     */
    error NotAuthorized();

    /*//////////////////////////////////////////////////////////////////////////
                                  FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @notice Creates new generative art project
     * @param _owner Address of project owner
     * @param _initInfo Initialization information
     * @param _projectInfo Project information
     * @param _metadataInfo Metadata information
     * @param _mintInfo Array of authorized minter contracts and their reserves
     * @param _royaltyReceivers Array of addresses receiving royalties
     * @param _allocations Array of allocation amounts for calculating royalty shares
     * @param _basisPoints Total allocation scalar for calculating royalty shares
     * @return genArtToken Address of newly created FxGenArt721 proxy
     */
    function createProjectWithParams(
        address _owner,
        InitInfo memory _initInfo,
        ProjectInfo memory _projectInfo,
        MetadataInfo memory _metadataInfo,
        MintInfo[] memory _mintInfo,
        address[] memory _royaltyReceivers,
        uint32[] memory _allocations,
        uint96 _basisPoints
    ) external returns (address);

    /**
     * @notice Creates new generative art project with single parameter
     * @param _creationInfo Bytes-encoded data for project creation
     * @return genArtToken Address of newly created FxGenArt721 proxy
     */
    function createProject(bytes memory _creationInfo) external returns (address);

    /**
     * @notice Creates new generative art project with new mint ticket in single transaction
     * @param _projectCreationInfo Bytes-encoded data for project creation
     * @param _ticketCreationInfo Bytes-encoded data for ticket creation
     * @param _tickeFactory Address of FxTicketFactory contract
     * @return genArtToken Address of newly created FxGenArt721 proxy
     * @return mintTicket Address of newly created FxMintTicket721 proxy
     */
    function createProjectWithTicket(
        bytes calldata _projectCreationInfo,
        bytes calldata _ticketCreationInfo,
        address _tickeFactory
    ) external returns (address, address);

    /**
     * @notice Calculates the CREATE2 address of a new FxGenArt721 proxy
     */
    function getTokenAddress(address _sender) external view returns (address);

    /**
     * @notice Returns address of current FxGenArt721 implementation contract
     */
    function implementation() external view returns (address);

    /**
     * @notice Mapping of deployer address to nonce value for precomputing token address
     */
    function nonces(address _deployer) external view returns (uint256);

    /**
     * @notice Stops new FxGenArt721 tokens from being created
     */
    function pause() external;

    /**
     * @notice Returns counter of latest project ID
     */
    function projectId() external view returns (uint96);

    /**
     * @notice Mapping of project ID to address of FxGenArt721 token contract
     */
    function projects(uint96) external view returns (address);

    /**
     * @notice Returns the address of the FxRoleRegistry contract
     */
    function roleRegistry() external view returns (address);

    /**
     * @notice Sets new FxGenArt721 implementation contract
     * @param _implementation Address of the implementation contract
     */
    function setImplementation(address _implementation) external;

    /**
     * @notice Enables new FxGenArt721 tokens from being created
     */
    function unpause() external;
}
IFxTicketFactory.sol 137 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {MintInfo} from "src/lib/Structs.sol";

/**
 * @title IFxTicketFactory
 * @author fx(hash)
 * @notice Factory for managing newly deployed FxMintTicket721 tokens
 */
interface IFxTicketFactory {
    /*//////////////////////////////////////////////////////////////////////////
                                  EVENTS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @notice Event emitted when the minimum grace period is updated
     * @param _owner Address of the factory owner
     * @param _gracePeriod Time duration of the new grace period
     */
    event GracePeriodUpdated(address indexed _owner, uint48 indexed _gracePeriod);

    /**
     * @notice Event emitted when the FxMintTicket721 implementation contract is updated
     * @param _owner Address of the factory owner
     * @param _implementation Address of the new FxMintTicket721 implementation contract
     */
    event ImplementationUpdated(address indexed _owner, address indexed _implementation);

    /**
     * @notice Event emitted when new FxMintTicket721 is created
     * @param _ticketId ID of the ticket contract
     * @param _mintTicket Address of newly deployed FxMintTicket721 token contract
     * @param _owner Address of ticket owner
     */
    event TicketCreated(uint96 indexed _ticketId, address indexed _mintTicket, address indexed _owner);

    /*//////////////////////////////////////////////////////////////////////////
                                  ERRORS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @notice Error thrown when grace period is less than minimum requirement of one day
     */
    error InvalidGracePeriod();

    /**
     * @notice Error thrown when owner is zero address
     */
    error InvalidOwner();

    /**
     * @notice Error thrown when redeemer contract is zero address
     */
    error InvalidRedeemer();

    /**
     * @notice Error thrown when renderer contract is zero address
     */
    error InvalidRenderer();

    /**
     * @notice Error thrown when token contract is zero address
     */
    error InvalidToken();

    /*//////////////////////////////////////////////////////////////////////////
                                  FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @notice Creates new mint ticket
     * @param _owner Address of project owner
     * @param _genArt721 Address of GenArt721 token contract
     * @param _redeemer Address of TicketRedeemer minter contract
     * @param _redeemer Address of renderer contract
     * @param _gracePeriod Duration of time before token enters harberger taxation
     * @param _mintInfo Array of authorized minter contracts and their reserves
     */
    function createTicket(
        address _owner,
        address _genArt721,
        address _redeemer,
        address _renderer,
        uint48 _gracePeriod,
        MintInfo[] memory _mintInfo
    ) external returns (address);

    /**
     * @notice Creates new mint ticket for new generative art project in single transaction
     * @param _creationInfo Bytes-encoded data for ticket creation
     * @return mintTicket Address of newly created FxMintTicket721 proxy
     */
    function createTicket(bytes calldata _creationInfo) external returns (address);

    /**
     * @notice Calculates the CREATE2 address of a new FxMintTicket721 proxy
     */
    function getTicketAddress(address _sender) external view returns (address);

    /**
     * @notice Returns address of current FxMintTicket721 implementation contract
     */
    function implementation() external view returns (address);

    /**
     * @notice Returns the minimum duration of time before a ticket enters harberger taxation
     */
    function minGracePeriod() external view returns (uint48);

    /**
     * @notice Mapping of deployer address to nonce value for precomputing ticket address
     */
    function nonces(address _deployer) external view returns (uint256);

    /**
     * @notice Sets the new minimum grace period
     * @param _gracePeriod Minimum time duration before a ticket enters harberger taxation
     */
    function setMinGracePeriod(uint48 _gracePeriod) external;

    /**
     * @notice Sets new FxMintTicket721 implementation contract
     * @param _implementation Address of the implementation contract
     */
    function setImplementation(address _implementation) external;

    /**
     * @notice Returns counter of latest token ID
     */
    function ticketId() external view returns (uint48);

    /**
     * @notice Mapping of token ID to address of FxMintTicket721 token contract
     */
    function tickets(uint48 _ticketId) external view returns (address);
}
Context.sol 24 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}
Pausable.sol 105 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

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

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

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

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

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

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

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

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}
IAccessControl.sol 88 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

Read Contract

getTokenAddress 0xb8d7b669 → address
implementation 0x5c60da1b → address
nonces 0x7ecebe00 → uint256
owner 0x8da5cb5b → address
ownershipHandoverExpiresAt 0xfee81cf4 → uint256
paused 0x5c975abb → bool
projectId 0x3fafa127 → uint96
projects 0x94a37936 → address
roleRegistry 0x08c73259 → address

Write Contract 11 functions

These functions modify contract state and require a wallet transaction to execute.

cancelOwnershipHandover 0x54d1f13d
No parameters
completeOwnershipHandover 0xf04e283e
address pendingOwner
createProject 0xabb1ab94
bytes _creationInfo
returns: address
createProjectWithParams 0xc8fd3a91
address _owner
tuple _initInfo
tuple _projectInfo
tuple _metadataInfo
tuple[] _mintInfo
address[] _royaltyReceivers
uint32[] _allocations
uint96 _basisPoints
returns: address
createProjectWithTicket 0x7d8983cf
bytes _projectCreationInfo
bytes _ticketCreationInfo
address _ticketFactory
returns: address, address
pause 0x8456cb59
No parameters
renounceOwnership 0x715018a6
No parameters
requestOwnershipHandover 0x25692962
No parameters
setImplementation 0xd784d426
address _implementation
transferOwnership 0xf2fde38b
address newOwner
unpause 0x3f4ba83a
No parameters

Recent Transactions

No transactions found for this address