Address Contract Verified
Address
0x442295de8A31d65026dBc09c29d469F6854f188a
Balance
0 ETH
Nonce
141
Code Size
7637 bytes
Creator
Create2 Deployer at tx 0x05d69dfe...370273
Indexed Transactions
0
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