ERC-721
Overview
Max Total Supply
128 256ART
Holders
72
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Balance
2 256ARTLoading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Minimal Proxy Contract for 0x3c3a6ae1cc64cc514d554856d34c7f86c244abc8
Contract Name:
TwoFiveSixProjectDefaultV2
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 0 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT /* ██████╗ ███████╗ ██████╗ ╚════██╗██╔════╝██╔════╝ █████╔╝███████╗███████╗ ██╔═══╝ ╚════██║██╔═══██╗ ███████╗███████║╚██████╔╝ ╚══════╝╚══════╝ ╚═════╝ Using this contract? A shout out to @Mint256Art is appreciated! */ pragma solidity ^0.8.25; import "./helpers/SSTORE2.sol"; import "./helpers/ERC721EnumerableUpgradeable.sol"; import "@openzeppelin/contracts/utils/Base64.sol"; import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; import "./helpers/File.sol"; contract TwoFiveSixProjectDefaultV2 is ERC721EnumerableUpgradeable { // ------------------------------------------------------------------------ // CUSTOM ERRORS // ------------------------------------------------------------------------ error SaleNotStarted(); error SaleEnded(); error MintedOut(); error MaxFourExceeded(); error AuctionOngoing(); error NotOnAllowList(); error AlreadyClaimed(); error InvalidFunds(); error ContractMintingNotAllowed(); error MinOneTokenRequired(); error RebateNotStarted(); error AuctionInProgress(); error ZeroBalance(); error TokenNotFound(); error TooLow(); error TooHigh(); error NotAllowed(); // ------------------------------------------------------------------------ // STATE VARIABLES // ------------------------------------------------------------------------ mapping(uint256 => bytes32) public tokenIdToHash; mapping(address => TotalAndCount) private addressToTotalAndCount; mapping(address => uint16) private addressToClaimed; struct Project { string name; //unknown string imageBase; //unkown address[] artScripts; //unknown address payable[] receivers; // unknown (0 will be owner, 1 will be 256ART, ) uint24[] shares; // unknown (0 will be owner, 1 will be 256ART, total has to be 10000) bytes32 merkleRoot; //32 address artInfo; //20 uint56 publicStartTimeStamp; //8 uint32 maxSupply; //4 // Set to one more for calculations address traits; //20 uint96 reservePrice; //12 address payable royaltyAddress; //20 uint96 lastSalePrice; //12 address libraryScripts; //20 uint56 endingTimeStamp; //8 uint24 royalty; //3 bool fixedPrice; //1 uint96 allowListPrice; //12 uint56 allowListStartTimeStamp; //8 uint32 totalAllowListMints; //4 uint24 artistAuctionWithdrawalsClaimed; //3 uint24 artistAllowListWithdrawalsClaimed; //3 uint16 allowedAmountPerALAddress; // 2 // Set to one more for calculations } struct Trait { string name; string[] values; string[] descriptions; uint256[] weights; } struct TotalAndCount { uint128 total; uint128 count; } struct LibraryScript { address fileStore; string fileName; } Project private project; event ImageBaseUpdated(string newImageBase); event MaxSupplyUpdated(uint24 newMaxSupply); /** * @notice Initializes the project. * @dev Initializes the ERC721 contract. * @param _p The project data. */ function initProject( Project calldata _p, address _traits, address _libraryScripts ) public initializer { __ERC721_init(_p.name, "256ART"); __Ownable_init(_p.receivers[0]); // receiver 0 is owner project = _p; if (_traits != address(0)) { project.traits = _traits; } if (_libraryScripts != address(0)) { project.libraryScripts = _libraryScripts; } } /** * @notice Gets the current price in public phase. */ function currentPrice() public view returns (uint256 p) { if (block.timestamp <= project.publicStartTimeStamp) revert SaleNotStarted(); if (block.timestamp >= project.endingTimeStamp) revert SaleEnded(); uint256 timeElapsed = block.timestamp - project.publicStartTimeStamp; uint256 price; if (timeElapsed < 3600 && !project.fixedPrice) { // Example falling price logic price = (((((project.reservePrice * 15 ** 8) / (10 ** 8)) / (15 ** (timeElapsed / 450))) * (10 ** (timeElapsed / 450))) / 10 ** 14) * 10 ** 14; return price; } else { return project.reservePrice; } } /** * @notice Mint tokens to an address (artist only) * @dev Mints a given number of tokens to a specified address. Can only be called by the project owner. * @param count The number of tokens to be minted. * @param a The address to which the tokens will be minted. */ function artistMint(uint24 count, address a) public onlyOwner { uint256 totalSupply = _owners.length; if (totalSupply + count >= project.maxSupply) revert MintedOut(); if (block.timestamp >= project.endingTimeStamp) revert SaleEnded(); if (count > 4) revert MaxFourExceeded(); // If dutch auction is not fixed and is active, revert if (!project.fixedPrice) { bool auctionActive = block.timestamp >= project.publicStartTimeStamp && block.timestamp <= (project.publicStartTimeStamp + 3600); if (auctionActive) revert AuctionOngoing(); } for (uint256 i; i < count; ) { unchecked { uint256 tokenId = totalSupply + i; tokenIdToHash[tokenId] = createHash( tokenId, project.receivers[0] ); _mint(a, tokenId); i++; } } unchecked { project.artistAuctionWithdrawalsClaimed = project.artistAuctionWithdrawalsClaimed + count; } } /** * @notice Mint a token to an allow listed address if conditions met. * @param proof The proof of inclusion in the project's Merkle tree. * @param a The address to which the token will be minted. */ function allowListMint( bytes32[] memory proof, address a, uint16 count ) public payable { if (block.timestamp <= project.allowListStartTimeStamp) revert SaleNotStarted(); if (block.timestamp >= project.publicStartTimeStamp) revert SaleEnded(); if ( !MerkleProof.verify( proof, project.merkleRoot, keccak256(abi.encodePacked(a)) ) ) revert NotOnAllowList(); if (addressToClaimed[a] + count >= project.allowedAmountPerALAddress) revert AlreadyClaimed(); uint256 totalSupply = _owners.length; if (totalSupply + count >= project.maxSupply) revert MintedOut(); if ((project.allowListPrice * count) > msg.value) revert InvalidFunds(); if (msg.sender != tx.origin) revert ContractMintingNotAllowed(); unchecked { addressToClaimed[a] = addressToClaimed[a] + count; project.totalAllowListMints = project.totalAllowListMints + count; } for (uint256 i; i < count; ) { unchecked { uint256 tokenId = totalSupply + i; tokenIdToHash[tokenId] = createHash(tokenId, msg.sender); _mint(a, tokenId); i++; } } } /** * @notice Check whether a given address is on the allowlist and how many remain to claim. */ function checkAllowListAndClaimStatus( address a, bytes32[] memory proof ) public view returns (bool, uint16) { bytes32 hash = keccak256(abi.encodePacked(a)); bool isOnList = MerkleProof.verify(proof, project.merkleRoot, hash); uint16 leftToClaim = project.allowedAmountPerALAddress - addressToClaimed[a] - 1; return (isOnList, leftToClaim); } /** * @notice Mint tokens to an address through a Dutch auction until reserve price is met. * @param count The number of tokens to be minted. * @param a The address to which the tokens will be minted. */ function publicMint(uint128 count, address a) public payable { uint256 totalSupply = _owners.length; uint256 price = currentPrice(); uint256 total = count * price; if (totalSupply + count >= project.maxSupply) revert MintedOut(); if (count == 0) revert MinOneTokenRequired(); if (count > 4) revert MaxFourExceeded(); if (total > msg.value) revert InvalidFunds(); if (msg.sender != tx.origin) revert ContractMintingNotAllowed(); // Track amounts for rebates if the final price changes if (price != project.reservePrice) { addressToTotalAndCount[a] = TotalAndCount( uint128(addressToTotalAndCount[a].total + msg.value), addressToTotalAndCount[a].count + count ); } // If this mint ends the auction, record lastSalePrice if ( (totalSupply + count) == (project.maxSupply - 1) && !project.fixedPrice ) { project.lastSalePrice = uint96(price); } for (uint256 i; i < count; ) { unchecked { uint256 tokenId = totalSupply + i; tokenIdToHash[tokenId] = createHash(tokenId, msg.sender); _mint(a, tokenId); i++; } } } /** * @notice Claim a rebate for each token minted at a higher price than the final price. */ function claimRebate(address payable a) public { // Rebate can only be claimed after the auction is (effectively) over if (block.timestamp <= project.publicStartTimeStamp + 3600) revert RebateNotStarted(); uint256 finalPrice; if ( _owners.length < (project.maxSupply - 1) || project.lastSalePrice == 0 ) { finalPrice = project.reservePrice; } else { finalPrice = project.lastSalePrice; } uint256 rebate = addressToTotalAndCount[a].total - (addressToTotalAndCount[a].count * finalPrice); delete addressToTotalAndCount[a]; a.transfer(rebate); } /** * @notice Create a hash for the given tokenId, blockNumber, and sender. */ function createHash( uint256 tokenId, address sender ) private view returns (bytes32) { unchecked { return keccak256( abi.encodePacked( tokenId, sender, blockhash(block.number - 1), blockhash(block.number - 2), blockhash(block.number - 4), block.prevrandao, block.coinbase ) ); } } /** * @notice Withdraw funds from the contract. */ function withdraw() public { if ( msg.sender != project.receivers[0] && msg.sender != project.receivers[1] ) revert NotAllowed(); uint256 totalSupply = _owners.length; uint256 finalPrice; uint256 totalBalance; if (project.fixedPrice) { totalBalance = address(this).balance; } else { // Auction logic, must be after the 1-hour mark if (block.timestamp <= project.publicStartTimeStamp + 3600) revert AuctionInProgress(); if ( _owners.length < (project.maxSupply - 1) || project.lastSalePrice == 0 ) { finalPrice = project.reservePrice; } else { finalPrice = project.lastSalePrice; } totalBalance = ( (totalSupply - project.totalAllowListMints - project.artistAuctionWithdrawalsClaimed) ) * finalPrice + ( (project.totalAllowListMints - project.artistAllowListWithdrawalsClaimed) ) * project.allowListPrice; } if (totalBalance == 0) revert ZeroBalance(); project.artistAuctionWithdrawalsClaimed = uint24( totalSupply - project.totalAllowListMints ); project.artistAllowListWithdrawalsClaimed = uint24( project.totalAllowListMints ); uint256 remainingBalance = totalBalance; for (uint256 i = 1; i < project.receivers.length; ) { unchecked { uint256 payment = (totalBalance * project.shares[i]) / 10000; project.receivers[i].transfer(payment); remainingBalance -= payment; i++; } } // Transfer any leftover (owner is at index 0, but we rely on Ownable's owner()) payable(owner()).transfer(remainingBalance); } /** * @notice Calculates the royalty information for a given sale. */ function royaltyInfo( uint256, uint256 _salePrice ) external view returns (address receiver, uint256 royaltyAmount) { return (project.royaltyAddress, (_salePrice * project.royalty) / 10000); } /** * @dev Generates an array of random numbers based on a seed value. */ function generateRandomNumbers( bytes32 seed, uint256 timesToCall ) private pure returns (uint256[] memory) { uint256[] memory randNumbers = new uint256[](timesToCall); for (uint256 i; i < timesToCall; i++) { uint256 r = uint256( keccak256(abi.encodePacked(uint256(seed) + i)) ) % 10000; randNumbers[i] = r; } return randNumbers; } /** * @notice Returns a string containing base64 encoded HTML code which renders the artwork. */ function tokenHTML( uint256 tokenId ) public view returns (string memory artwork) { if (!_exists(tokenId)) revert TokenNotFound(); string memory artScript; string memory libraryScripts; string memory traits; string memory blockParams; // Load library scripts if (project.libraryScripts != address(0)) { LibraryScript[] memory librariesArray = abi.decode( SSTORE2.read(project.libraryScripts), (LibraryScript[]) ); for (uint256 l; l < librariesArray.length; l++) { IFileStore fileStore = IFileStore(librariesArray[l].fileStore); libraryScripts = string.concat( libraryScripts, "await ls256('", fileStore.getFile(librariesArray[l].fileName).read(), "');" ); } } // Load traits if present if (project.traits != address(0)) { traits = ","; Trait[] memory traitsArray = abi.decode( SSTORE2.read(project.traits), (Trait[]) ); uint256[] memory randNumbers = generateRandomNumbers( tokenIdToHash[tokenId], traitsArray.length ); for (uint256 j = 0; j < traitsArray.length; j++) { uint256 r = randNumbers[j]; for (uint256 k = 0; k < traitsArray[j].weights.length; k++) { if (r < traitsArray[j].weights[k]) { traits = string.concat( traits, "'", traitsArray[j].name, "'", ":{value: '", traitsArray[j].values[k], "',", "description: '", traitsArray[j].descriptions[k], "'}" ); if (j < traitsArray.length - 1) { traits = string.concat(traits, ","); } break; } } } } // Block params blockParams = string.concat( ", 'ownerOfPiece' : '", Strings.toHexString(uint256(uint160(ownerOf(tokenId))), 20), "', 'blockHash' : '", Strings.toHexString(uint256(blockhash(block.number - 1)), 32), "', 'blockNumber' : ", Strings.toString(block.number), ", 'blockTimestamp' : ", Strings.toString(block.timestamp), ", 'blockBaseFee' : ", Strings.toString(block.basefee), ", 'blockCoinbase' : '", Strings.toHexString(uint256(uint160(address(block.coinbase))), 20), "', 'prevrandao' : ", Strings.toString(block.prevrandao), ", 'totalSupply' : ", Strings.toString(_owners.length), ", 'balanceOfOwner' : ", Strings.toString(balanceOf(ownerOf(tokenId))), ", 'ethBalanceOfOwner' : ", Strings.toString(ownerOf(tokenId).balance) ); // Concatenate all art scripts for (uint256 i; i < project.artScripts.length; i++) { IArtScript artscriptToGet = IArtScript(project.artScripts[i]); artScript = string.concat(artScript, artscriptToGet.artScript()); } return string.concat( "data:text/html;base64,", Base64.encode( abi.encodePacked( "<html><head><script>let inputData={'tokenId': ", Strings.toString(tokenId), ",'hash': '", Strings.toHexString( uint256(tokenIdToHash[tokenId]), 32 ), "'", traits, blockParams, "};", "</script>", "<meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1'><style type='text/css'>html{height:100%;width:100%;}body{height:100%;width:100%;margin:0;padding:0;background:#000000;}canvas{max-width:100%;max-height:100%;padding:0;margin:auto;position:absolute;top:0;bottom:0;left:0;right:0;object-fit:contain;}</style>", "</head><body><script defer>async function ls256(e){let t=new TextDecoder,a=window.atob(e),n=a.length,r=new Uint8Array(n);for(var o=0;o<n;o++)r[o]=a.charCodeAt(o);let d=r.buffer;let c=new ReadableStream({start(e){e.enqueue(d),e.close()}}).pipeThrough(new DecompressionStream('gzip')),i=await new Response(c),p=await i.arrayBuffer(),l=await t.decode(p),s=document.createElement('script');s.type='text/javascript',s.appendChild(document.createTextNode(l)),document.body.appendChild(s)};async function la256(){", libraryScripts, "await ls256('", artScript, "');" "};la256();</script></body></html>" ) ) ); } /** * @notice Returns metadata of the token with the given ID. */ function tokenURI(uint256 _tokenId) public view returns (string memory) { if (!_exists(_tokenId)) revert TokenNotFound(); IArtInfo artInfoToGet = IArtInfo(project.artInfo); string memory imageBase; string memory librariesUsed = ',"libraries": "'; string memory attributes; if (bytes(project.imageBase).length != 0) { imageBase = string.concat( ',"image":"', project.imageBase, Strings.toString(_tokenId), '"' ); } if (project.libraryScripts != address(0)) { LibraryScript[] memory librariesArray = abi.decode( SSTORE2.read(project.libraryScripts), (LibraryScript[]) ); for (uint256 l; l < librariesArray.length; l++) { librariesUsed = string.concat( librariesUsed, librariesArray[l].fileName, " " ); } } else { librariesUsed = string.concat(librariesUsed, "None"); } librariesUsed = string.concat(librariesUsed, '"'); if (project.traits != address(0)) { Trait[] memory traitsArray = abi.decode( SSTORE2.read(project.traits), (Trait[]) ); uint256[] memory randNumbers = generateRandomNumbers( tokenIdToHash[_tokenId], traitsArray.length ); for (uint256 j = 0; j < traitsArray.length; j++) { uint256 r = randNumbers[j]; for (uint256 k = 0; k < traitsArray[j].weights.length; k++) { if (r < traitsArray[j].weights[k]) { attributes = string.concat( attributes, '{"trait_type":"', traitsArray[j].name, '", "value":"', traitsArray[j].descriptions[k], '"}' ); if (j < traitsArray.length - 1) { attributes = string.concat(attributes, ","); } break; } } } } return string.concat( "data:application/json;base64,", Base64.encode( abi.encodePacked( '{"name":"', project.name, " #", Strings.toString(_tokenId), '", "artist":"', artInfoToGet.artist(), '","description":"', artInfoToGet.description(), '","license":"', artInfoToGet.license(), '","hash":"', Strings.toHexString( uint256(tokenIdToHash[_tokenId]), 32 ), '"', librariesUsed, imageBase, ',"animation_url":"', tokenHTML(_tokenId), '","attributes":[', attributes, "]}" ) ) ); } /** * @notice Allows the owner to set the image base URL for the project. */ function setImageBase(string calldata _imageBase) public onlyOwner { project.imageBase = _imageBase; emit ImageBaseUpdated(_imageBase); } /** * @notice Allows the owner to update the allowlist's Merkle root. */ function setMerkleRoot(bytes32 _merkleRoot) public onlyOwner { project.merkleRoot = _merkleRoot; } /** * @notice Allows the owner to update the royalty percentage. */ function setRoyalty(uint24 _royalty) public onlyOwner { project.royalty = _royalty; } /** * @notice Sets the max number of tokens that can be minted for the project. */ function setMaxSupply(uint24 _maxSupply) public onlyOwner { // Must be greater than total minted so far... if (_maxSupply <= _owners.length) revert TooLow(); // ...and less than the current maxSupply if (_maxSupply >= project.maxSupply) revert TooHigh(); project.maxSupply = _maxSupply + 1; emit MaxSupplyUpdated(_maxSupply); } /** * @notice Allows the owner to set the art scripts for the project. */ function setArtScripts(address[] calldata _artScripts) public onlyOwner { project.artScripts = _artScripts; } /** * @notice Allows the owner to set the library scripts for the project. */ function setLibraryScripts( LibraryScript[] calldata _libraries ) public onlyOwner { address libScripts = SSTORE2.write(abi.encode(_libraries)); project.libraryScripts = libScripts; } /** * @notice Returns basic details about the project. */ function getProjectDetails() external view returns ( bool fixedPrice, uint256 reservePrice, uint256 allowListPrice, uint256 publicStartTimeStamp, uint256 allowListStartTimeStamp, uint256 maxSupply ) { return ( project.fixedPrice, project.reservePrice, project.allowListPrice, project.publicStartTimeStamp, project.allowListStartTimeStamp, project.maxSupply - 1 ); } } interface IArtScript { function artScript() external pure returns (string memory); } interface IArtInfo { function artist() external pure returns (string memory); function description() external pure returns (string memory); function license() external pure returns (string memory); } interface IFileStore { function getFile( string memory filename ) external view returns (File memory file); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165Upgradeable is Initializable, IERC165 { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol) pragma solidity ^0.8.20; import {IERC721} from "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Enumerable is IERC721 { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.20; import {IERC721} from "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or * {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the address zero. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be * reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.2) (utils/Base64.sol) pragma solidity ^0.8.20; /** * @dev Provides a set of functions to operate with Base64 strings. */ library Base64 { /** * @dev Base64 Encoding/Decoding Table */ string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** * @dev Converts a `bytes` to its Bytes64 `string` representation. */ function encode(bytes memory data) internal pure returns (string memory) { /** * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol */ if (data.length == 0) return ""; // Loads the table into memory string memory table = _TABLE; // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter // and split into 4 numbers of 6 bits. // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up // - `data.length + 2` -> Round up // - `/ 3` -> Number of 3-bytes chunks // - `4 *` -> 4 characters for each chunk string memory result = new string(4 * ((data.length + 2) / 3)); /// @solidity memory-safe-assembly assembly { // Prepare the lookup table (skip the first "length" byte) let tablePtr := add(table, 1) // Prepare result pointer, jump over length let resultPtr := add(result, 0x20) let dataPtr := data let endPtr := add(data, mload(data)) // In some cases, the last iteration will read bytes after the end of the data. We cache the value, and // set it to zero to make sure no dirty bytes are read in that section. let afterPtr := add(endPtr, 0x20) let afterCache := mload(afterPtr) mstore(afterPtr, 0x00) // Run over the input, 3 bytes at a time for { } lt(dataPtr, endPtr) { } { // Advance 3 bytes dataPtr := add(dataPtr, 3) let input := mload(dataPtr) // To write each character, shift the 3 byte (24 bits) chunk // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) // and apply logical AND with 0x3F to bitmask the least significant 6 bits. // Use this as an index into the lookup table, mload an entire word // so the desired character is in the least significant byte, and // mstore8 this least significant byte into the result and continue. mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) resultPtr := add(resultPtr, 1) // Advance } // Reset the value that was cached mstore(afterPtr, afterCache) // When data `bytes` is not exactly 3 bytes long // it is padded with `=` characters at the end switch mod(mload(data), 3) case 1 { mstore8(sub(resultPtr, 1), 0x3d) mstore8(sub(resultPtr, 2), 0x3d) } case 2 { mstore8(sub(resultPtr, 1), 0x3d) } } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.20; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The tree and the proofs can be generated using our * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. * You will find a quickstart guide in the readme. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the Merkle tree could be reinterpreted as a leaf value. * OpenZeppelin's JavaScript library generates Merkle trees that are safe * against this attack out of the box. */ library MerkleProof { /** *@dev The multiproof provided is not valid. */ error MerkleProofInvalidMultiproof(); /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { return processProof(proof, leaf) == root; } /** * @dev Calldata version of {verify} */ function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Calldata version of {processProof} */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. */ function multiProofVerify( bytes32[] memory proof, bool[] memory proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProof(proof, proofFlags, leaves) == root; } /** * @dev Calldata version of {multiProofVerify} * * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. */ function multiProofVerifyCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProofCalldata(proof, proofFlags, leaves) == root; } /** * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false * respectively. * * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the Merkle tree. uint256 leavesLen = leaves.length; uint256 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. if (leavesLen + proofLen != totalHashes + 1) { revert MerkleProofInvalidMultiproof(); } // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { if (proofPos != proofLen) { revert MerkleProofInvalidMultiproof(); } unchecked { return hashes[totalHashes - 1]; } } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof}. * * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the Merkle tree. uint256 leavesLen = leaves.length; uint256 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. if (leavesLen + proofLen != totalHashes + 1) { revert MerkleProofInvalidMultiproof(); } // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { if (proofPos != proofLen) { revert MerkleProofInvalidMultiproof(); } unchecked { return hashes[totalHashes - 1]; } } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Sorts the pair (a, b) and hashes the result. */ function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _efficientHash(a, b) : _efficientHash(b, a); } /** * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory. */ function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned( int256 value ) internal pure returns (string memory) { return string.concat( value < 0 ? "-" : "", toString(SignedMath.abs(value)) ); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString( uint256 value, uint256 length ) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal( string memory a, string memory b ) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.25; library Address { function isContract(address account) internal view returns (bool) { uint256 size; assembly { size := extcodesize(account) } return size > 0; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.25; library Bytecode { error InvalidCodeAtRange(uint256 _size, uint256 _start, uint256 _end); /** @notice Generate a creation code that results on a contract with `_code` as bytecode @param _code The returning value of the resulting `creationCode` @return creationCode (constructor) for new contract */ function creationCodeFor( bytes memory _code ) internal pure returns (bytes memory) { /* 0x00 0x63 0x63XXXXXX PUSH4 _code.length size 0x01 0x80 0x80 DUP1 size size 0x02 0x60 0x600e PUSH1 14 14 size size 0x03 0x60 0x6000 PUSH1 00 0 14 size size 0x04 0x39 0x39 CODECOPY size 0x05 0x60 0x6000 PUSH1 00 0 size 0x06 0xf3 0xf3 RETURN <CODE> */ return abi.encodePacked( hex"63", uint32(_code.length), hex"80_60_0E_60_00_39_60_00_F3", _code ); } /** @notice Returns the size of the code on a given address @param _addr Address that may or may not contain code @return size of the code on the given `_addr` */ function codeSize(address _addr) internal view returns (uint256 size) { assembly { size := extcodesize(_addr) } } /** @notice Returns the code of a given address @dev It will fail if `_end < _start` @param _addr Address that may or may not contain code @param _start number of bytes of code to skip on read @param _end index before which to end extraction @return oCode read from `_addr` deployed bytecode Forked from: https://gist.github.com/KardanovIR/fe98661df9338c842b4a30306d507fbd */ function codeAt( address _addr, uint256 _start, uint256 _end ) internal view returns (bytes memory oCode) { uint256 csize = codeSize(_addr); if (csize == 0) return bytes(""); if (_start > csize) return bytes(""); if (_end < _start) revert InvalidCodeAtRange(csize, _start, _end); unchecked { uint256 reqSize = _end - _start; uint256 maxSize = csize - _start; uint256 size = maxSize < reqSize ? maxSize : reqSize; assembly { // allocate output byte array - this could also be done without assembly // by using o_code = new bytes(size) oCode := mload(0x40) // new "memory end" including padding mstore( 0x40, add(oCode, and(add(add(size, 0x20), 0x1f), not(0x1f))) ) // store length in memory mstore(oCode, size) // actually retrieve the code, this needs assembly extcodecopy(_addr, add(oCode, 0x20), _start, size) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; interface ICreatorToken { event TransferValidatorUpdated(address oldValidator, address newValidator); function getTransferValidator() external view returns (address validator); function setTransferValidator(address validator) external; function getTransferValidationFunction() external view returns (bytes4 functionSignature, bool isViewFunction); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; interface ICreatorTokenLegacy { event TransferValidatorUpdated(address oldValidator, address newValidator); function getTransferValidator() external view returns (address validator); function setTransferValidator(address validator) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; interface ITransferValidator { function applyCollectionTransferPolicy(address caller, address from, address to) external view; function validateTransfer(address caller, address from, address to) external view; function validateTransfer(address caller, address from, address to, uint256 tokenId) external view; function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external; function beforeAuthorizedTransfer(address operator, address token, uint256 tokenId) external; function afterAuthorizedTransfer(address token, uint256 tokenId) external; function beforeAuthorizedTransfer(address operator, address token) external; function afterAuthorizedTransfer(address token) external; function beforeAuthorizedTransfer(address token, uint256 tokenId) external; function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external; function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; interface ITransferValidatorSetTokenType { function setTokenTypeOfCollection(address collection, uint16 tokenType) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "../../OwnableUpgradeable.sol"; /** * @title AutomaticValidatorTransferApproval * @author Limit Break, Inc. * @notice Base contract mix-in that provides boilerplate code giving the contract owner the * option to automatically approve a 721-C transfer validator implementation for transfers. */ abstract contract AutomaticValidatorTransferApproval is OwnableUpgradeable { /// @dev Emitted when the automatic approval flag is modified by the creator. event AutomaticApprovalOfTransferValidatorSet(bool autoApproved); /// @dev If true, the collection's transfer validator is automatically approved to transfer holder's tokens. bool public autoApproveTransfersFromValidator; /** * @notice Sets if the transfer validator is automatically approved as an operator for all token owners. * * @dev Throws when the caller is not the contract owner. * * @param autoApprove If true, the collection's transfer validator will be automatically approved to * transfer holder's tokens. */ function setAutomaticApprovalOfTransfersFromValidator( bool autoApprove ) external onlyOwner { autoApproveTransfersFromValidator = autoApprove; emit AutomaticApprovalOfTransferValidatorSet(autoApprove); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "../../OwnableUpgradeable.sol"; import "../interfaces/ICreatorToken.sol"; import "../interfaces/ICreatorTokenLegacy.sol"; import "../interfaces/ITransferValidator.sol"; import "./TransferValidation.sol"; import "../interfaces/ITransferValidatorSetTokenType.sol"; /** * @title CreatorTokenBase * @author Limit Break, Inc. * @notice CreatorTokenBaseV3 is an abstract contract that provides basic functionality for managing token * transfer policies through an implementation of ICreatorTokenTransferValidator/ICreatorTokenTransferValidatorV2/ICreatorTokenTransferValidatorV3. * This contract is intended to be used as a base for creator-specific token contracts, enabling customizable transfer * restrictions and security policies. * * <h4>Features:</h4> * <ul>Ownable: This contract can have an owner who can set and update the transfer validator.</ul> * <ul>TransferValidation: Implements the basic token transfer validation interface.</ul> * * <h4>Benefits:</h4> * <ul>Provides a flexible and modular way to implement custom token transfer restrictions and security policies.</ul> * <ul>Allows creators to enforce policies such as account and codehash blacklists, whitelists, and graylists.</ul> * <ul>Can be easily integrated into other token contracts as a base contract.</ul> * * <h4>Intended Usage:</h4> * <ul>Use as a base contract for creator token implementations that require advanced transfer restrictions and * security policies.</ul> * <ul>Set and update the ICreatorTokenTransferValidator implementation contract to enforce desired policies for the * creator token.</ul> * * <h4>Compatibility:</h4> * <ul>Backward and Forward Compatible - V1/V2/V3 Creator Token Base will work with V1/V2/V3 Transfer Validators.</ul> */ abstract contract CreatorTokenBase is OwnableUpgradeable, TransferValidation, ICreatorToken { /// @dev Thrown when setting a transfer validator address that has no deployed code. error CreatorTokenBase__InvalidTransferValidatorContract(); /// @dev Instead of a constant, we store it in a state variable for upgradeable usage. address internal _defaultTransferValidator; /// @dev Used to determine if the default transfer validator is applied. /// @dev Set to true when the creator sets a transfer validator address. bool private isValidatorInitialized; /// @dev Address of the transfer validator to apply to transactions. address private transferValidator; /** * @dev Replacement for constructor in upgradeable pattern */ function __CreatorTokenBase_init() internal onlyInitializing { // You can set your default validator here in storage _defaultTransferValidator = address( 0x721C002B0059009a671D00aD1700c9748146cd1B ); // Emulate the logic that was in the constructor originally _emitDefaultTransferValidator(); _registerTokenType(_defaultTransferValidator); } /** * @notice Sets the transfer validator for the token contract. * * @dev Throws when provided validator contract is not the zero address and does not have code. * @dev Throws when the caller is not the contract owner. * * @dev <h4>Postconditions:</h4> * 1. The transferValidator address is updated. * 2. The `TransferValidatorUpdated` event is emitted. * * @param transferValidator_ The address of the transfer validator contract. */ function setTransferValidator(address transferValidator_) public onlyOwner { bool isValidTransferValidator = transferValidator_.code.length > 0; if (transferValidator_ != address(0) && !isValidTransferValidator) { revert CreatorTokenBase__InvalidTransferValidatorContract(); } emit TransferValidatorUpdated( address(getTransferValidator()), transferValidator_ ); isValidatorInitialized = true; transferValidator = transferValidator_; _registerTokenType(transferValidator_); } /** * @notice Returns the transfer validator contract address for this token contract. */ function getTransferValidator() public view override returns (address validator) { return transferValidator; } /** * @dev Pre-validates a token transfer, reverting if the transfer is not allowed by this token's security policy. * Inheriting contracts are responsible for overriding the _beforeTokenTransfer function, or its equivalent * and calling _validateBeforeTransfer so that checks can be properly applied during token transfers. * * @dev Be aware that if the msg.sender is the transfer validator, the transfer is automatically permitted, as the * transfer validator is expected to pre-validate the transfer. * * @dev Throws when the transfer doesn't comply with the collection's transfer policy, if the transferValidator is * set to a non-zero address. * * @param caller The address of the caller. * @param from The address of the sender. * @param to The address of the receiver. * @param tokenId The token id being transferred. */ function _preValidateTransfer( address caller, address from, address to, uint256 tokenId, uint256 /*value*/ ) internal virtual override { address validator = getTransferValidator(); if (validator != address(0)) { if (msg.sender == validator) { return; } ITransferValidator(validator).validateTransfer( caller, from, to, tokenId ); } } /** * @dev Pre-validates a token transfer, reverting if the transfer is not allowed by this token's security policy. * Inheriting contracts are responsible for overriding the _beforeTokenTransfer function, or its equivalent * and calling _validateBeforeTransfer so that checks can be properly applied during token transfers. * * @dev Be aware that if the msg.sender is the transfer validator, the transfer is automatically permitted, as the * transfer validator is expected to pre-validate the transfer. * * @dev Used for ERC20 and ERC1155 token transfers which have an amount value to validate in the transfer validator. * @dev The `tokenId` for ERC20 tokens should be set to `0`. * * @dev Throws when the transfer doesn't comply with the collection's transfer policy, if the transferValidator is * set to a non-zero address. * * @param caller The address of the caller. * @param from The address of the sender. * @param to The address of the receiver. * @param tokenId The token id being transferred. * @param amount The amount of token being transferred. */ function _preValidateTransfer( address caller, address from, address to, uint256 tokenId, uint256 amount, uint256 /*value*/ ) internal virtual override { address validator = getTransferValidator(); if (validator != address(0)) { if (msg.sender == validator) { return; } ITransferValidator(validator).validateTransfer( caller, from, to, tokenId, amount ); } } function _tokenType() internal pure virtual returns (uint16); function _registerTokenType(address validator) internal { if (validator != address(0)) { uint256 validatorCodeSize; assembly { validatorCodeSize := extcodesize(validator) } if (validatorCodeSize > 0) { try ITransferValidatorSetTokenType(validator) .setTokenTypeOfCollection(address(this), _tokenType()) {} catch {} } } } /** * @dev Used during contract deployment for constructable and cloneable creator tokens * @dev to emit the `TransferValidatorUpdated` event signaling the validator for the contract * @dev is the default transfer validator. */ function _emitDefaultTransferValidator() internal { emit TransferValidatorUpdated(address(0), _defaultTransferValidator); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; /** * @title TransferValidation * @author Limit Break, Inc. * @notice A mix-in that can be combined with ERC-721 contracts to provide more granular hooks. * Openzeppelin's ERC721 contract only provides hooks for before and after transfer. This allows * developers to validate or customize transfers within the context of a mint, a burn, or a transfer. */ abstract contract TransferValidation is ContextUpgradeable { /// @dev Thrown when the from and to address are both the zero address. error ShouldNotMintToBurnAddress(); /*************************************************************************/ /* Transfers Without Amounts */ /*************************************************************************/ /// @dev Inheriting contracts should call this function in the _beforeTokenTransfer function to get more granular hooks. function _validateBeforeTransfer( address from, address to, uint256 tokenId ) internal virtual { bool fromZeroAddress = from == address(0); bool toZeroAddress = to == address(0); if (fromZeroAddress && toZeroAddress) { revert ShouldNotMintToBurnAddress(); } else if (fromZeroAddress) { _preValidateMint(_msgSender(), to, tokenId, msg.value); } else if (toZeroAddress) { _preValidateBurn(_msgSender(), from, tokenId, msg.value); } else { _preValidateTransfer(_msgSender(), from, to, tokenId, msg.value); } } /// @dev Inheriting contracts should call this function in the _afterTokenTransfer function to get more granular hooks. function _validateAfterTransfer( address from, address to, uint256 tokenId ) internal virtual { bool fromZeroAddress = from == address(0); bool toZeroAddress = to == address(0); if (fromZeroAddress && toZeroAddress) { revert ShouldNotMintToBurnAddress(); } else if (fromZeroAddress) { _postValidateMint(_msgSender(), to, tokenId, msg.value); } else if (toZeroAddress) { _postValidateBurn(_msgSender(), from, tokenId, msg.value); } else { _postValidateTransfer(_msgSender(), from, to, tokenId, msg.value); } } /// @dev Optional validation hook that fires before a mint function _preValidateMint( address caller, address to, uint256 tokenId, uint256 value ) internal virtual {} /// @dev Optional validation hook that fires after a mint function _postValidateMint( address caller, address to, uint256 tokenId, uint256 value ) internal virtual {} /// @dev Optional validation hook that fires before a burn function _preValidateBurn( address caller, address from, uint256 tokenId, uint256 value ) internal virtual {} /// @dev Optional validation hook that fires after a burn function _postValidateBurn( address caller, address from, uint256 tokenId, uint256 value ) internal virtual {} /// @dev Optional validation hook that fires before a transfer function _preValidateTransfer( address caller, address from, address to, uint256 tokenId, uint256 value ) internal virtual {} /// @dev Optional validation hook that fires after a transfer function _postValidateTransfer( address caller, address from, address to, uint256 tokenId, uint256 value ) internal virtual {} /*************************************************************************/ /* Transfers With Amounts */ /*************************************************************************/ /// @dev Inheriting contracts should call this function in the _beforeTokenTransfer function to get more granular hooks. function _validateBeforeTransfer( address from, address to, uint256 tokenId, uint256 amount ) internal virtual { bool fromZeroAddress = from == address(0); bool toZeroAddress = to == address(0); if (fromZeroAddress && toZeroAddress) { revert ShouldNotMintToBurnAddress(); } else if (fromZeroAddress) { _preValidateMint(_msgSender(), to, tokenId, amount, msg.value); } else if (toZeroAddress) { _preValidateBurn(_msgSender(), from, tokenId, amount, msg.value); } else { _preValidateTransfer( _msgSender(), from, to, tokenId, amount, msg.value ); } } /// @dev Inheriting contracts should call this function in the _afterTokenTransfer function to get more granular hooks. function _validateAfterTransfer( address from, address to, uint256 tokenId, uint256 amount ) internal virtual { bool fromZeroAddress = from == address(0); bool toZeroAddress = to == address(0); if (fromZeroAddress && toZeroAddress) { revert ShouldNotMintToBurnAddress(); } else if (fromZeroAddress) { _postValidateMint(_msgSender(), to, tokenId, amount, msg.value); } else if (toZeroAddress) { _postValidateBurn(_msgSender(), from, tokenId, amount, msg.value); } else { _postValidateTransfer( _msgSender(), from, to, tokenId, amount, msg.value ); } } /// @dev Optional validation hook that fires before a mint function _preValidateMint( address caller, address to, uint256 tokenId, uint256 amount, uint256 value ) internal virtual {} /// @dev Optional validation hook that fires after a mint function _postValidateMint( address caller, address to, uint256 tokenId, uint256 amount, uint256 value ) internal virtual {} /// @dev Optional validation hook that fires before a burn function _preValidateBurn( address caller, address from, uint256 tokenId, uint256 amount, uint256 value ) internal virtual {} /// @dev Optional validation hook that fires after a burn function _postValidateBurn( address caller, address from, uint256 tokenId, uint256 amount, uint256 value ) internal virtual {} /// @dev Optional validation hook that fires before a transfer function _preValidateTransfer( address caller, address from, address to, uint256 tokenId, uint256 amount, uint256 value ) internal virtual {} /// @dev Optional validation hook that fires after a transfer function _postValidateTransfer( address caller, address from, address to, uint256 tokenId, uint256 amount, uint256 value ) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.25; import "./ERC721Upgradeable.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol"; error OOB(); // "Out of bounds" abstract contract ERC721EnumerableUpgradeable is ERC721Upgradeable, IERC721Enumerable { function supportsInterface( bytes4 interfaceId ) public view virtual override(IERC165, ERC721Upgradeable) returns (bool) { return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); } function totalSupply() public view virtual override returns (uint256) { return _owners.length; } function tokenByIndex( uint256 index ) public view virtual override returns (uint256) { if (index >= _owners.length) revert OOB(); return index; } function tokenOfOwnerByIndex( address owner, uint256 index ) public view virtual override returns (uint256 tokenId) { if (index >= balanceOf(owner)) revert OOB(); uint256 count; for (uint256 i; i < _owners.length; i++) { if (owner == _owners[i]) { if (count == index) return i; unchecked { count++; } } } revert OOB(); } function walletOfOwner( address _owner ) public view returns (uint256[] memory) { uint256 tokenCount = balanceOf(_owner); if (tokenCount == 0) return new uint256[](0); uint256[] memory tokensId = new uint256[](tokenCount); for (uint256 i; i < tokenCount; ) { tokensId[i] = tokenOfOwnerByIndex(_owner, i); unchecked { i++; } } return tokensId; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.25; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol"; import "./ERC721-C/utils/AutomaticValidatorTransferApproval.sol"; import "./ERC721-C/utils/CreatorTokenBase.sol"; import "./ERC721-C/interfaces/ITransferValidatorSetTokenType.sol"; import "./Address.sol"; error ZeroAddr(); // "No zero address" error NonExistent(); // "Nonexistent token" error NotOwnerNorApproved(); // "Not owner nor approved" error ApproveToOwner(); // "Approval to current owner" error NotOwned(); // "Not owned" error NonERC721Receiver(); // "Non ERC721Receiver implementer" error NotOwner(); // "Not owner" error NotOwnerOrContract(); // "Not owner nor contract owner" error NonZeroSender(); // Used if needed for some checks error AlreadyApproved(); // If needed error NotOwnerToken(); // "Not owner" error NoZeroOwner(); // If needed for zero checks interface IERC2981 is IERC165 { function royaltyInfo( uint256 tokenId, uint256 salePrice ) external view returns (address receiver, uint256 royaltyAmount); } interface IERC4906 is IERC165, IERC721 { event MetadataUpdate(uint256 _tokenId); event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); } abstract contract ERC721Upgradeable is ContextUpgradeable, ERC165Upgradeable, IERC721, IERC2981, IERC4906, CreatorTokenBase, AutomaticValidatorTransferApproval { using Address for address; using Strings for uint256; string private _name; string private _symbol; address[] internal _owners; mapping(uint256 => address) private _tokenApprovals; mapping(address => mapping(address => bool)) private _operatorApprovals; function __ERC721_init( string memory name_, string memory symbol_ ) internal onlyInitializing { __ERC721_init_unchained(name_, symbol_); __CreatorTokenBase_init(); } function __ERC721_init_unchained( string memory name_, string memory symbol_ ) internal onlyInitializing { _name = name_; _symbol = symbol_; } function supportsInterface( bytes4 interfaceId ) public view virtual override(ERC165Upgradeable, IERC165) returns (bool) { return interfaceId == type(IERC4906).interfaceId || interfaceId == type(IERC2981).interfaceId || interfaceId == type(ICreatorToken).interfaceId || interfaceId == type(ICreatorTokenLegacy).interfaceId || interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } function updateMetadata(uint256 tokenId) external { if (!_exists(tokenId)) revert NonExistent(); // Check ownership: either owner of token or owner of contract address tokenOwner = ownerOf(tokenId); if (msg.sender != tokenOwner && msg.sender != owner()) revert NotOwnerOrContract(); emit MetadataUpdate(tokenId); } function updateBatchMetadata( uint256 fromTokenId, uint256 toTokenId ) external onlyOwner { emit BatchMetadataUpdate(fromTokenId, toTokenId); } function balanceOf( address owner ) public view virtual override returns (uint256) { if (owner == address(0)) revert ZeroAddr(); uint256 count; for (uint256 i; i < _owners.length; ) { if (owner == _owners[i]) count++; unchecked { i++; } } return count; } function ownerOf( uint256 tokenId ) public view virtual override returns (address) { if (tokenId >= _owners.length || _owners[tokenId] == address(0)) revert NonExistent(); return _owners[tokenId]; } function name() public view virtual returns (string memory) { return _name; } function symbol() public view virtual returns (string memory) { return _symbol; } function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721Upgradeable.ownerOf(tokenId); if (to == owner) revert ApproveToOwner(); if (_msgSender() != owner && !isApprovedForAll(owner, _msgSender())) revert NotOwnerNorApproved(); _approve(to, tokenId); } function getApproved( uint256 tokenId ) public view virtual override returns (address) { if (!_exists(tokenId)) revert NonExistent(); return _tokenApprovals[tokenId]; } function setApprovalForAll( address operator, bool approved ) public virtual override { if (operator == _msgSender()) revert ApproveToOwner(); _operatorApprovals[_msgSender()][operator] = approved; emit ApprovalForAll(_msgSender(), operator, approved); } function isApprovedForAll( address owner, address operator ) public view virtual override returns (bool isApproved) { isApproved = _operatorApprovals[owner][operator]; if (!isApproved && autoApproveTransfersFromValidator) { isApproved = operator == address(getTransferValidator()); } } function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) { functionSignature = bytes4( keccak256("validateTransfer(address,address,address,uint256)") ); isViewFunction = true; } function _beforeTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal virtual { for (uint256 i; i < batchSize; ) { _validateBeforeTransfer(from, to, firstTokenId + i); unchecked { ++i; } } } function _afterTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal virtual { for (uint256 i; i < batchSize; ) { _validateAfterTransfer(from, to, firstTokenId + i); unchecked { ++i; } } } function _tokenType() internal pure override returns (uint16) { return uint16(721); } function batchTransferFrom( address _from, address _to, uint256[] memory _tokenIds ) public { for (uint256 i; i < _tokenIds.length; ) { transferFrom(_from, _to, _tokenIds[i]); unchecked { i++; } } } function batchSafeTransferFrom( address _from, address _to, uint256[] memory _tokenIds, bytes memory data_ ) public { for (uint256 i; i < _tokenIds.length; ) { safeTransferFrom(_from, _to, _tokenIds[i], data_); unchecked { i++; } } } function transferFrom( address from, address to, uint256 tokenId ) public virtual override { if (!_isApprovedOrOwner(_msgSender(), tokenId)) revert NotOwnerNorApproved(); _transfer(from, to, tokenId); } function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ""); } function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory _data ) public virtual override { if (!_isApprovedOrOwner(_msgSender(), tokenId)) revert NotOwnerNorApproved(); _safeTransfer(from, to, tokenId, _data); } function _safeTransfer( address from, address to, uint256 tokenId, bytes memory _data ) internal virtual { _transfer(from, to, tokenId); if (!_checkOnERC721Received(from, to, tokenId, _data)) revert NonERC721Receiver(); } function _exists(uint256 tokenId) internal view virtual returns (bool) { return tokenId < _owners.length && _owners[tokenId] != address(0); } function _isApprovedOrOwner( address spender, uint256 tokenId ) internal view virtual returns (bool) { if (!_exists(tokenId)) revert NonExistent(); address owner = ERC721Upgradeable.ownerOf(tokenId); return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); } function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } function _safeMint( address to, uint256 tokenId, bytes memory _data ) internal virtual { _mint(to, tokenId); if (!_checkOnERC721Received(address(0), to, tokenId, _data)) revert NonERC721Receiver(); } function _mint(address to, uint256 tokenId) internal virtual { if (to == address(0)) revert ZeroAddr(); _beforeTokenTransfer(address(0), to, tokenId, 1); _owners.push(to); _afterTokenTransfer(address(0), to, tokenId, 1); emit Transfer(address(0), to, tokenId); } function _burn(uint256 tokenId) internal virtual { address owner = ERC721Upgradeable.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId, 1); _approve(address(0), tokenId); _owners[tokenId] = address(0); _afterTokenTransfer(owner, address(0), tokenId, 1); emit Transfer(owner, address(0), tokenId); } function _transfer( address from, address to, uint256 tokenId ) internal virtual { if (ERC721Upgradeable.ownerOf(tokenId) != from) revert NotOwned(); if (to == address(0)) revert ZeroAddr(); _beforeTokenTransfer(from, to, tokenId, 1); _approve(address(0), tokenId); _owners[tokenId] = to; _afterTokenTransfer(from, to, tokenId, 1); emit Transfer(from, to, tokenId); } function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721Upgradeable.ownerOf(tokenId), to, tokenId); } function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received( _msgSender(), from, tokenId, _data ) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert NonERC721Receiver(); } else { assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.25; /** * @title EthFS File * @notice A representation of an onchain file, composed of slices of contract bytecode and utilities to construct the file contents from those slices. * @dev For best gas efficiency, it's recommended using `File.read()` as close to the output returned by the contract call as possible. Lots of gas is consumed every time a large data blob is passed between functions. */ /** * @dev Represents a reference to a slice of bytecode in a contract */ struct BytecodeSlice { address pointer; uint32 start; uint32 end; } /** * @dev Represents a file composed of one or more bytecode slices */ struct File { // Total length of file contents (sum of all slice sizes). Useful when you want to use DynamicBuffer to build the file contents from the slices. uint256 size; BytecodeSlice[] slices; } // extend File struct with read functions using {read} for File global; using {readUnchecked} for File global; /** * @dev Error thrown when a slice is out of the bounds of the contract's bytecode */ error SliceOutOfBounds( address pointer, uint32 codeSize, uint32 sliceStart, uint32 sliceEnd ); /** * @notice Reads the contents of a file by concatenating its slices * @param file The file to read * @return contents The concatenated contents of the file */ function read(File memory file) view returns (string memory contents) { BytecodeSlice[] memory slices = file.slices; bytes4 sliceOutOfBoundsSelector = SliceOutOfBounds.selector; assembly { let len := mload(slices) let size := 0x20 contents := mload(0x40) let slice let pointer let start let end let codeSize for { let i := 0 } lt(i, len) { i := add(i, 1) } { slice := mload(add(slices, add(0x20, mul(i, 0x20)))) pointer := mload(slice) start := mload(add(slice, 0x20)) end := mload(add(slice, 0x40)) codeSize := extcodesize(pointer) if gt(end, codeSize) { mstore(0x00, sliceOutOfBoundsSelector) mstore(0x04, pointer) mstore(0x24, codeSize) mstore(0x44, start) mstore(0x64, end) revert(0x00, 0x84) } extcodecopy(pointer, add(contents, size), start, sub(end, start)) size := add(size, sub(end, start)) } // update contents size mstore(contents, sub(size, 0x20)) // store contents mstore(0x40, add(contents, and(add(size, 0x1f), not(0x1f)))) } } /** * @notice Reads the contents of a file without reverting on unreadable/invalid slices. Skips any slices that are out of bounds or invalid. Useful if you are composing contract bytecode where a contract can still selfdestruct (which would result in an invalid slice) and want to avoid reverts but still output potentially "corrupted" file contents (due to missing data). * @param file The file to read * @return contents The concatenated contents of the file, skipping invalid slices */ function readUnchecked(File memory file) view returns (string memory contents) { BytecodeSlice[] memory slices = file.slices; assembly { let len := mload(slices) let size := 0x20 contents := mload(0x40) let slice let pointer let start let end let codeSize for { let i := 0 } lt(i, len) { i := add(i, 1) } { slice := mload(add(slices, add(0x20, mul(i, 0x20)))) pointer := mload(slice) start := mload(add(slice, 0x20)) end := mload(add(slice, 0x40)) codeSize := extcodesize(pointer) if lt(end, codeSize) { extcodecopy( pointer, add(contents, size), start, sub(end, start) ) size := add(size, sub(end, start)) } } // update contents size mstore(contents, sub(size, 0x20)) // store contents mstore(0x40, add(contents, and(add(size, 0x1f), not(0x1f)))) } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^0.8.25; import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init(address _ownerOnInit) internal onlyInitializing { __Ownable_init_unchained(_ownerOnInit); } function __Ownable_init_unchained( address _ownerOnInit ) internal onlyInitializing { _transferOwnership(_ownerOnInit); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Not owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "No zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.25; import "./Bytecode.sol"; library SSTORE2 { error WriteError(); /** @notice Stores `_data` and returns `pointer` as key for later retrieval @dev The pointer is a contract address with `_data` as code @param _data to be written @return pointer Pointer to the written `_data` */ function write(bytes memory _data) internal returns (address pointer) { // Append 00 to _data so contract can't be called // Build init code bytes memory code = Bytecode.creationCodeFor( abi.encodePacked(hex"00", _data) ); // Deploy contract using create assembly { pointer := create(0, add(code, 32), mload(code)) } // Address MUST be non-zero if (pointer == address(0)) revert WriteError(); } /** @notice Reads the contents of the `_pointer` code as data, skips the first byte @dev The function is intended for reading pointers generated by `write` @param _pointer to be read @return data read from `_pointer` contract */ function read(address _pointer) internal view returns (bytes memory) { return Bytecode.codeAt(_pointer, 1, type(uint256).max); } /** @notice Reads the contents of the `_pointer` code as data, skips the first byte @dev The function is intended for reading pointers generated by `write` @param _pointer to be read @param _start number of bytes to skip @return data read from `_pointer` contract */ function read( address _pointer, uint256 _start ) internal view returns (bytes memory) { return Bytecode.codeAt(_pointer, _start + 1, type(uint256).max); } /** @notice Reads the contents of the `_pointer` code as data, skips the first byte @dev The function is intended for reading pointers generated by `write` @param _pointer to be read @param _start number of bytes to skip @param _end index before which to end extraction @return data read from `_pointer` contract */ function read( address _pointer, uint256 _start, uint256 _end ) internal view returns (bytes memory) { return Bytecode.codeAt(_pointer, _start + 1, _end + 1); } }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 0, "details": { "yul": true } }, "evmVersion": "cancun", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[],"name":"AlreadyClaimed","type":"error"},{"inputs":[],"name":"ApproveToOwner","type":"error"},{"inputs":[],"name":"AuctionInProgress","type":"error"},{"inputs":[],"name":"AuctionOngoing","type":"error"},{"inputs":[],"name":"ContractMintingNotAllowed","type":"error"},{"inputs":[],"name":"CreatorTokenBase__InvalidTransferValidatorContract","type":"error"},{"inputs":[{"internalType":"uint256","name":"_size","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"InvalidCodeAtRange","type":"error"},{"inputs":[],"name":"InvalidFunds","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"MaxFourExceeded","type":"error"},{"inputs":[],"name":"MinOneTokenRequired","type":"error"},{"inputs":[],"name":"MintedOut","type":"error"},{"inputs":[],"name":"NonERC721Receiver","type":"error"},{"inputs":[],"name":"NonExistent","type":"error"},{"inputs":[],"name":"NotAllowed","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NotOnAllowList","type":"error"},{"inputs":[],"name":"NotOwned","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"NotOwnerOrContract","type":"error"},{"inputs":[],"name":"OOB","type":"error"},{"inputs":[],"name":"RebateNotStarted","type":"error"},{"inputs":[],"name":"SaleEnded","type":"error"},{"inputs":[],"name":"SaleNotStarted","type":"error"},{"inputs":[],"name":"ShouldNotMintToBurnAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"length","type":"uint256"}],"name":"StringsInsufficientHexLength","type":"error"},{"inputs":[],"name":"TokenNotFound","type":"error"},{"inputs":[],"name":"TooHigh","type":"error"},{"inputs":[],"name":"TooLow","type":"error"},{"inputs":[],"name":"WriteError","type":"error"},{"inputs":[],"name":"ZeroAddr","type":"error"},{"inputs":[],"name":"ZeroBalance","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"autoApproved","type":"bool"}],"name":"AutomaticApprovalOfTransferValidatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"newImageBase","type":"string"}],"name":"ImageBaseUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint24","name":"newMaxSupply","type":"uint24"}],"name":"MaxSupplyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValidator","type":"address"},{"indexed":false,"internalType":"address","name":"newValidator","type":"address"}],"name":"TransferValidatorUpdated","type":"event"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"address","name":"a","type":"address"},{"internalType":"uint16","name":"count","type":"uint16"}],"name":"allowListMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"count","type":"uint24"},{"internalType":"address","name":"a","type":"address"}],"name":"artistMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"autoApproveTransfersFromValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"batchSafeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"batchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"a","type":"address"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"checkAllowListAndClaimStatus","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"a","type":"address"}],"name":"claimRebate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentPrice","outputs":[{"internalType":"uint256","name":"p","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProjectDetails","outputs":[{"internalType":"bool","name":"fixedPrice","type":"bool"},{"internalType":"uint256","name":"reservePrice","type":"uint256"},{"internalType":"uint256","name":"allowListPrice","type":"uint256"},{"internalType":"uint256","name":"publicStartTimeStamp","type":"uint256"},{"internalType":"uint256","name":"allowListStartTimeStamp","type":"uint256"},{"internalType":"uint256","name":"maxSupply","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransferValidationFunction","outputs":[{"internalType":"bytes4","name":"functionSignature","type":"bytes4"},{"internalType":"bool","name":"isViewFunction","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTransferValidator","outputs":[{"internalType":"address","name":"validator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"imageBase","type":"string"},{"internalType":"address[]","name":"artScripts","type":"address[]"},{"internalType":"address payable[]","name":"receivers","type":"address[]"},{"internalType":"uint24[]","name":"shares","type":"uint24[]"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"address","name":"artInfo","type":"address"},{"internalType":"uint56","name":"publicStartTimeStamp","type":"uint56"},{"internalType":"uint32","name":"maxSupply","type":"uint32"},{"internalType":"address","name":"traits","type":"address"},{"internalType":"uint96","name":"reservePrice","type":"uint96"},{"internalType":"address payable","name":"royaltyAddress","type":"address"},{"internalType":"uint96","name":"lastSalePrice","type":"uint96"},{"internalType":"address","name":"libraryScripts","type":"address"},{"internalType":"uint56","name":"endingTimeStamp","type":"uint56"},{"internalType":"uint24","name":"royalty","type":"uint24"},{"internalType":"bool","name":"fixedPrice","type":"bool"},{"internalType":"uint96","name":"allowListPrice","type":"uint96"},{"internalType":"uint56","name":"allowListStartTimeStamp","type":"uint56"},{"internalType":"uint32","name":"totalAllowListMints","type":"uint32"},{"internalType":"uint24","name":"artistAuctionWithdrawalsClaimed","type":"uint24"},{"internalType":"uint24","name":"artistAllowListWithdrawalsClaimed","type":"uint24"},{"internalType":"uint16","name":"allowedAmountPerALAddress","type":"uint16"}],"internalType":"struct TwoFiveSixProjectDefaultV2.Project","name":"_p","type":"tuple"},{"internalType":"address","name":"_traits","type":"address"},{"internalType":"address","name":"_libraryScripts","type":"address"}],"name":"initProject","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"isApproved","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"count","type":"uint128"},{"internalType":"address","name":"a","type":"address"}],"name":"publicMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_artScripts","type":"address[]"}],"name":"setArtScripts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"autoApprove","type":"bool"}],"name":"setAutomaticApprovalOfTransfersFromValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_imageBase","type":"string"}],"name":"setImageBase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"fileStore","type":"address"},{"internalType":"string","name":"fileName","type":"string"}],"internalType":"struct TwoFiveSixProjectDefaultV2.LibraryScript[]","name":"_libraries","type":"tuple[]"}],"name":"setLibraryScripts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"_maxSupply","type":"uint24"}],"name":"setMaxSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"_royalty","type":"uint24"}],"name":"setRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transferValidator_","type":"address"}],"name":"setTransferValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenHTML","outputs":[{"internalType":"string","name":"artwork","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenIdToHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"internalType":"uint256","name":"toTokenId","type":"uint256"}],"name":"updateBatchMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"updateMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"walletOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.