Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
20113951 | 133 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
GenArt721CoreV3_Engine
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 10 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.22; // Created By: Art Blocks Inc. import "../../interfaces/v0.8.x/IRandomizer_V3CoreBase.sol"; import "../../interfaces/v0.8.x/IAdminACLV0_Extended.sol"; import "../../interfaces/v0.8.x/IGenArt721CoreContractV3_Engine.sol"; import {IGenArt721CoreContractV3_ProjectFinance} from "../../interfaces/v0.8.x/IGenArt721CoreContractV3_ProjectFinance.sol"; import "../../interfaces/v0.8.x/IGenArt721CoreContractExposesHashSeed.sol"; import "../../interfaces/v0.8.x/IDependencyRegistryCompatibleV0.sol"; import {ISplitProviderV0} from "../../interfaces/v0.8.x/ISplitProviderV0.sol"; import {IBytecodeStorageReader_Base} from "../../interfaces/v0.8.x/IBytecodeStorageReader_Base.sol"; import "@openzeppelin-5.0/contracts/utils/Strings.sol"; import "@openzeppelin-5.0/contracts/access/Ownable.sol"; import {IERC2981} from "@openzeppelin-5.0/contracts/interfaces/IERC2981.sol"; import "../../libs/v0.8.x/ERC721_PackedHashSeedV1.sol"; import {BytecodeStorageWriter, BytecodeStorageReader} from "../../libs/v0.8.x/BytecodeStorageV2.sol"; import "../../libs/v0.8.x/Bytes32Strings.sol"; /** * @title Art Blocks Engine ERC-721 core contract, V3. * @author Art Blocks Inc. * @notice Privileged Roles and Ownership: * This contract is designed to be managed, with progressively limited powers * as a project progresses from active to locked. * Privileged roles and abilities are controlled by the admin ACL contract and * artists. Both of these roles hold extensive power and can arbitrarily * control and modify portions of projects, dependent upon project state. After * a project is locked, important project metadata fields are locked including * the project name, artist name, and script and display details. Edition size * can never be increased. * Care must be taken to ensure that the admin ACL contract and artist * addresses are secure behind a multi-sig or other access control mechanism. * ---------------------------------------------------------------------------- * The following functions are restricted to the Admin ACL contract: * - updateArtblocksDependencyRegistryAddress * - updateArtblocksOnChainGeneratorAddress * - updateNextCoreContract * - updateProviderSalesAddresses * - updateProviderPrimarySalesPercentages (up to 100%) * - updateProviderDefaultSecondarySalesBPS (up to 100%) * - syncProviderSecondaryForProjectToDefaults * - updateMinterContract * - updateRandomizerAddress * - toggleProjectIsActive (note: artist may be configured to activate projects) * - addProject * - forbidNewProjects (forever forbidding new projects) * - updateDefaultBaseURI (used to initialize new project base URIs) * - updateSplitProvider * - updateBytecodeStorageReaderContract * ---------------------------------------------------------------------------- * The following functions are restricted to either the Artist address or * the Admin ACL contract, only when the project is not locked: * - updateProjectName * - updateProjectArtistName * - updateProjectLicense * - Change project script via addProjectScript, addProjectScriptCompressed, * updateProjectScript, updateProjectScriptCompressed, * and removeProjectLastScript * - updateProjectScriptType * - updateProjectAspectRatio * ---------------------------------------------------------------------------- * The following functions are restricted to only the Artist address: * - proposeArtistPaymentAddressesAndSplits (Note that this has to be accepted * by adminAcceptArtistAddressesAndSplits to take effect, which is restricted * to the Admin ACL contract, or the artist if the core contract owner has * renounced ownership. Also note that a proposal will be automatically * accepted if the artist only proposes changed payee percentages without * modifying any payee addresses, or is only removing payee addresses, or * if the global config `autoApproveArtistSplitProposals` is set to `true`.) * - toggleProjectIsPaused (note the artist can still mint while paused) * - updateProjectSecondaryMarketRoyaltyPercentage (up to ARTIST_MAX_SECONDARY_ROYALTY_PERCENTAGE percent) * - updateProjectWebsite * - updateProjectMaxInvocations (to a number greater than or equal to the * current number of invocations, and less than current project maximum * invocations) * - updateProjectBaseURI (controlling the base URI for tokens in the project) * ---------------------------------------------------------------------------- * The following function is restricted to either the Admin ACL contract, or * the Artist address if the core contract owner has renounced ownership: * - adminAcceptArtistAddressesAndSplits * - updateProjectArtistAddress (owner ultimately controlling the project and * its and-on revenue, unless owner has renounced ownership) * ---------------------------------------------------------------------------- * The following function is restricted to the artist when a project is * unlocked, and only callable by Admin ACL contract when a project is locked: * - updateProjectDescription * ---------------------------------------------------------------------------- * The following function is restricted to owner calling directly: * - transferOwnership * - renounceOwnership * ---------------------------------------------------------------------------- * The following configuration variables are set at time of contract deployment, * and not modifiable thereafter (immutable after the point of deployment): * - (bool) autoApproveArtistSplitProposals * ---------------------------------------------------------------------------- * Additional admin and artist privileged roles may be described on minters, * registries, and other contracts that may interact with this core contract. */ contract GenArt721CoreV3_Engine is ERC721_PackedHashSeedV1, Ownable, IERC2981, IDependencyRegistryCompatibleV0, IGenArt721CoreContractV3_Engine, IGenArt721CoreContractV3_ProjectFinance, IGenArt721CoreContractExposesHashSeed { using BytecodeStorageWriter for string; using BytecodeStorageWriter for bytes; using Bytes32Strings for bytes32; using Strings for uint256; using Strings for address; uint256 constant ONE_HUNDRED = 100; uint256 constant ONE_MILLION = 1_000_000; uint24 constant ONE_MILLION_UINT24 = 1_000_000; uint256 constant FOUR_WEEKS_IN_SECONDS = 2_419_200; uint8 constant AT_CHARACTER_CODE = uint8(bytes1("@")); // 0x40 // numeric constants uint256 constant MAX_PROVIDER_SECONDARY_SALES_BPS = 10000; // 10_000 BPS = 100% uint256 constant ARTIST_MAX_SECONDARY_ROYALTY_PERCENTAGE = 95; // 95% /// pointer to next core contract associated with this contract address public nextCoreContract; /// Dependency registry managed by Art Blocks address public artblocksDependencyRegistryAddress; /// On chain generator managed by Art Blocks address public artblocksOnChainGeneratorAddress; /// ensure initialization can only be performed once bool private _initialized; /// current randomizer contract IRandomizer_V3CoreBase public randomizerContract; /// append-only array of all randomizer contract addresses ever used by /// this contract address[] private _historicalRandomizerAddresses; /// admin ACL contract IAdminACLV0 public adminACLContract; struct Project { uint24 invocations; uint24 maxInvocations; uint24 scriptCount; // max uint64 ~= 1.8e19 sec ~= 570 billion years uint64 completedTimestamp; bool active; bool paused; string name; string artist; address descriptionAddress; string website; string license; string projectBaseURI; bytes32 scriptTypeAndVersion; string aspectRatio; // mapping from script index to address storing script in bytecode mapping(uint256 => address) scriptBytecodeAddresses; } mapping(uint256 => Project) projects; /// private mapping from project ID to project financial information. See /// `projectIdToFinancials` getter for public access. mapping(uint256 _projectId => ProjectFinance) private _projectIdToFinancials; /// hash of artist's proposed payment updates to be approved by admin mapping(uint256 => bytes32) public proposedArtistAddressesAndSplitsHash; /// The render provider payment address for all primary sales revenues /// (packed) address payable public renderProviderPrimarySalesAddress; /// Percentage of primary sales revenue allocated to the render provider /// (packed) // packed uint: max of 100, max uint8 = 255 uint8 private _renderProviderPrimarySalesPercentage; /// The platform provider payment address for all primary sales revenues /// (packed) address payable public platformProviderPrimarySalesAddress; /// Percentage of primary sales revenue allocated to the platform provider /// (packed) // packed uint: max of 100, max uint8 = 255 uint8 private _platformProviderPrimarySalesPercentage; /// @dev Note on "default" provider secondary values - the only way these can /// be different on a per project basis is if admin updates these and then /// does not call syncProviderSecondaryForProjectToDefaults for the project. /// ----------------------------------------------------------------------- /// The default render provider payment address for all secondary sales royalty /// revenues, for all new projects. Individual project payment info is defined /// in each project's ProjectFinance struct. /// Projects can be updated to this value by calling the /// `syncProviderSecondaryForProjectToDefaults` function for each project. address payable public defaultRenderProviderSecondarySalesAddress; /// The default basis points allocated to render provider for all secondary /// sales royalty revenues, for all new projects. Individual project /// payment info is defined in each project's ProjectFinance struct. /// Projects can be updated to this value by calling the /// `syncProviderSecondaryForProjectToDefaults` function for each project. uint256 public defaultRenderProviderSecondarySalesBPS; /// The default platform provider payment address for all secondary sales royalty /// revenues, for all new projects. Individual project payment info is defined /// in each project's ProjectFinance struct. /// Projects can be updated to this value by calling the /// `syncProviderSecondaryForProjectToDefaults` function for each project. address payable public defaultPlatformProviderSecondarySalesAddress; /// The default basis points allocated to platform provider for all secondary /// sales royalty revenues, for all new projects. Individual project /// payment info is defined in each project's ProjectFinance struct. /// Projects can be updated to this value by calling the /// `syncProviderSecondaryForProjectToDefaults` function for each project. uint256 public defaultPlatformProviderSecondarySalesBPS; /// ----------------------------------------------------------------------- /// single minter allowed for this core contract address public minterContract; /// starting (initial) project ID on this contract configured /// at time of deployment and intended to be immutable after initialization. /// Not marked as immutable due to initialization requirements /// under the ERC-1167 minimal proxy pattern, which necessitates /// setting this value post-deployment. uint256 public startingProjectId; /// next project ID to be created uint248 private _nextProjectId; /// bool indicating if adding new projects is forbidden; /// default behavior is to allow new projects bool public newProjectsForbidden; /// configuration variable set at time of deployment, intended to be /// immutable after initialization, that determines whether or not /// admin approval^ should be required to accept artist address change /// proposals, or if these proposals should always auto-approve, as /// determined by the business process requirements of the Engine /// partner using this contract. /// /// ^does not apply in the case where contract-ownership itself is revoked /// Not marked as immutable due to initialization requirements /// under the ERC-1167 minimal proxy pattern, which necessitates /// setting this value post-deployment. bool public autoApproveArtistSplitProposals; /// configuration variable set at time of deployment, intended to be /// immutable after initialization, that determines if platform provider /// fees and addresses are always required to be set to zero. /// Not marked as immutable due to initialization requirements /// under the ERC-1167 minimal proxy pattern, which necessitates /// setting this value post-deployment. bool public nullPlatformProvider; /// configuration variable set at time of deployment, intended to be /// immutable after initialization, that determines if artists are allowed /// to activate their own projects. /// Not marked as immutable due to initialization requirements /// under the ERC-1167 minimal proxy pattern, which necessitates /// setting this value post-deployment. bool public allowArtistProjectActivation; /// version & type of this core contract bytes32 constant CORE_VERSION = "v3.2.4"; function coreVersion() external pure returns (string memory) { return CORE_VERSION.toString(); } bytes32 constant CORE_TYPE = "GenArt721CoreV3_Engine"; function coreType() external pure returns (string memory) { return CORE_TYPE.toString(); } /// default base URI to initialize all new project projectBaseURI values to string public defaultBaseURI; // ERC2981 royalty support and default royalty values bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a; uint8 private constant _DEFAULT_ARTIST_SECONDARY_ROYALTY_PERCENTAGE = 5; // royalty split provider ISplitProviderV0 public splitProvider; // bytecode storage reader contract; may be universal or specific version reader contract IBytecodeStorageReader_Base public bytecodeStorageReaderContract; /** * @dev This constructor sets the owner to a non-functional address as a formality. * It is only ever ran on the implementation contract. The `Ownable` constructor is * called to satisfy the contract's inheritance requirements. This owner has no * operational significance and should not be considered secure or meaningful. * The true ownership will be set in the `initialize` function post-deployment to * ensure correct owner management in the proxy architecture. * Explicitly setting the owner to '0xdead' to indicate non-operational use. */ constructor() Ownable(0x000000000000000000000000000000000000dEaD) {} function _onlyNonZeroAddress(address _address) internal pure { if (_address == address(0)) { revert GenArt721Error(ErrorCodes.OnlyNonZeroAddress); } } function _onlyNonEmptyString(string memory _string) internal pure { if (bytes(_string).length == 0) { revert GenArt721Error(ErrorCodes.OnlyNonEmptyString); } } function _onlyNonEmptyBytes(bytes memory _bytes) internal pure { if (_bytes.length == 0) { revert GenArt721Error(ErrorCodes.OnlyNonEmptyBytes); } } function _onlyValidTokenId(uint256 _tokenId) internal view { if (_ownerOf(_tokenId) == address(0)) { revert GenArt721Error(ErrorCodes.TokenDoesNotExist); } } function _onlyValidProjectId(uint256 _projectId) internal view { if (_projectId < startingProjectId || _projectId >= _nextProjectId) { revert GenArt721Error(ErrorCodes.ProjectDoesNotExist); } } function _onlyUnlocked(uint256 _projectId) internal view { // Note: calling `_projectUnlocked` enforces that the `_projectId` // passed in is valid.` if (!_projectUnlocked(_projectId)) { revert GenArt721Error(ErrorCodes.OnlyUnlockedProjects); } } function _onlyAdminACL(bytes4 _selector) internal { if (!adminACLAllowed(msg.sender, address(this), _selector)) { revert GenArt721Error(ErrorCodes.OnlyAdminACL); } } function _onlyArtist(uint256 _projectId) internal view { if (msg.sender != _projectIdToFinancials[_projectId].artistAddress) { revert GenArt721Error(ErrorCodes.OnlyArtist); } } function _onlyArtistOrAdminACL( uint256 _projectId, bytes4 _selector ) internal { if ( !(msg.sender == _projectIdToFinancials[_projectId].artistAddress || adminACLAllowed(msg.sender, address(this), _selector)) ) { revert GenArt721Error(ErrorCodes.OnlyArtistOrAdminACL); } } /** * This modifier allows the artist of a project to call a function if the * owner of the contract has renounced ownership. This is to allow the * contract to continue to function if the owner decides to renounce * ownership. */ function _onlyAdminACLOrRenouncedArtist( uint256 _projectId, bytes4 _selector ) internal { // check if Admin ACL is allowed to call this function if (adminACLAllowed(msg.sender, address(this), _selector)) { return; } // check if the owner has renounced ownership and the caller is the // artist of the project if ( owner() == address(0) && msg.sender == _projectIdToFinancials[_projectId].artistAddress ) { return; } // neither of the above conditions were met, revert revert GenArt721Error(ErrorCodes.OnlyAdminACLOrRenouncedArtist); } /** * @notice Initializes the contract with the provided `engineConfiguration`. * This function should be called atomically, immediately after deployment. * Only callable once. Validation on `engineConfiguration` is performed by caller. * @dev This function is intentionally unpermissioned to allow for the * initialization of the contract post-deployment. It is expected that this * function will be called atomically by the factory contract that deploys this * contract, after which it will be initialized and uncallable. * @param engineConfiguration EngineConfiguration to configure the contract with. * @param adminACLContract_ Address of admin access control contract, to be * set as contract owner. * @param defaultBaseURIHost Base URI prefix to initialize default base URI with. * @param bytecodeStorageReaderContract_ Address of the bytecode storage reader contract. */ function initialize( EngineConfiguration memory engineConfiguration, address adminACLContract_, string memory defaultBaseURIHost, address bytecodeStorageReaderContract_ ) external virtual { // @dev internal function call so derived contracts have access to initialization logic _initialize({ engineConfiguration: engineConfiguration, adminACLContract_: adminACLContract_, defaultBaseURIHost: defaultBaseURIHost, bytecodeStorageReaderContract_: bytecodeStorageReaderContract_ }); } /** * @notice Mints a token from project `_projectId` and sets the * token's owner to `_to`. Hash may or may not be assigned to the token * during the mint transaction, depending on the randomizer contract. * @param _to Address to be the minted token's owner. * @param _projectId Project ID to mint a token on. * @param _by Purchaser of minted token. * @return _tokenId The ID of the minted token. * @dev sender must be the allowed minterContract * @dev name of function is optimized for gas usage */ function mint_Ecf( address _to, uint256 _projectId, address _by ) external returns (uint256 _tokenId) { // CHECKS if (msg.sender != minterContract) { revert GenArt721Error(ErrorCodes.OnlyMinterContract); } Project storage project = projects[_projectId]; // load invocations into memory uint24 invocationsBefore = project.invocations; uint24 invocationsAfter; unchecked { // invocationsBefore guaranteed <= maxInvocations <= 1_000_000, // 1_000_000 << max uint24, so no possible overflow invocationsAfter = invocationsBefore + 1; } uint24 maxInvocations = project.maxInvocations; if (invocationsBefore >= maxInvocations) { revert GenArt721Error(ErrorCodes.MaxInvocationsReached); } if ( !(project.active || _by == _projectIdToFinancials[_projectId].artistAddress) ) { revert GenArt721Error(ErrorCodes.ProjectMustExistAndBeActive); } if ( project.paused && _by != _projectIdToFinancials[_projectId].artistAddress ) { revert GenArt721Error(ErrorCodes.PurchasesPaused); } // EFFECTS // increment project's invocations project.invocations = invocationsAfter; uint256 thisTokenId; unchecked { // invocationsBefore is uint24 << max uint256. In production use, // _projectId * ONE_MILLION must be << max uint256, otherwise // tokenIdToProjectId function become invalid. // Therefore, no risk of overflow thisTokenId = (_projectId * ONE_MILLION) + invocationsBefore; } // mark project as completed if hit max invocations if (invocationsAfter == maxInvocations) { _completeProject(_projectId); } // INTERACTIONS _mint(_to, thisTokenId); // token hash is updated by the randomizer contract on V3 randomizerContract.assignTokenHash(thisTokenId); // Do not need to also log `projectId` in event, as the `projectId` for // a given token can be derived from the `tokenId` with: // projectId = tokenId / 1_000_000 emit Mint(_to, thisTokenId); return thisTokenId; } /** * @notice Sets the hash seed for a given token ID `_tokenId`. * May only be called by the current randomizer contract. * May only be called for tokens that have not already been assigned a * non-zero hash. * @param _tokenId Token ID to set the hash for. * @param _hashSeed Hash seed to set for the token ID. Only last 12 bytes * will be used. * @dev gas-optimized function name because called during mint sequence * @dev if a separate event is required when the token hash is set, e.g. * for indexing purposes, it must be emitted by the randomizer. This is to * minimize gas when minting. */ function setTokenHash_8PT(uint256 _tokenId, bytes32 _hashSeed) external { _onlyValidTokenId(_tokenId); OwnerAndHashSeed storage ownerAndHashSeed = _ownersAndHashSeeds[ _tokenId ]; if (msg.sender != address(randomizerContract)) { revert GenArt721Error(ErrorCodes.OnlyRandomizer); } if (ownerAndHashSeed.hashSeed != bytes12(0)) { revert GenArt721Error(ErrorCodes.TokenHashAlreadySet); } if (_hashSeed == bytes12(0)) { revert GenArt721Error(ErrorCodes.NoZeroHashSeed); } ownerAndHashSeed.hashSeed = bytes12(_hashSeed); } /** * @notice Allows owner (AdminACL) to revoke ownership of the contract. * Note that the contract is intended to continue to function after the * owner renounces ownership, but no new projects will be able to be added. * Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the * owner/AdminACL contract. The same is true for any dependent contracts * that also integrate with the owner/AdminACL contract (e.g. potentially * minter suite contracts, registry contracts, etc.). * After renouncing ownership, artists will be in control of updates to * their payment addresses and splits (see modifier * onlyAdminACLOrRenouncedArtist`). * While there is no currently intended reason to call this method based on * typical Engine partner business practices, this method exists to allow * artists to continue to maintain the limited set of contract * functionality that exists post-project-lock in an environment in which * there is no longer an admin maintaining this smart contract. * @dev This function is intended to be called directly by the AdminACL, * not by an address allowed by the AdminACL contract. */ function renounceOwnership() public override onlyOwner { // broadcast that new projects are no longer allowed (if not already) _forbidNewProjects(); // renounce ownership viw Ownable Ownable.renounceOwnership(); } /** * @notice Updates reference to next core contract, associated with this contract. * @param _nextCoreContract Address of the next core contract */ function updateNextCoreContract(address _nextCoreContract) external { _onlyAdminACL(this.updateNextCoreContract.selector); nextCoreContract = _nextCoreContract; emit PlatformUpdated( bytes32(uint256(PlatformUpdatedFields.FIELD_NEXT_CORE_CONTRACT)) ); } /** * @notice Updates reference to Art Blocks Dependency Registry contract. * @param _artblocksDependencyRegistryAddress Address of new Dependency * Registry. */ function updateArtblocksDependencyRegistryAddress( address _artblocksDependencyRegistryAddress ) external { _onlyAdminACL(this.updateArtblocksDependencyRegistryAddress.selector); _onlyNonZeroAddress(_artblocksDependencyRegistryAddress); artblocksDependencyRegistryAddress = _artblocksDependencyRegistryAddress; emit PlatformUpdated( bytes32( uint256( PlatformUpdatedFields .FIELD_ARTBLOCKS_DEPENDENCY_REGISTRY_ADDRESS ) ) ); } /** * @notice Updates reference to Art Blocks On Chain Generator contract. * @param _artblocksOnChainGeneratorAddress Address of new on chain generator. */ function updateArtblocksOnChainGeneratorAddress( address _artblocksOnChainGeneratorAddress ) external { _onlyAdminACL(this.updateArtblocksOnChainGeneratorAddress.selector); _onlyNonZeroAddress(_artblocksOnChainGeneratorAddress); artblocksOnChainGeneratorAddress = _artblocksOnChainGeneratorAddress; emit PlatformUpdated( bytes32( uint256( PlatformUpdatedFields .FIELD_ARTBLOCKS_ON_CHAIN_GENERATOR_ADDRESS ) ) ); } /** * @notice Updates sales addresses for the platform and render providers to * the input parameters. * note: This does not update splitter contracts for all projects on * this core contract. If updated splitter contracts are desired, they must be * updated after this update via the `syncProviderSecondaryForProjectToDefaults` function. * @param _renderProviderPrimarySalesAddress Address of new primary sales * payment address. * @param _defaultRenderProviderSecondarySalesAddress Default address of new secondary sales * payment address. * @param _platformProviderPrimarySalesAddress Address of new primary sales * payment address. * @param _defaultPlatformProviderSecondarySalesAddress Default address of new secondary sales * payment address. */ function updateProviderSalesAddresses( address payable _renderProviderPrimarySalesAddress, address payable _defaultRenderProviderSecondarySalesAddress, address payable _platformProviderPrimarySalesAddress, address payable _defaultPlatformProviderSecondarySalesAddress ) external { _onlyAdminACL(this.updateProviderSalesAddresses.selector); _onlyNonZeroAddress(_renderProviderPrimarySalesAddress); _onlyNonZeroAddress(_defaultRenderProviderSecondarySalesAddress); // @dev checks on platform provider addresses performed in _updateProviderSalesAddresses _updateProviderSalesAddresses( _renderProviderPrimarySalesAddress, _defaultRenderProviderSecondarySalesAddress, _platformProviderPrimarySalesAddress, _defaultPlatformProviderSecondarySalesAddress ); } /** * @notice Updates the render and platform provider primary sales revenue percentage to * the provided inputs. * If contract is configured to have a null platform provider, the platform provider * primary sales percentage must be set to zero. * @param renderProviderPrimarySalesPercentage_ New primary sales revenue % for the render provider * @param platformProviderPrimarySalesPercentage_ New primary sales revenue % for the platform provider * percentage. */ function updateProviderPrimarySalesPercentages( uint256 renderProviderPrimarySalesPercentage_, uint256 platformProviderPrimarySalesPercentage_ ) external { _onlyAdminACL(this.updateProviderPrimarySalesPercentages.selector); // require no platform provider payment if null platform provider if ( nullPlatformProvider && platformProviderPrimarySalesPercentage_ != 0 ) { revert GenArt721Error(ErrorCodes.OnlyNullPlatformProvider); } // Validate that the sum of the proposed %s, does not exceed 100%. if ( (renderProviderPrimarySalesPercentage_ + platformProviderPrimarySalesPercentage_) > ONE_HUNDRED ) { revert GenArt721Error(ErrorCodes.OverMaxSumOfPercentages); } // Casting to `uint8` here is safe due check above, which does not allow // overflow as of solidity version ^0.8.0. _renderProviderPrimarySalesPercentage = uint8( renderProviderPrimarySalesPercentage_ ); _platformProviderPrimarySalesPercentage = uint8( platformProviderPrimarySalesPercentage_ ); emit PlatformUpdated( bytes32( uint256( PlatformUpdatedFields .FIELD_PROVIDER_PRIMARY_SALES_PERCENTAGES ) ) ); } /** * @notice Updates default render and platform provider secondary sales royalty * Basis Points to the provided inputs. * If contract is configured to have a null platform provider, the platform provider * secondary sales BPS must be set to zero. * note: This does not update splitter contracts for all projects on * this core contract. If updated splitter contracts are desired, they must be * updated after this update via the `syncProviderSecondaryForProjectToDefaults` function. * @param _defaultRenderProviderSecondarySalesBPS New default secondary sales royalty Basis * points. * @param _defaultPlatformProviderSecondarySalesBPS New default secondary sales royalty Basis * points. * @dev Due to secondary royalties being ultimately enforced via social * consensus, no hard upper limit is imposed on the BPS value, other than * <= 100% royalty, which would not make mathematical sense. Realistically, * changing this value is expected to either never occur, or be a rare * occurrence. */ function updateProviderDefaultSecondarySalesBPS( uint256 _defaultRenderProviderSecondarySalesBPS, uint256 _defaultPlatformProviderSecondarySalesBPS ) external { _onlyAdminACL(this.updateProviderDefaultSecondarySalesBPS.selector); // require no platform provider payment if null platform provider if ( nullPlatformProvider && _defaultPlatformProviderSecondarySalesBPS != 0 ) { revert GenArt721Error(ErrorCodes.OnlyNullPlatformProvider); } // Validate that the sum of the proposed provider BPS, does not exceed 10_000 BPS. if ( _defaultRenderProviderSecondarySalesBPS + _defaultPlatformProviderSecondarySalesBPS > MAX_PROVIDER_SECONDARY_SALES_BPS ) { revert GenArt721Error(ErrorCodes.OverMaxSumOfBPS); } defaultRenderProviderSecondarySalesBPS = _defaultRenderProviderSecondarySalesBPS; defaultPlatformProviderSecondarySalesBPS = _defaultPlatformProviderSecondarySalesBPS; emit PlatformUpdated( bytes32( uint256( PlatformUpdatedFields.FIELD_PROVIDER_SECONDARY_SALES_BPS ) ) ); } /** * @notice Updates minter to `_address`. * @param _address Address of new minter. */ function updateMinterContract(address _address) external { _onlyAdminACL(this.updateMinterContract.selector); _onlyNonZeroAddress(_address); _updateMinterContract(_address); } /** * @notice Updates randomizer to `_randomizerAddress`. * @param _randomizerAddress Address of new randomizer. */ function updateRandomizerAddress(address _randomizerAddress) external { _onlyAdminACL(this.updateRandomizerAddress.selector); _onlyNonZeroAddress(_randomizerAddress); _updateRandomizerAddress(_randomizerAddress); } /** * @notice Updates split provider address to `_splitProviderAddress`. * Reverts if `_splitProviderAddress` is zero address. * @param _splitProviderAddress New split provider address. */ function updateSplitProvider(address _splitProviderAddress) external { _onlyAdminACL(this.updateSplitProvider.selector); _updateSplitProvider(_splitProviderAddress); } /** * @notice Updates bytecode storage reader contract to `_bytecodeStorageReaderContract`. * Reverts if `_bytecodeStorageReaderContract` is zero address. * Updating the active Bytecode Storage Reader contract may affect the ability to read * data related to existing projects. Care should be taken to ensure that the new * contract is compatible with the existing project data. * @param _bytecodeStorageReaderContract New bytecode storage reader contract address. */ function updateBytecodeStorageReaderContract( address _bytecodeStorageReaderContract ) external { _onlyAdminACL(this.updateBytecodeStorageReaderContract.selector); _onlyNonZeroAddress(_bytecodeStorageReaderContract); _updateBytecodeStorageReaderContract(_bytecodeStorageReaderContract); } /** * @notice Toggles project `_projectId` as active/inactive. * @param _projectId Project ID to be toggled. */ function toggleProjectIsActive(uint256 _projectId) external { if (allowArtistProjectActivation) { _onlyArtistOrAdminACL( _projectId, this.toggleProjectIsActive.selector ); } else { _onlyAdminACL(this.toggleProjectIsActive.selector); } _onlyValidProjectId(_projectId); projects[_projectId].active = !projects[_projectId].active; emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_ACTIVE)) ); } /** * @notice Artist proposes updated set of artist address, additional payee * addresses, and percentage splits for project `_projectId`. Addresses and * percentages do not have to all be changed, but they must all be defined * as a complete set. * Note that if the artist is only proposing a change to the payee percentage * splits, without modifying the payee addresses, the proposal will be * automatically approved and the new splits will become active immediately. * Automatic approval will also be granted if the artist is only removing * additional payee addresses, without adding any new ones. * Also note that if `autoApproveArtistSplitProposals` is true, proposals * will always be auto-approved, regardless of what is being changed. * Also note that if the artist is proposing sending funds to the zero * address, this function will revert and the proposal will not be created. * @param _projectId Project ID. * @param _artistAddress Artist address that controls the project, and may * receive payments. * @param _additionalPayeePrimarySales Address that may receive a * percentage split of the artist's primary sales revenue. * @param _additionalPayeePrimarySalesPercentage Percent of artist's * portion of primary sale revenue that will be split to address * `_additionalPayeePrimarySales`. * @param _additionalPayeeSecondarySales Address that may receive a percentage * split of the secondary sales royalties. * @param _additionalPayeeSecondarySalesPercentage Percent of artist's portion * of secondary sale royalties that will be split to address * `_additionalPayeeSecondarySales`. * @dev `_artistAddress` must be a valid address (non-zero-address), but it * is intentionally allowable for `_additionalPayee{Primary,Secondaary}Sales` * and their associated percentages to be zero'd out by the controlling artist. */ function proposeArtistPaymentAddressesAndSplits( uint256 _projectId, address payable _artistAddress, address payable _additionalPayeePrimarySales, uint256 _additionalPayeePrimarySalesPercentage, address payable _additionalPayeeSecondarySales, uint256 _additionalPayeeSecondarySalesPercentage ) external { _onlyValidProjectId(_projectId); _onlyArtist(_projectId); _onlyNonZeroAddress(_artistAddress); ProjectFinance storage projectFinance = _projectIdToFinancials[ _projectId ]; // checks if ( _additionalPayeePrimarySalesPercentage > ONE_HUNDRED || _additionalPayeeSecondarySalesPercentage > ONE_HUNDRED ) { revert GenArt721Error(ErrorCodes.MaxOf100Percent); } if ( _additionalPayeePrimarySalesPercentage > 0 && _additionalPayeePrimarySales == address(0) ) { revert GenArt721Error(ErrorCodes.PrimaryPayeeIsZeroAddress); } if ( _additionalPayeeSecondarySalesPercentage > 0 && _additionalPayeeSecondarySales == address(0) ) { revert GenArt721Error(ErrorCodes.SecondaryPayeeIsZeroAddress); } // effects // emit event for off-chain indexing // note: always emit a proposal event, even in the pathway of // automatic approval, to simplify indexing expectations emit ProposedArtistAddressesAndSplits( _projectId, _artistAddress, _additionalPayeePrimarySales, _additionalPayeePrimarySalesPercentage, _additionalPayeeSecondarySales, _additionalPayeeSecondarySalesPercentage ); // automatically accept if no proposed addresses modifications, or if // the proposal only removes payee addresses, or if contract is set to // always auto-approve. // store proposal hash on-chain, only if not automatic accept bool automaticAccept = autoApproveArtistSplitProposals; if (!automaticAccept) { // block scope to avoid stack too deep error bool artistUnchanged = _artistAddress == projectFinance.artistAddress; bool additionalPrimaryUnchangedOrRemoved = (_additionalPayeePrimarySales == projectFinance.additionalPayeePrimarySales) || (_additionalPayeePrimarySales == address(0)); bool additionalSecondaryUnchangedOrRemoved = (_additionalPayeeSecondarySales == projectFinance.additionalPayeeSecondarySales) || (_additionalPayeeSecondarySales == address(0)); automaticAccept = artistUnchanged && additionalPrimaryUnchangedOrRemoved && additionalSecondaryUnchangedOrRemoved; } if (automaticAccept) { // clear any previously proposed values proposedArtistAddressesAndSplitsHash[_projectId] = bytes32(0); // update storage // artist address can change during automatic accept if // autoApproveArtistSplitProposals is true projectFinance.artistAddress = _artistAddress; projectFinance .additionalPayeePrimarySales = _additionalPayeePrimarySales; // safe to cast as uint8 as max is 100%, max uint8 is 255 projectFinance.additionalPayeePrimarySalesPercentage = uint8( _additionalPayeePrimarySalesPercentage ); projectFinance .additionalPayeeSecondarySales = _additionalPayeeSecondarySales; // safe to cast as uint8 as max is 100%, max uint8 is 255 projectFinance.additionalPayeeSecondarySalesPercentage = uint8( _additionalPayeeSecondarySalesPercentage ); // assign project's splitter // @dev only call after all previous storage updates _assignSplitter(_projectId); // emit event for off-chain indexing emit AcceptedArtistAddressesAndSplits(_projectId); } else { proposedArtistAddressesAndSplitsHash[_projectId] = keccak256( abi.encode( _artistAddress, _additionalPayeePrimarySales, _additionalPayeePrimarySalesPercentage, _additionalPayeeSecondarySales, _additionalPayeeSecondarySalesPercentage ) ); } } /** * @notice Admin accepts a proposed set of updated artist address, * additional payee addresses, and percentage splits for project * `_projectId`. Addresses and percentages do not have to all be changed, * but they must all be defined as a complete set. * @param _projectId Project ID. * @param _artistAddress Artist address that controls the project, and may * receive payments. * @param _additionalPayeePrimarySales Address that may receive a * percentage split of the artist's primary sales revenue. * @param _additionalPayeePrimarySalesPercentage Percent of artist's * portion of primary sale revenue that will be split to address * `_additionalPayeePrimarySales`. * @param _additionalPayeeSecondarySales Address that may receive a percentage * split of the secondary sales royalties. * @param _additionalPayeeSecondarySalesPercentage Percent of artist's portion * of secondary sale royalties that will be split to address * `_additionalPayeeSecondarySales`. * @dev this must be called by the Admin ACL contract, and must only accept * the most recent proposed values for a given project (validated on-chain * by comparing the hash of the proposed and accepted values). * @dev `_artistAddress` must be a valid address (non-zero-address), but it * is intentionally allowable for `_additionalPayee{Primary,Secondaary}Sales` * and their associated percentages to be zero'd out by the controlling artist. */ function adminAcceptArtistAddressesAndSplits( uint256 _projectId, address payable _artistAddress, address payable _additionalPayeePrimarySales, uint256 _additionalPayeePrimarySalesPercentage, address payable _additionalPayeeSecondarySales, uint256 _additionalPayeeSecondarySalesPercentage ) external { _onlyValidProjectId(_projectId); _onlyAdminACLOrRenouncedArtist( _projectId, this.adminAcceptArtistAddressesAndSplits.selector ); _onlyNonZeroAddress(_artistAddress); // checks if ( proposedArtistAddressesAndSplitsHash[_projectId] != keccak256( abi.encode( _artistAddress, _additionalPayeePrimarySales, _additionalPayeePrimarySalesPercentage, _additionalPayeeSecondarySales, _additionalPayeeSecondarySalesPercentage ) ) ) { revert GenArt721Error(ErrorCodes.MustMatchArtistProposal); } // effects ProjectFinance storage projectFinance = _projectIdToFinancials[ _projectId ]; projectFinance.artistAddress = _artistAddress; projectFinance .additionalPayeePrimarySales = _additionalPayeePrimarySales; projectFinance.additionalPayeePrimarySalesPercentage = uint8( _additionalPayeePrimarySalesPercentage ); projectFinance .additionalPayeeSecondarySales = _additionalPayeeSecondarySales; projectFinance.additionalPayeeSecondarySalesPercentage = uint8( _additionalPayeeSecondarySalesPercentage ); // clear proposed values proposedArtistAddressesAndSplitsHash[_projectId] = bytes32(0); // assign project's splitter // @dev only call after all previous storage updates _assignSplitter(_projectId); // emit event for off-chain indexing emit AcceptedArtistAddressesAndSplits(_projectId); } /** * @notice Updates artist of project `_projectId` to `_artistAddress`. * This is to only be used in the event that the artist address is * compromised or sanctioned. * @param _projectId Project ID. * @param _artistAddress New artist address. */ function updateProjectArtistAddress( uint256 _projectId, address payable _artistAddress ) external { _onlyValidProjectId(_projectId); _onlyAdminACLOrRenouncedArtist( _projectId, this.updateProjectArtistAddress.selector ); _onlyNonZeroAddress(_artistAddress); _projectIdToFinancials[_projectId].artistAddress = _artistAddress; // assign project's splitter // @dev only call after all previous storage updates _assignSplitter(_projectId); emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_ARTIST_ADDRESS)) ); } /** * @notice Toggles paused state of project `_projectId`. * @param _projectId Project ID to be toggled. */ function toggleProjectIsPaused(uint256 _projectId) external { _onlyArtist(_projectId); projects[_projectId].paused = !projects[_projectId].paused; emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_PAUSED)) ); } /** * @notice Adds new project `_projectName` by `_artistAddress`. * @param _projectName Project name. * @param _artistAddress Artist's address. * @dev token price now stored on minter */ function addProject( string memory _projectName, address payable _artistAddress ) external { _onlyAdminACL(this.addProject.selector); _onlyNonEmptyString(_projectName); _onlyNonZeroAddress(_artistAddress); if (newProjectsForbidden) { revert GenArt721Error(ErrorCodes.NewProjectsForbidden); } uint256 projectId = _nextProjectId; ProjectFinance storage projectFinance = _projectIdToFinancials[ projectId ]; projectFinance.artistAddress = _artistAddress; projects[projectId].name = _projectName; projects[projectId].paused = true; projects[projectId].maxInvocations = ONE_MILLION_UINT24; projects[projectId].projectBaseURI = defaultBaseURI; // assign default artist royalty to artist projectFinance .secondaryMarketRoyaltyPercentage = _DEFAULT_ARTIST_SECONDARY_ROYALTY_PERCENTAGE; // copy default platform and render provider royalties to ProjectFinance projectFinance .platformProviderSecondarySalesAddress = defaultPlatformProviderSecondarySalesAddress; projectFinance.platformProviderSecondarySalesBPS = uint16( defaultPlatformProviderSecondarySalesBPS ); projectFinance .renderProviderSecondarySalesAddress = defaultRenderProviderSecondarySalesAddress; projectFinance.renderProviderSecondarySalesBPS = uint16( defaultRenderProviderSecondarySalesBPS ); _nextProjectId = uint248(projectId) + 1; // @dev emit initial project created event before splitter event emit ProjectUpdated( projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_CREATED)) ); // assign project's splitter // @dev only call after all previous storage updates _assignSplitter(projectId); } /** * @notice Forever forbids new projects from being added to this contract. */ function forbidNewProjects() external { _onlyAdminACL(this.forbidNewProjects.selector); if (newProjectsForbidden) { revert GenArt721Error(ErrorCodes.NewProjectsAlreadyForbidden); } _forbidNewProjects(); } /** * @notice Updates name of project `_projectId` to be `_projectName`. * @param _projectId Project ID. * @param _projectName New project name. */ function updateProjectName( uint256 _projectId, string memory _projectName ) external { _onlyUnlocked(_projectId); _onlyArtistOrAdminACL(_projectId, this.updateProjectName.selector); _onlyNonEmptyString(_projectName); projects[_projectId].name = _projectName; emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_NAME)) ); } /** * @notice Updates artist name for project `_projectId` to be * `_projectArtistName`. * @dev allows admin to update after project is locked, due to our * experiences of artist name changes being requested post-lock. * @param _projectId Project ID. * @param _projectArtistName New artist name. */ function updateProjectArtistName( uint256 _projectId, string memory _projectArtistName ) external { // if unlocked, only artist may update, if locked, only admin may update // @dev valid project checked in _projectUnlocked function if (_projectUnlocked(_projectId)) { if ( msg.sender != _projectIdToFinancials[_projectId].artistAddress ) { revert GenArt721Error(ErrorCodes.OnlyArtistOrAdminIfLocked); } } else { if ( !adminACLAllowed( msg.sender, address(this), this.updateProjectArtistName.selector ) ) { revert GenArt721Error(ErrorCodes.OnlyArtistOrAdminIfLocked); } } _onlyNonEmptyString(_projectArtistName); projects[_projectId].artist = _projectArtistName; emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_ARTIST_NAME)) ); } /** * @notice Updates artist secondary market royalties for project * `_projectId` to be `_secondaryMarketRoyalty` percent. * This deploys a new splitter contract if needed. * This DOES NOT include the secondary market royalty percentages collected * by the issuing platform; it is only the total percentage of royalties * that will be split to artist and additionalSecondaryPayee. * @param _projectId Project ID. * @param _secondaryMarketRoyalty Percent of secondary sales revenue that will * be split to artist and additionalSecondaryPayee. This must be less than * or equal to ARTIST_MAX_SECONDARY_ROYALTY_PERCENTAGE percent. */ function updateProjectSecondaryMarketRoyaltyPercentage( uint256 _projectId, uint256 _secondaryMarketRoyalty ) external { _onlyArtist(_projectId); if (_secondaryMarketRoyalty > ARTIST_MAX_SECONDARY_ROYALTY_PERCENTAGE) { revert GenArt721Error(ErrorCodes.OverMaxSecondaryRoyaltyPercentage); } _projectIdToFinancials[_projectId] .secondaryMarketRoyaltyPercentage = uint8(_secondaryMarketRoyalty); // assign project's splitter // @dev only call after all previous storage updates _assignSplitter(_projectId); emit ProjectUpdated( _projectId, bytes32( uint256( ProjectUpdatedFields .FIELD_PROJECT_SECONDARY_MARKET_ROYALTY_PERCENTAGE ) ) ); } /** * @notice Updates platform and render provider secondary market royalty addresses * and BPS to the contract-level default values for project `_projectId`. * This updates the splitter parameters on the existing splitter for the project. * Reverts if called by a non-admin address. * @param _projectId Project ID. */ function syncProviderSecondaryForProjectToDefaults( uint256 _projectId ) external { _onlyAdminACL(this.syncProviderSecondaryForProjectToDefaults.selector); _onlyValidProjectId(_projectId); ProjectFinance storage projectFinance = _projectIdToFinancials[ _projectId ]; // update project finance for project in storage projectFinance .platformProviderSecondarySalesAddress = defaultPlatformProviderSecondarySalesAddress; projectFinance.platformProviderSecondarySalesBPS = uint16( defaultPlatformProviderSecondarySalesBPS ); projectFinance .renderProviderSecondarySalesAddress = defaultRenderProviderSecondarySalesAddress; projectFinance.renderProviderSecondarySalesBPS = uint16( defaultRenderProviderSecondarySalesBPS ); emit ProjectUpdated( _projectId, bytes32( uint256( ProjectUpdatedFields .FIELD_PROJECT_PROVIDER_SECONDARY_FINANCIALS ) ) ); // assign project's splitter // @dev only call after all previous storage updates _assignSplitter(_projectId); } /** * @notice Updates description of project `_projectId`. * Only artist may call when unlocked, only admin may call when locked. * Note: The BytecodeStorage library is used to store the description to * reduce initial upload cost, however, even minor edits will require an * expensive, entirely new bytecode storage contract to be deployed instead * of relatively cheap updates to already-warm storage slots. This results * in an increased gas cost for minor edits to the description after the * initial upload, but an overall decrease in gas cost for projects with * less than ~3-5 edits (depending on the length of the description). * @param _projectId Project ID. * @param _projectDescription New project description. */ function updateProjectDescription( uint256 _projectId, string memory _projectDescription ) external { // checks // if unlocked, only artist may update, if locked, only admin may update if (_projectUnlocked(_projectId)) { if ( msg.sender != _projectIdToFinancials[_projectId].artistAddress ) { revert GenArt721Error(ErrorCodes.OnlyArtistOrAdminIfLocked); } } else { if ( !adminACLAllowed( msg.sender, address(this), this.updateProjectDescription.selector ) ) { revert GenArt721Error(ErrorCodes.OnlyArtistOrAdminIfLocked); } } // effects // store description in contract bytecode, replacing reference address from // the old storage description with the newly created one projects[_projectId].descriptionAddress = _projectDescription .writeToBytecode(); emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_DESCRIPTION)) ); } /** * @notice Updates website of project `_projectId` to be `_projectWebsite`. * @param _projectId Project ID. * @param _projectWebsite New project website. * @dev It is intentionally allowed for this to be set to the empty string. */ function updateProjectWebsite( uint256 _projectId, string memory _projectWebsite ) external { _onlyArtist(_projectId); projects[_projectId].website = _projectWebsite; emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_WEBSITE)) ); } /** * @notice Updates license for project `_projectId`. * @param _projectId Project ID. * @param _projectLicense New project license. */ function updateProjectLicense( uint256 _projectId, string memory _projectLicense ) external { _onlyUnlocked(_projectId); _onlyArtistOrAdminACL(_projectId, this.updateProjectLicense.selector); _onlyNonEmptyString(_projectLicense); projects[_projectId].license = _projectLicense; emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_LICENSE)) ); } /** * @notice Updates maximum invocations for project `_projectId` to * `_maxInvocations`. Maximum invocations may only be decreased by the * artist, and must be greater than or equal to current invocations. * New projects are created with maximum invocations of 1 million by * default. * @param _projectId Project ID. * @param _maxInvocations New maximum invocations. */ function updateProjectMaxInvocations( uint256 _projectId, uint24 _maxInvocations ) external { _onlyArtist(_projectId); // CHECKS Project storage project = projects[_projectId]; uint256 _invocations = project.invocations; if (_maxInvocations >= project.maxInvocations) { revert GenArt721Error(ErrorCodes.OnlyMaxInvocationsDecrease); } if (_maxInvocations < _invocations) { revert GenArt721Error(ErrorCodes.OnlyGteInvocations); } // EFFECTS project.maxInvocations = _maxInvocations; emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_MAX_INVOCATIONS)) ); // register completed timestamp if action completed the project if (_maxInvocations == _invocations) { _completeProject(_projectId); } } /** * @notice Adds a script to project `_projectId`. * @param _projectId Project to be updated. * @param _script Script to be added. Required to be a non-empty string, * but no further validation is performed. */ function addProjectScript( uint256 _projectId, string memory _script ) external { _onlyUnlocked(_projectId); _onlyArtistOrAdminACL(_projectId, this.addProjectScript.selector); _onlyNonEmptyString(_script); Project storage project = projects[_projectId]; // store script in contract bytecode project.scriptBytecodeAddresses[project.scriptCount] = _script .writeToBytecode(); project.scriptCount = project.scriptCount + 1; emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_SCRIPT)) ); } /** * @notice Adds a pre-compressed script to project `_projectId`. The script * should be compressed using `getCompressed`. This function stores the script * in a compressed format on-chain. For reads, the compressed script is * decompressed on-chain, ensuring the original text is reconstructed without * external dependencies. * @param _projectId Project to be updated. * @param _compressedScript Pre-compressed script to be added. * Required to be non-empty, but no further validation is performed. */ function addProjectScriptCompressed( uint256 _projectId, bytes memory _compressedScript ) external { _onlyUnlocked(_projectId); _onlyArtistOrAdminACL( _projectId, this.addProjectScriptCompressed.selector ); _onlyNonEmptyBytes(_compressedScript); Project storage project = projects[_projectId]; // store compressed script in contract bytecode project.scriptBytecodeAddresses[project.scriptCount] = _compressedScript .writeToBytecodeCompressed(); project.scriptCount = project.scriptCount + 1; emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_SCRIPT)) ); } /** * @notice Updates script for project `_projectId` at script ID `_scriptId`. * @param _projectId Project to be updated. * @param _scriptId Script ID to be updated. * @param _script The updated script value. Required to be a non-empty * string, but no further validation is performed. */ function updateProjectScript( uint256 _projectId, uint256 _scriptId, string memory _script ) external { _onlyUnlocked(_projectId); _onlyArtistOrAdminACL(_projectId, this.updateProjectScript.selector); _onlyNonEmptyString(_script); Project storage project = projects[_projectId]; if (_scriptId >= project.scriptCount) { revert GenArt721Error(ErrorCodes.ScriptIdOutOfRange); } // store script in contract bytecode, replacing reference address from // the old storage contract with the newly created one project.scriptBytecodeAddresses[_scriptId] = _script.writeToBytecode(); emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_SCRIPT)) ); } /** * @notice Updates script for project `_projectId` at script ID `_scriptId` * with a pre-compressed script. The script should be compressed using * `getCompressed`. This function stores the script in a compressed format * on-chain. For reads, the compressed script is decompressed on-chain, ensuring * the original text is reconstructed without external dependencies. * @param _projectId Project to be updated. * @param _scriptId Script ID to be updated. * @param _compressedScript The updated pre-compressed script value. * Required to be non-empty, but no further validation is performed. */ function updateProjectScriptCompressed( uint256 _projectId, uint256 _scriptId, bytes memory _compressedScript ) external { _onlyUnlocked(_projectId); _onlyArtistOrAdminACL( _projectId, this.updateProjectScriptCompressed.selector ); _onlyNonEmptyBytes(_compressedScript); Project storage project = projects[_projectId]; if (_scriptId >= project.scriptCount) { revert GenArt721Error(ErrorCodes.ScriptIdOutOfRange); } // store script in contract bytecode, replacing reference address from // the old storage contract with the newly created one project.scriptBytecodeAddresses[_scriptId] = _compressedScript .writeToBytecodeCompressed(); emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_SCRIPT)) ); } /** * @notice Removes last script from project `_projectId`. * @param _projectId Project to be updated. */ function removeProjectLastScript(uint256 _projectId) external { _onlyUnlocked(_projectId); _onlyArtistOrAdminACL( _projectId, this.removeProjectLastScript.selector ); Project storage project = projects[_projectId]; if (project.scriptCount == 0) { revert GenArt721Error(ErrorCodes.NoScriptsToRemove); } // delete reference to old storage contract address delete project.scriptBytecodeAddresses[project.scriptCount - 1]; unchecked { project.scriptCount = project.scriptCount - 1; } emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_SCRIPT)) ); } /** * @notice Updates script type for project `_projectId`. * @param _projectId Project to be updated. * @param _scriptTypeAndVersion Script type and version e.g. "[email protected]", * as bytes32 encoded string. */ function updateProjectScriptType( uint256 _projectId, bytes32 _scriptTypeAndVersion ) external { _onlyUnlocked(_projectId); _onlyArtistOrAdminACL( _projectId, this.updateProjectScriptType.selector ); Project storage project = projects[_projectId]; // require exactly one @ symbol in _scriptTypeAndVersion if ( !_scriptTypeAndVersion.containsExactCharacterQty( AT_CHARACTER_CODE, uint8(1) ) ) { revert GenArt721Error(ErrorCodes.ScriptTypeAndVersionFormat); } project.scriptTypeAndVersion = _scriptTypeAndVersion; emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_SCRIPT_TYPE)) ); } /** * @notice Updates project's aspect ratio. * @param _projectId Project to be updated. * @param _aspectRatio Aspect ratio to be set. Intended to be string in the * format of a decimal, e.g. "1" for square, "1.77777778" for 16:9, etc., * allowing for a maximum of 10 digits and one (optional) decimal separator. */ function updateProjectAspectRatio( uint256 _projectId, string memory _aspectRatio ) external { _onlyUnlocked(_projectId); _onlyArtistOrAdminACL( _projectId, this.updateProjectAspectRatio.selector ); _onlyNonEmptyString(_aspectRatio); // Perform more detailed input validation for aspect ratio. bytes memory aspectRatioBytes = bytes(_aspectRatio); uint256 bytesLength = aspectRatioBytes.length; if (bytesLength > 11) { revert GenArt721Error(ErrorCodes.AspectRatioTooLong); } bool hasSeenDecimalSeparator = false; bool hasSeenNumber = false; for (uint256 i; i < bytesLength; i++) { bytes1 character = aspectRatioBytes[i]; // Allow as many #s as desired. if (character >= 0x30 && character <= 0x39) { // 9-0 // We need to ensure there is at least 1 `9-0` occurrence. hasSeenNumber = true; continue; } if (character == 0x2E) { // . // Allow no more than 1 `.` occurrence. if (!hasSeenDecimalSeparator) { hasSeenDecimalSeparator = true; continue; } } revert GenArt721Error(ErrorCodes.AspectRatioImproperFormat); } if (!hasSeenNumber) { revert GenArt721Error(ErrorCodes.AspectRatioNoNumbers); } projects[_projectId].aspectRatio = _aspectRatio; emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_ASPECT_RATIO)) ); } /** * @notice Updates base URI for project `_projectId` to `_newBaseURI`. * This is the controlling base URI for all tokens in the project. The * contract-level defaultBaseURI is only used when initializing new * projects. * @param _projectId Project to be updated. * @param _newBaseURI New base URI. */ function updateProjectBaseURI( uint256 _projectId, string memory _newBaseURI ) external { _onlyArtist(_projectId); _onlyNonEmptyString(_newBaseURI); projects[_projectId].projectBaseURI = _newBaseURI; emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_BASE_URI)) ); } /** * @notice Updates default base URI to `_defaultBaseURI`. The * contract-level defaultBaseURI is only used when initializing new * projects. Token URIs are determined by their project's `projectBaseURI`. * @param _defaultBaseURI New default base URI. */ function updateDefaultBaseURI(string memory _defaultBaseURI) external { _onlyAdminACL(this.updateDefaultBaseURI.selector); _onlyNonEmptyString(_defaultBaseURI); _updateDefaultBaseURI(_defaultBaseURI); } /** * @notice Next project ID to be created on this contract. * @return uint256 Next project ID. */ function nextProjectId() external view returns (uint256) { return _nextProjectId; } /** * @notice Returns token hash for token ID `_tokenId`. Returns null if hash * has not been set. * @param _tokenId Token ID to be queried. * @return bytes32 Token hash. * @dev token hash is the keccak256 hash of the stored hash seed */ function tokenIdToHash(uint256 _tokenId) external view returns (bytes32) { bytes12 _hashSeed = _ownersAndHashSeeds[_tokenId].hashSeed; if (_hashSeed == 0) { return 0; } return keccak256(abi.encode(_hashSeed)); } /** * @notice Returns token hash **seed** for token ID `_tokenId`. Returns * null if hash seed has not been set. The hash seed id the bytes12 value * which is hashed to produce the token hash. * @param _tokenId Token ID to be queried. * @return bytes12 Token hash seed. * @dev token hash seed is keccak256 hashed to give the token hash */ function tokenIdToHashSeed( uint256 _tokenId ) external view returns (bytes12) { return _ownersAndHashSeeds[_tokenId].hashSeed; } /** * @notice View function returning the render provider portion of * primary sales, in percent. * @return uint256 The render provider portion of primary sales, * in percent. */ function renderProviderPrimarySalesPercentage() external view returns (uint256) { return _renderProviderPrimarySalesPercentage; } /** * @notice View function returning the platform provider portion of * primary sales, in percent. * @return uint256 The platform provider portion of primary sales, * in percent. */ function platformProviderPrimarySalesPercentage() external view returns (uint256) { return _platformProviderPrimarySalesPercentage; } /** * @notice View function returning Artist's address for project * `_projectId`. * @param _projectId Project ID to be queried. * @return address Artist's address. */ function projectIdToArtistAddress( uint256 _projectId ) external view returns (address payable) { return _projectIdToFinancials[_projectId].artistAddress; } /** * @notice View function returning Artist's secondary market royalty * percentage for project `_projectId`. * This does not include render/platform providers portions of secondary * market royalties. * @param _projectId Project ID to be queried. * @return uint256 Artist's secondary market royalty percentage. */ function projectIdToSecondaryMarketRoyaltyPercentage( uint256 _projectId ) external view returns (uint256) { return _projectIdToFinancials[_projectId].secondaryMarketRoyaltyPercentage; } /** * @notice View function returning project financial details for project * `_projectId`. * @param _projectId Project ID to be queried. * @return ProjectFinance Project financial details. */ function projectIdToFinancials( uint256 _projectId ) external view returns (ProjectFinance memory) { return _projectIdToFinancials[_projectId]; } /** * @notice Returns project details for project `_projectId`. * @param _projectId Project to be queried. * @return projectName Name of project * @return artist Artist of project * @return description Project description * @return website Project website * @return license Project license * @dev this function was named projectDetails prior to V3 core contract. */ function projectDetails( uint256 _projectId ) external view returns ( string memory projectName, string memory artist, string memory description, string memory website, string memory license ) { Project storage project = projects[_projectId]; projectName = project.name; artist = project.artist; address projectDescriptionBytecodeAddress = project.descriptionAddress; if (projectDescriptionBytecodeAddress == address(0)) { description = ""; } else { description = _readFromBytecode(projectDescriptionBytecodeAddress); } website = project.website; license = project.license; } /** * @notice Returns project state data for project `_projectId`. * @param _projectId Project to be queried * @return invocations Current number of invocations * @return maxInvocations Maximum allowed invocations * @return active Boolean representing if project is currently active * @return paused Boolean representing if project is paused * @return completedTimestamp zero if project not complete, otherwise * timestamp of project completion. * @return locked Boolean representing if project is locked * @dev price and currency info are located on minter contracts */ function projectStateData( uint256 _projectId ) external view returns ( uint256 invocations, uint256 maxInvocations, bool active, bool paused, uint256 completedTimestamp, bool locked ) { Project storage project = projects[_projectId]; invocations = project.invocations; maxInvocations = project.maxInvocations; active = project.active; paused = project.paused; completedTimestamp = project.completedTimestamp; locked = !_projectUnlocked(_projectId); } /** * @notice Returns script information for project `_projectId`. * @param _projectId Project to be queried. * @return scriptTypeAndVersion Project's script type and version * (e.g. "p5js(atSymbol)1.0.0") * @return aspectRatio Aspect ratio of project (e.g. "1" for square, * "1.77777778" for 16:9, etc.) * @return scriptCount Count of scripts for project */ function projectScriptDetails( uint256 _projectId ) external view override(IGenArt721CoreContractV3_Base, IDependencyRegistryCompatibleV0) returns ( string memory scriptTypeAndVersion, string memory aspectRatio, uint256 scriptCount ) { Project storage project = projects[_projectId]; scriptTypeAndVersion = project.scriptTypeAndVersion.toString(); aspectRatio = project.aspectRatio; scriptCount = project.scriptCount; } /** * @notice Returns address with bytecode containing project script for * project `_projectId` at script index `_index`. */ function projectScriptBytecodeAddressByIndex( uint256 _projectId, uint256 _index ) external view returns (address) { return projects[_projectId].scriptBytecodeAddresses[_index]; } /** * @notice Returns the compressed form of a string in bytes using solady LibZip's flz compress algorithm. The bytes output from this function are intended to be used as input to `addProjectScriptCompressed` and `updateProjectScriptCompressed`. * @param _script Script to be compressed. Required to be a non-empty string, but no further validaton is performed. * @return bytes compressed bytes */ function getCompressed( string memory _script ) external pure returns (bytes memory) { _onlyNonEmptyString(_script); // @dev want a potentially version-specific compression algorithm, so use version-specific library here return BytecodeStorageReader.getCompressed(_script); } /** * @notice Returns script for project `_projectId` at script index `_index`. * @param _projectId Project to be queried. * @param _index Index of script to be queried. */ function projectScriptByIndex( uint256 _projectId, uint256 _index ) external view returns (string memory) { Project storage project = projects[_projectId]; // If trying to access an out-of-index script, return the empty string. if (_index >= project.scriptCount) { return ""; } return _readFromBytecode(project.scriptBytecodeAddresses[_index]); } /** * @notice Returns base URI for project `_projectId`. * @param _projectId Project to be queried. * @return projectBaseURI Base URI for project */ function projectURIInfo( uint256 _projectId ) external view returns (string memory projectBaseURI) { projectBaseURI = projects[_projectId].projectBaseURI; } /** * @notice Backwards-compatible (pre-V3) function returning if `_minter` is * minterContract. * @param _minter Address to be queried. * @return bool Boolean representing if `_minter` is minterContract. */ function isMintWhitelisted(address _minter) external view returns (bool) { return (minterContract == _minter); } /** * @notice Gets qty of randomizers in history of all randomizers used by * this core contract. If a randomizer is switched away from then back to, * it will show up in the history twice. * @return randomizerHistoryCount Count of randomizers in history */ function numHistoricalRandomizers() external view returns (uint256) { return _historicalRandomizerAddresses.length; } /** * @notice Gets address of randomizer at index `_index` in history of all * randomizers used by this core contract. Index is zero-based. * @param _index Historical index of randomizer to be queried. * @return randomizerAddress Address of randomizer at index `_index`. * @dev If a randomizer is switched away from and then switched back to, it * will show up in the history twice. */ function getHistoricalRandomizerAt( uint256 _index ) external view returns (address) { if (_index >= _historicalRandomizerAddresses.length) { revert GenArt721Error(ErrorCodes.IndexOutOfBounds); } return _historicalRandomizerAddresses[_index]; } /** * @notice Gets ERC-2981 royalty information for token with ID `_tokenId` * and sale price `_salePrice`. * @param _tokenId Token ID to be queried for royalty information * @param _salePrice the sale price of the NFT asset specified by _tokenId * @return receiver address that should be sent the royalty payment * @return royaltyAmount the royalty payment amount for `_salePrice * @dev reverts if invalid _tokenId */ function royaltyInfo( uint256 _tokenId, uint256 _salePrice ) external view returns (address receiver, uint256 royaltyAmount) { _onlyValidTokenId(_tokenId); // populate receiver with project's royalty splitter // @dev royalty splitter created upon project creation, so will always exist // for valid token ID uint256 projectId = tokenIdToProjectId(_tokenId); ProjectFinance storage projectFinance = _projectIdToFinancials[ projectId ]; receiver = projectFinance.royaltySplitter; // populate royaltyAmount with calculated royalty amount // @dev important to cast to uint256 before multiplying to avoid overflow uint256 totalRoyaltyBPS = (100 * uint256(projectFinance.secondaryMarketRoyaltyPercentage)) + projectFinance.platformProviderSecondarySalesBPS + projectFinance.renderProviderSecondarySalesBPS; // @dev totalRoyaltyBPS guaranteed to be <= 10,000, if (totalRoyaltyBPS > 10_000) { revert GenArt721Error(ErrorCodes.OverMaxSumOfBPS); } // @dev overflow automatically checked in solidity 0.8 // @dev totalRoyaltyBPS guaranteed to be <= 10_000, // so overflow only possible with unreasonably high _salePrice values near uint256 max royaltyAmount = (_salePrice * totalRoyaltyBPS) / 10_000; } /** * @notice View function that returns appropriate revenue splits between * different render provider, platform provider, Artist, and Artist's * additional primary sales payee given a sale price of `_price` on * project `_projectId`. * This always returns four revenue amounts and four addresses, but if a * revenue is zero for either Artist or additional payee, the corresponding * address returned will also be null (for gas optimization). * Does not account for refund if user overpays for a token (minter should * handle a refund of the difference, if appropriate). * Some minters may have alternative methods of splitting payments, in * which case they should implement their own payment splitting logic. * @param _projectId Project ID to be queried. * @param _price Sale price of token. * @return renderProviderRevenue_ amount of revenue to be sent to the * render provider * @return renderProviderAddress_ address to send render provider revenue to * @return platformProviderRevenue_ amount of revenue to be sent to the * platform provider * @return platformProviderAddress_ address to send platform provider revenue to * @return artistRevenue_ amount of revenue to be sent to Artist * @return artistAddress_ address to send Artist revenue to. Will be null * if no revenue is due to artist (gas optimization). * @return additionalPayeePrimaryRevenue_ amount of revenue to be sent to * additional payee for primary sales * @return additionalPayeePrimaryAddress_ address to send Artist's * additional payee for primary sales revenue to. Will be null if no * revenue is due to additional payee for primary sales (gas optimization). * @dev this always returns four addresses and four revenues, but if the * revenue is zero, the corresponding address will be address(0). It is up * to the contract performing the revenue split to handle this * appropriately. */ function getPrimaryRevenueSplits( uint256 _projectId, uint256 _price ) external view returns ( uint256 renderProviderRevenue_, address payable renderProviderAddress_, uint256 platformProviderRevenue_, address payable platformProviderAddress_, uint256 artistRevenue_, address payable artistAddress_, uint256 additionalPayeePrimaryRevenue_, address payable additionalPayeePrimaryAddress_ ) { ProjectFinance storage projectFinance = _projectIdToFinancials[ _projectId ]; // calculate revenues – this is a three-way split between the // render provider, the platform provider, and the artist, and // is safe to perform this given that in the case of loss of // precision Solidity will round down. uint256 projectFunds = _price; renderProviderRevenue_ = (_price * uint256(_renderProviderPrimarySalesPercentage)) / ONE_HUNDRED; // renderProviderRevenue_ percentage is always <=100, so guaranteed to never underflow projectFunds -= renderProviderRevenue_; platformProviderRevenue_ = (_price * uint256(_platformProviderPrimarySalesPercentage)) / ONE_HUNDRED; // platformProviderRevenue_ percentage is always <=100, so guaranteed to never underflow projectFunds -= platformProviderRevenue_; additionalPayeePrimaryRevenue_ = (projectFunds * projectFinance.additionalPayeePrimarySalesPercentage) / ONE_HUNDRED; // projectIdToAdditionalPayeePrimarySalesPercentage is always // <=100, so guaranteed to never underflow artistRevenue_ = projectFunds - additionalPayeePrimaryRevenue_; // set addresses from storage renderProviderAddress_ = renderProviderPrimarySalesAddress; platformProviderAddress_ = platformProviderPrimarySalesAddress; if (artistRevenue_ > 0) { artistAddress_ = projectFinance.artistAddress; } if (additionalPayeePrimaryRevenue_ > 0) { additionalPayeePrimaryAddress_ = projectFinance .additionalPayeePrimarySales; } } /** * @notice Backwards-compatible (pre-V3) getter returning contract admin * @return address Address of contract admin (same as owner) */ function admin() external view returns (address) { return owner(); } /** * @notice Gets the project ID for a given `_tokenId`. * @param _tokenId Token ID to be queried. * @return _projectId Project ID for given `_tokenId`. */ function tokenIdToProjectId( uint256 _tokenId ) public pure returns (uint256 _projectId) { return _tokenId / ONE_MILLION; } /** * @notice Convenience function that returns whether `_sender` is allowed * to call function with selector `_selector` on contract `_contract`, as * determined by this contract's current Admin ACL contract. Expected use * cases include minter contracts checking if caller is allowed to call * admin-gated functions on minter contracts. * @param _sender Address of the sender calling function with selector * `_selector` on contract `_contract`. * @param _contract Address of the contract being called by `_sender`. * @param _selector Function selector of the function being called by * `_sender`. * @return bool Whether `_sender` is allowed to call function with selector * `_selector` on contract `_contract`. * @dev assumes the Admin ACL contract is the owner of this contract, which * is expected to always be true. * @dev adminACLContract is expected to either be null address (if owner * has renounced ownership), or conform to IAdminACLV0 interface. Check for * null address first to avoid revert when admin has renounced ownership. */ function adminACLAllowed( address _sender, address _contract, bytes4 _selector ) public returns (bool) { return owner() != address(0) && adminACLContract.allowed(_sender, _contract, _selector); } /** * @notice Returns contract owner. Set to deployer's address by default on * contract deployment. * @return address Address of contract owner. * @dev ref: https://docs.openzeppelin.com/contracts/4.x/api/access#Ownable * @dev owner role was called `admin` prior to V3 core contract */ function owner() public view override(Ownable, IGenArt721CoreContractV3_Base) returns (address) { return Ownable.owner(); } /** * @notice Gets token URI for token ID `_tokenId`. * @param _tokenId Token ID to be queried. * @return string URI of token ID `_tokenId`. * @dev token URIs are the concatenation of the project base URI and the * token ID. */ function tokenURI( uint256 _tokenId ) public view override returns (string memory) { _onlyValidTokenId(_tokenId); string memory _projectBaseURI = projects[tokenIdToProjectId(_tokenId)] .projectBaseURI; return string.concat(_projectBaseURI, _tokenId.toString()); } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface( bytes4 interfaceId ) public view virtual override(ERC721_PackedHashSeedV1, IERC165) returns (bool) { return interfaceId == _INTERFACE_ID_ERC2981 || super.supportsInterface(interfaceId); } /** * @notice Forbids new projects from being created * @dev only performs operation and emits event if contract is not already * forbidding new projects. */ function _forbidNewProjects() internal { if (!newProjectsForbidden) { newProjectsForbidden = true; emit PlatformUpdated( bytes32( uint256(PlatformUpdatedFields.FIELD_NEW_PROJECTS_FORBIDDEN) ) ); } } /** * @notice Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. * @param newOwner New owner. * @dev owner role was called `admin` prior to V3 core contract. * @dev Overrides and wraps OpenZeppelin's _transferOwnership function to * also update adminACLContract for improved introspection. */ function _transferOwnership(address newOwner) internal override { Ownable._transferOwnership(newOwner); adminACLContract = IAdminACLV0(newOwner); } /** * @notice Updates sales addresses for the platform and render providers to * the input parameters. * Reverts if invalid platform provider addresses are provided given the * contract's immutably configured nullPlatformProvider state. * Does not check render provider addresses in any way. * @param _renderProviderPrimarySalesAddress Address of new primary sales * payment address. * @param _defaultRenderProviderSecondarySalesAddress Address of new secondary sales * payment address. * @param _platformProviderPrimarySalesAddress Address of new primary sales * payment address. * @param _defaultPlatformProviderSecondarySalesAddress Address of new secondary sales * payment address. */ function _updateProviderSalesAddresses( address _renderProviderPrimarySalesAddress, address _defaultRenderProviderSecondarySalesAddress, address _platformProviderPrimarySalesAddress, address _defaultPlatformProviderSecondarySalesAddress ) internal { if (nullPlatformProvider) { // require null platform provider address if ( _platformProviderPrimarySalesAddress != address(0) || _defaultPlatformProviderSecondarySalesAddress != address(0) ) { revert GenArt721Error(ErrorCodes.OnlyNullPlatformProvider); } } else { _onlyNonZeroAddress(_platformProviderPrimarySalesAddress); _onlyNonZeroAddress(_defaultPlatformProviderSecondarySalesAddress); } platformProviderPrimarySalesAddress = payable( _platformProviderPrimarySalesAddress ); defaultPlatformProviderSecondarySalesAddress = payable( _defaultPlatformProviderSecondarySalesAddress ); renderProviderPrimarySalesAddress = payable( _renderProviderPrimarySalesAddress ); defaultRenderProviderSecondarySalesAddress = payable( _defaultRenderProviderSecondarySalesAddress ); emit PlatformUpdated( bytes32( uint256(PlatformUpdatedFields.FIELD_PROVIDER_SALES_ADDRESSES) ) ); } /** * @notice Updates minter address to `_minterAddress`. * @param _minterAddress New minter address. * @dev Note that this method does not check that the input address is * not `address(0)`, as it is expected that callers of this method should * perform input validation where applicable. */ function _updateMinterContract(address _minterAddress) internal { minterContract = _minterAddress; emit MinterUpdated(_minterAddress); } /** * @notice Updates randomizer address to `_randomizerAddress`. * @param _randomizerAddress New randomizer address. * @dev Note that this method does not check that the input address is * not `address(0)`, as it is expected that callers of this method should * perform input validation where applicable. */ function _updateRandomizerAddress(address _randomizerAddress) internal { randomizerContract = IRandomizer_V3CoreBase(_randomizerAddress); // populate historical randomizer array _historicalRandomizerAddresses.push(_randomizerAddress); emit PlatformUpdated( bytes32(uint256(PlatformUpdatedFields.FIELD_RANDOMIZER_ADDRESS)) ); } /** * @notice Updates split provider address to `_splitProviderAddress`. * Reverts if `_splitProviderAddress` is the zero address. * @param _splitProviderAddress New split provider address. * @dev Note that this method does not check that the input address is * not `address(0)`, as it is expected that callers of this method should * perform input validation where applicable. */ function _updateSplitProvider(address _splitProviderAddress) internal { // require non-zero split provider address _onlyNonZeroAddress(_splitProviderAddress); splitProvider = ISplitProviderV0(_splitProviderAddress); emit PlatformUpdated( bytes32(uint256(PlatformUpdatedFields.FIELD_SPLIT_PROVIDER)) ); } /** * @notice Update the bytecode storage reader contract address, and emit corresponding event. * @param _bytecodeStorageReaderContract New bytecode storage reader contract address. */ function _updateBytecodeStorageReaderContract( address _bytecodeStorageReaderContract ) internal { bytecodeStorageReaderContract = IBytecodeStorageReader_Base( _bytecodeStorageReaderContract ); emit PlatformUpdated( bytes32( uint256(PlatformUpdatedFields.FIELD_BYTECODE_STORAGE_READER) ) ); } /** * @notice internal function to update a splitter contract for a project, * based on the project's financials in this contract's storage. * @dev Warning: this function uses storage reads to get the project's * financials, so ensure storage has been updated before calling this * @dev This function includes a trusted interaction that is entrusted to * not reenter this contract. * @param projectId Project ID to be updated. */ function _assignSplitter(uint256 projectId) internal { ProjectFinance storage projectFinance = _projectIdToFinancials[ projectId ]; // assign project's royalty splitter // @dev loads values from storage, so need to ensure storage has been updated address royaltySplitter = splitProvider.getOrCreateSplitter( ISplitProviderV0.SplitInputs({ platformProviderSecondarySalesAddress: projectFinance .platformProviderSecondarySalesAddress, platformProviderSecondarySalesBPS: projectFinance .platformProviderSecondarySalesBPS, renderProviderSecondarySalesAddress: projectFinance .renderProviderSecondarySalesAddress, renderProviderSecondarySalesBPS: projectFinance .renderProviderSecondarySalesBPS, artistTotalRoyaltyPercentage: projectFinance .secondaryMarketRoyaltyPercentage, artist: projectFinance.artistAddress, additionalPayee: projectFinance.additionalPayeeSecondarySales, additionalPayeePercentage: projectFinance .additionalPayeeSecondarySalesPercentage }) ); projectFinance.royaltySplitter = royaltySplitter; emit ProjectRoyaltySplitterUpdated({ projectId: projectId, royaltySplitter: royaltySplitter }); } /** * @notice Updates default base URI to `_defaultBaseURI`. * When new projects are added, their `projectBaseURI` is automatically * initialized to `_defaultBaseURI`. * @param _defaultBaseURI New default base URI. * @dev Note that this method does not check that the input string is not * the empty string, as it is expected that callers of this method should * perform input validation where applicable. */ function _updateDefaultBaseURI(string memory _defaultBaseURI) internal { defaultBaseURI = _defaultBaseURI; emit PlatformUpdated( bytes32(uint256(PlatformUpdatedFields.FIELD_DEFAULT_BASE_URI)) ); } /** * @notice Internal function to complete a project. * @param _projectId Project ID to be completed. */ function _completeProject(uint256 _projectId) internal { projects[_projectId].completedTimestamp = uint64(block.timestamp); emit ProjectUpdated( _projectId, bytes32(uint256(ProjectUpdatedFields.FIELD_PROJECT_COMPLETED)) ); } /** * @notice Initializes the contract with the provided `engineConfiguration`. * This function should be called atomically, immediately after deployment. * Only callable once. Validation on `engineConfiguration` is performed by caller. * @param engineConfiguration EngineConfiguration to configure the contract with. * @param adminACLContract_ Address of admin access control contract, to be * set as contract owner. * @param defaultBaseURIHost Base URI prefix to initialize default base URI with. * @param bytecodeStorageReaderContract_ Address of bytecode storage reader contract. */ function _initialize( EngineConfiguration memory engineConfiguration, address adminACLContract_, string memory defaultBaseURIHost, address bytecodeStorageReaderContract_ ) internal { // can only be initialized once if (_initialized) { revert GenArt721Error(ErrorCodes.ContractInitialized); } // immediately mark as initialized _initialized = true; // @dev assume renderProviderAddress, randomizer, and AdminACL non-zero // checks on platform provider addresses performed in _updateProviderSalesAddresses // initialize default sales revenue percentages and basis points _renderProviderPrimarySalesPercentage = 10; defaultRenderProviderSecondarySalesBPS = 250; _platformProviderPrimarySalesPercentage = engineConfiguration .nullPlatformProvider ? 0 : 10; defaultPlatformProviderSecondarySalesBPS = engineConfiguration .nullPlatformProvider ? 0 : 250; // set token name and token symbol ERC721_PackedHashSeedV1.initialize( engineConfiguration.tokenName, engineConfiguration.tokenSymbol ); // update minter if populated if (engineConfiguration.minterFilterAddress != address(0)) { _updateMinterContract(engineConfiguration.minterFilterAddress); } _updateSplitProvider(engineConfiguration.splitProviderAddress); _updateBytecodeStorageReaderContract(bytecodeStorageReaderContract_); // setup immutable `autoApproveArtistSplitProposals` config autoApproveArtistSplitProposals = engineConfiguration .autoApproveArtistSplitProposals; // setup immutable `nullPlatformProvider` config nullPlatformProvider = engineConfiguration.nullPlatformProvider; // setup immutable `allowArtistProjectActivation` config allowArtistProjectActivation = engineConfiguration .allowArtistProjectActivation; // record contracts starting project ID // casting-up is safe startingProjectId = uint256(engineConfiguration.startingProjectId); // @dev nullPlatformProvider must be set before calling _updateProviderSalesAddresses _updateProviderSalesAddresses( engineConfiguration.renderProviderAddress, engineConfiguration.renderProviderAddress, engineConfiguration.platformProviderAddress, engineConfiguration.platformProviderAddress ); _updateRandomizerAddress(engineConfiguration.randomizerContract); // set AdminACL management contract as owner _transferOwnership(adminACLContract_); // initialize default base URI _updateDefaultBaseURI( string.concat(defaultBaseURIHost, address(this).toHexString(), "/") ); // initialize next project ID _nextProjectId = engineConfiguration.startingProjectId; emit PlatformUpdated( bytes32(uint256(PlatformUpdatedFields.FIELD_NEXT_PROJECT_ID)) ); // @dev This contract is registered on the core registry in a // subsequent call by the factory. } /** * @notice Internal function that returns whether a project is unlocked. * Projects automatically lock four weeks after they are completed. * Projects are considered completed when they have been invoked the * maximum number of times. * @param _projectId Project ID to be queried. * @return bool true if project is unlocked, false otherwise. * @dev This also enforces that the `_projectId` passed in is valid. */ function _projectUnlocked(uint256 _projectId) internal view returns (bool) { _onlyValidProjectId(_projectId); uint256 projectCompletedTimestamp = projects[_projectId] .completedTimestamp; bool projectOpen = projectCompletedTimestamp == 0; return projectOpen || (block.timestamp - projectCompletedTimestamp < FOUR_WEEKS_IN_SECONDS); } /** * @notice Helper for calling bytecodeStorageReaderContract reader method; * added for bytecode size reduction purposes. */ function _readFromBytecode( address _address ) internal view returns (string memory) { return bytecodeStorageReaderContract.readFromBytecode(_address); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.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. * * The initial owner is set to the address provided by the deployer. 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 Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling 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 { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _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); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. */ interface IERC20Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. */ interface IERC1155Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param owner Address of the current owner of a token. */ error ERC1155MissingApprovalForAll(address operator, address owner); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC1155InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC1155InvalidOperator(address operator); /** * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. * Used in batch transfers. * @param idsLength Length of the array of token identifiers * @param valuesLength Length of the array of token amounts */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC2981.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol"; /** * @dev Interface for the NFT Royalty Standard. * * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal * support for royalty payments across all NFT marketplaces and ecosystem participants. */ interface IERC2981 is IERC165 { /** * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. */ function royaltyInfo( uint256 tokenId, uint256 salePrice ) external view returns (address receiver, uint256 royaltyAmount); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (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.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } 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 "./IERC165.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 ERC165 is IERC165 { /** * @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) (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: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; import "./IAdminACLV0.sol"; interface IAdminACLV0_Extended is IAdminACLV0 { /** * @notice Allows superAdmin change the superAdmin address. * @param _newSuperAdmin The new superAdmin address. * @param _genArt721CoreAddressesToUpdate Array of genArt721Core * addresses to update to the new superAdmin, for indexing purposes only. * @dev this function is gated to only superAdmin address. */ function changeSuperAdmin( address _newSuperAdmin, address[] calldata _genArt721CoreAddressesToUpdate ) external; }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; interface IAdminACLV0 { /** * @notice Token ID `_tokenId` minted to `_to`. * @param previousSuperAdmin The previous superAdmin address. * @param newSuperAdmin The new superAdmin address. * @param genArt721CoreAddressesToUpdate Array of genArt721Core * addresses to update to the new superAdmin, for indexing purposes only. */ event SuperAdminTransferred( address indexed previousSuperAdmin, address indexed newSuperAdmin, address[] genArt721CoreAddressesToUpdate ); /// Type of the Admin ACL contract, e.g. "AdminACLV0" function AdminACLType() external view returns (string memory); /// super admin address function superAdmin() external view returns (address); /** * @notice Calls transferOwnership on other contract from this contract. * This is useful for updating to a new AdminACL contract. * @dev this function should be gated to only superAdmin-like addresses. */ function transferOwnershipOn( address _contract, address _newAdminACL ) external; /** * @notice Calls renounceOwnership on other contract from this contract. * @dev this function should be gated to only superAdmin-like addresses. */ function renounceOwnershipOn(address _contract) external; /** * @notice Checks if sender `_sender` is allowed to call function with selector * `_selector` on contract `_contract`. */ function allowed( address _sender, address _contract, bytes4 _selector ) external returns (bool); }
// SPDX-License-Identifier: LGPL-3.0-only // Creatd By: Art Blocks Inc. pragma solidity ^0.8.0; /** * @title Art Blocks Script Storage Library - Minimal Interface for Reader Contracts * @notice This interface defines the minimal expected read function(s) for a Bytecode Storage Reader contract. */ interface IBytecodeStorageReader_Base { /** * @notice Read a string from a data contract deployed via BytecodeStorage. * @dev may also support reading additional stored data formats in the future. * @param address_ address of contract deployed via BytecodeStorage to be read * @return data The string data stored at the specific address. */ function readFromBytecode( address address_ ) external view returns (string memory data); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.19; interface IDependencyRegistryCompatibleV0 { /// Dependency registry managed by Art Blocks function artblocksDependencyRegistryAddress() external view returns (address); /** * @notice Returns script information for project `_projectId`. * @param _projectId Project to be queried. * @return scriptTypeAndVersion Project's script type and version * (e.g. "p5js(atSymbol)1.0.0") * @return aspectRatio Aspect ratio of project (e.g. "1" for square, * "1.77777778" for 16:9, etc.) * @return scriptCount Count of scripts for project */ function projectScriptDetails( uint256 _projectId ) external view returns ( string memory scriptTypeAndVersion, string memory aspectRatio, uint256 scriptCount ); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; interface IGenArt721CoreContractExposesHashSeed { // function to read the hash-seed for a given tokenId function tokenIdToHashSeed( uint256 _tokenId ) external view returns (bytes12); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; import "./IAdminACLV0.sol"; /** * @title This interface is intended to house interface items that are common * across all GenArt721CoreContractV3 flagship and derivative implementations. * This interface extends the IManifold royalty interface in order to * add support the Royalty Registry by default. * @author Art Blocks Inc. */ interface IGenArt721CoreContractV3_Base { // This interface emits generic events that contain fields that indicate // which parameter has been updated. This is sufficient for application // state management, while also simplifying the contract and indexing code. // This was done as an alternative to having custom events that emit what // field-values have changed for each event, given that changed values can // be introspected by indexers due to the design of this smart contract // exposing these state changes via publicly viewable fields. /** * @notice Project's royalty splitter was updated to `_splitter`. * @dev New event in v3.2 * @param projectId The project ID. * @param royaltySplitter The new splitter address to receive royalties. */ event ProjectRoyaltySplitterUpdated( uint256 indexed projectId, address indexed royaltySplitter ); // The following fields are used to indicate which contract-level parameter // has been updated in the `PlatformUpdated` event: // @dev only append to the end of this enum in the case of future updates enum PlatformUpdatedFields { FIELD_NEXT_PROJECT_ID, // 0 FIELD_NEW_PROJECTS_FORBIDDEN, // 1 FIELD_DEFAULT_BASE_URI, // 2 FIELD_RANDOMIZER_ADDRESS, // 3 FIELD_NEXT_CORE_CONTRACT, // 4 FIELD_ARTBLOCKS_DEPENDENCY_REGISTRY_ADDRESS, // 5 FIELD_ARTBLOCKS_ON_CHAIN_GENERATOR_ADDRESS, // 6 FIELD_PROVIDER_SALES_ADDRESSES, // 7 FIELD_PROVIDER_PRIMARY_SALES_PERCENTAGES, // 8 FIELD_PROVIDER_SECONDARY_SALES_BPS, // 9 FIELD_SPLIT_PROVIDER, // 10 FIELD_BYTECODE_STORAGE_READER // 11 } // The following fields are used to indicate which project-level parameter // has been updated in the `ProjectUpdated` event: // @dev only append to the end of this enum in the case of future updates enum ProjectUpdatedFields { FIELD_PROJECT_COMPLETED, // 0 FIELD_PROJECT_ACTIVE, // 1 FIELD_PROJECT_ARTIST_ADDRESS, // 2 FIELD_PROJECT_PAUSED, // 3 FIELD_PROJECT_CREATED, // 4 FIELD_PROJECT_NAME, // 5 FIELD_PROJECT_ARTIST_NAME, // 6 FIELD_PROJECT_SECONDARY_MARKET_ROYALTY_PERCENTAGE, // 7 FIELD_PROJECT_DESCRIPTION, // 8 FIELD_PROJECT_WEBSITE, // 9 FIELD_PROJECT_LICENSE, // 10 FIELD_PROJECT_MAX_INVOCATIONS, // 11 FIELD_PROJECT_SCRIPT, // 12 FIELD_PROJECT_SCRIPT_TYPE, // 13 FIELD_PROJECT_ASPECT_RATIO, // 14 FIELD_PROJECT_BASE_URI, // 15 FIELD_PROJECT_PROVIDER_SECONDARY_FINANCIALS // 16 } /** * @notice Error codes for the GenArt721 contract. Used by the GenArt721Error * custom error. * @dev only append to the end of this enum in the case of future updates */ enum ErrorCodes { OnlyNonZeroAddress, // 0 OnlyNonEmptyString, // 1 OnlyNonEmptyBytes, // 2 TokenDoesNotExist, // 3 ProjectDoesNotExist, // 4 OnlyUnlockedProjects, // 5 OnlyAdminACL, // 6 OnlyArtist, // 7 OnlyArtistOrAdminACL, // 8 OnlyAdminACLOrRenouncedArtist, // 9 OnlyMinterContract, // 10 MaxInvocationsReached, // 11 ProjectMustExistAndBeActive, // 12 PurchasesPaused, // 13 OnlyRandomizer, // 14 TokenHashAlreadySet, // 15 NoZeroHashSeed, // 16 OverMaxSumOfPercentages, // 17 IndexOutOfBounds, // 18 OverMaxSumOfBPS, // 19 MaxOf100Percent, // 20 PrimaryPayeeIsZeroAddress, // 21 SecondaryPayeeIsZeroAddress, // 22 MustMatchArtistProposal, // 23 NewProjectsForbidden, // 24 NewProjectsAlreadyForbidden, // 25 OnlyArtistOrAdminIfLocked, // 26 OverMaxSecondaryRoyaltyPercentage, // 27 OnlyMaxInvocationsDecrease, // 28 OnlyGteInvocations, // 29 ScriptIdOutOfRange, // 30 NoScriptsToRemove, // 31 ScriptTypeAndVersionFormat, // 32 AspectRatioTooLong, // 33 AspectRatioNoNumbers, // 34 AspectRatioImproperFormat, // 35 OnlyNullPlatformProvider, // 36 ContractInitialized // 37 } /** * @notice Emits an error code `_errorCode` in the GenArt721Error event. * @dev Emitting error codes instead of error strings saves significant * contract bytecode size, allowing for more contract functionality within * the 24KB contract size limit. * @param _errorCode The error code to emit. See ErrorCodes enum. */ error GenArt721Error(ErrorCodes _errorCode); /** * @notice Token ID `_tokenId` minted to `_to`. */ event Mint(address indexed _to, uint256 indexed _tokenId); /** * @notice currentMinter updated to `_currentMinter`. * @dev Implemented starting with V3 core */ event MinterUpdated(address indexed _currentMinter); /** * @notice Platform updated on bytes32-encoded field `_field`. */ event PlatformUpdated(bytes32 indexed _field); /** * @notice Project ID `_projectId` updated on bytes32-encoded field * `_update`. */ event ProjectUpdated(uint256 indexed _projectId, bytes32 indexed _update); event ProposedArtistAddressesAndSplits( uint256 indexed _projectId, address _artistAddress, address _additionalPayeePrimarySales, uint256 _additionalPayeePrimarySalesPercentage, address _additionalPayeeSecondarySales, uint256 _additionalPayeeSecondarySalesPercentage ); event AcceptedArtistAddressesAndSplits(uint256 indexed _projectId); // version and type of the core contract // coreVersion is a string of the form "0.x.y" function coreVersion() external view returns (string memory); // coreType is a string of the form "GenArt721CoreV3" function coreType() external view returns (string memory); // owner (pre-V3 was named admin) of contract // this is expected to be an Admin ACL contract for V3 function owner() external view returns (address); // Admin ACL contract for V3, will be at the address owner() function adminACLContract() external returns (IAdminACLV0); // backwards-compatible (pre-V3) admin - equal to owner() function admin() external view returns (address); /** * Function determining if _sender is allowed to call function with * selector _selector on contract `_contract`. Intended to be used with * peripheral contracts such as minters, as well as internally by the * core contract itself. */ function adminACLAllowed( address _sender, address _contract, bytes4 _selector ) external returns (bool); /// getter function of public variable function startingProjectId() external view returns (uint256); // getter function of public variable function nextProjectId() external view returns (uint256); // getter function of public mapping function tokenIdToProjectId( uint256 tokenId ) external view returns (uint256 projectId); // @dev this is not available in V0 function isMintWhitelisted(address minter) external view returns (bool); function projectIdToArtistAddress( uint256 _projectId ) external view returns (address payable); function projectIdToSecondaryMarketRoyaltyPercentage( uint256 _projectId ) external view returns (uint256); function projectURIInfo( uint256 _projectId ) external view returns (string memory projectBaseURI); // @dev new function in V3 function projectStateData( uint256 _projectId ) external view returns ( uint256 invocations, uint256 maxInvocations, bool active, bool paused, uint256 completedTimestamp, bool locked ); function projectDetails( uint256 _projectId ) external view returns ( string memory projectName, string memory artist, string memory description, string memory website, string memory license ); function projectScriptDetails( uint256 _projectId ) external view returns ( string memory scriptTypeAndVersion, string memory aspectRatio, uint256 scriptCount ); function projectScriptByIndex( uint256 _projectId, uint256 _index ) external view returns (string memory); function tokenIdToHash(uint256 _tokenId) external view returns (bytes32); // function to set a token's hash (must be guarded) function setTokenHash_8PT(uint256 _tokenId, bytes32 _hash) external; // @dev gas-optimized signature in V3 for `mint` function mint_Ecf( address _to, uint256 _projectId, address _by ) external returns (uint256 tokenId); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; import "./IAdminACLV0.sol"; import "./IGenArt721CoreContractV3_Base.sol"; import "./ISplitProviderV0.sol"; /** * @notice Struct representing Engine contract configuration. * @param tokenName Name of token. * @param tokenSymbol Token symbol. * @param renderProviderAddress address to send render provider revenue to * @param randomizerContract Randomizer contract. * @param splitProviderAddress Address to use as royalty splitter provider for the contract. * @param minterFilterAddress Address of the Minter Filter to set as the Minter * on the contract. * @param startingProjectId The initial next project ID. * @param autoApproveArtistSplitProposals Whether or not to always * auto-approve proposed artist split updates. * @param nullPlatformProvider Enforce always setting zero platform provider fees and addresses. * @param allowArtistProjectActivation Allow artist to activate their own projects. * @dev _startingProjectId should be set to a value much, much less than * max(uint248), but an explicit input type of `uint248` is used as it is * safer to cast up to `uint256` than it is to cast down for the purposes * of setting `_nextProjectId`. */ struct EngineConfiguration { string tokenName; string tokenSymbol; address renderProviderAddress; address platformProviderAddress; address newSuperAdminAddress; address randomizerContract; address splitProviderAddress; address minterFilterAddress; uint248 startingProjectId; bool autoApproveArtistSplitProposals; bool nullPlatformProvider; bool allowArtistProjectActivation; } interface IGenArt721CoreContractV3_Engine is IGenArt721CoreContractV3_Base { // @dev new function in V3.2 /** * @notice Initializes the contract with the provided `engineConfiguration`. * This function should be called atomically, immediately after deployment. * Only callable once. Validation on `engineConfiguration` is performed by caller. * @param engineConfiguration EngineConfiguration to configure the contract with. * @param adminACLContract_ Address of admin access control contract, to be * set as contract owner. * @param defaultBaseURIHost Base URI prefix to initialize default base URI with. * @param bytecodeStorageReaderContract_ Address of the bytecode storage reader contract. */ function initialize( EngineConfiguration calldata engineConfiguration, address adminACLContract_, string memory defaultBaseURIHost, address bytecodeStorageReaderContract_ ) external; // @dev new function in V3 function getPrimaryRevenueSplits( uint256 _projectId, uint256 _price ) external view returns ( uint256 renderProviderRevenue_, address payable renderProviderAddress_, uint256 platformProviderRevenue_, address payable platformProviderAddress_, uint256 artistRevenue_, address payable artistAddress_, uint256 additionalPayeePrimaryRevenue_, address payable additionalPayeePrimaryAddress_ ); // @dev The render provider primary sales payment address function renderProviderPrimarySalesAddress() external view returns (address payable); // @dev The platform provider primary sales payment address function platformProviderPrimarySalesAddress() external view returns (address payable); // @dev Percentage of primary sales allocated to the render provider function renderProviderPrimarySalesPercentage() external view returns (uint256); // @dev Percentage of primary sales allocated to the platform provider function platformProviderPrimarySalesPercentage() external view returns (uint256); /** @notice The default render provider payment address for all secondary sales royalty * revenues, for all new projects. Individual project payment info is defined * in each project's ProjectFinance struct. * @return The default render provider payment address for secondary sales royalties. */ function defaultRenderProviderSecondarySalesAddress() external view returns (address payable); /** @notice The default platform provider payment address for all secondary sales royalty * revenues, for all new projects. Individual project payment info is defined * in each project's ProjectFinance struct. * @return The default platform provider payment address for secondary sales royalties. */ function defaultPlatformProviderSecondarySalesAddress() external view returns (address payable); /** @notice The default render provider payment basis points for all secondary sales royalty * revenues, for all new projects. Individual project payment info is defined * in each project's ProjectFinance struct. * @return The default render provider payment basis points for secondary sales royalties. */ function defaultRenderProviderSecondarySalesBPS() external view returns (uint256); /** @notice The default platform provider payment basis points for all secondary sales royalty * revenues, for all new projects. Individual project payment info is defined * in each project's ProjectFinance struct. * @return The default platform provider payment basis points for secondary sales royalties. */ function defaultPlatformProviderSecondarySalesBPS() external view returns (uint256); /** * @notice The address of the current split provider being used by the contract. * @return The address of the current split provider. */ function splitProvider() external view returns (ISplitProviderV0); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; import "./IAdminACLV0.sol"; /** * @title This interface defines a project finance struct that is used in the * GenArt721CoreContractV3 flagship and derivative implementations beginning * with v3.2.0. This struct is intended to house all financial information * related to a project, including royalties, artist splits, and platform * provider splits. * @author Art Blocks Inc. */ interface IGenArt721CoreContractV3_ProjectFinance { /// packed struct containing project financial information struct ProjectFinance { address payable additionalPayeePrimarySales; // packed uint: max of 95, max uint8 = 255 uint8 secondaryMarketRoyaltyPercentage; address payable additionalPayeeSecondarySales; // packed uint: max of 100, max uint8 = 255 uint8 additionalPayeeSecondarySalesPercentage; address payable artistAddress; // packed uint: max of 100, max uint8 = 255 uint8 additionalPayeePrimarySalesPercentage; address platformProviderSecondarySalesAddress; // packed uint: max of 10_000 max uint16 = 65_535 uint16 platformProviderSecondarySalesBPS; address renderProviderSecondarySalesAddress; // packed uint: max of 10_000 max uint16 = 65_535 uint16 renderProviderSecondarySalesBPS; // address to send ERC-2981 royalties to address royaltySplitter; } /** * @notice View function returning project financial details for project * `_projectId`. * @param _projectId Project ID to be queried. * @return ProjectFinance Project financial details. */ function projectIdToFinancials( uint256 _projectId ) external view returns (ProjectFinance memory); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. to support the 0xSplits V2 integration // Sourced from: // - https://github.com/0xSplits/splits-contracts-monorepo/blob/main/packages/splits-v2/src/libraries/SplitV2.sol // - https://github.com/0xSplits/splits-contracts-monorepo/blob/main/packages/splits-v2/src/splitters/SplitFactoryV2.sol pragma solidity ^0.8.0; interface ISplitFactoryV2 { /* -------------------------------------------------------------------------- */ /* STRUCTS */ /* -------------------------------------------------------------------------- */ /** * @notice Split struct * @dev This struct is used to store the split information. * @dev There are no hard caps on the number of recipients/totalAllocation/allocation unit. Thus the chain and its * gas limits will dictate these hard caps. Please double check if the split you are creating can be distributed on * the chain. * @param recipients The recipients of the split. * @param allocations The allocations of the split. * @param totalAllocation The total allocation of the split. * @param distributionIncentive The incentive for distribution. Limits max incentive to 6.5%. */ struct Split { address[] recipients; uint256[] allocations; uint256 totalAllocation; uint16 distributionIncentive; } /* -------------------------------------------------------------------------- */ /* FUNCTIONS */ /* -------------------------------------------------------------------------- */ /** * @notice Create a new split with params and owner. * @param _splitParams Params to create split with. * @param _owner Owner of created split. * @param _creator Creator of created split. * @param _salt Salt for create2. * @return split Address of the created split. */ function createSplitDeterministic( Split calldata _splitParams, address _owner, address _creator, bytes32 _salt ) external returns (address split); /** * @notice Predict the address of a new split and check if it is deployed. * @param _splitParams Params to create split with. * @param _owner Owner of created split. * @param _salt Salt for create2. */ function isDeployed( Split calldata _splitParams, address _owner, bytes32 _salt ) external view returns (address split, bool exists); }
// SPDX-License-Identifier: LGPL-3.0-only // Creatd By: Art Blocks Inc. pragma solidity ^0.8.0; interface IRandomizer_V3CoreBase { /** * @notice This function is intended to be called by a core contract, and * the core contract can be assured that the randomizer will call back to * the calling contract to set the token hash seed for `_tokenId` via * `setTokenHash_8PT`. * @dev This function may revert if hash seed generation is improperly * configured (for example, if in polyptych mode, but no hash seed has been * previously configured). * @dev This function is not specifically gated to any specific caller, but * will only call back to the calling contract, `msg.sender`, to set the * specified token's hash seed. * A third party contract calling this function will not be able to set the * token hash seed on a different core contract. * @param _tokenId The token ID must be assigned a hash. */ function assignTokenHash(uint256 _tokenId) external; }
// SPDX-License-Identifier: LGPL-3.0-only // Creatd By: Art Blocks Inc. pragma solidity ^0.8.0; import {ISplitFactoryV2} from "./integration-refs/splits-0x-v2/ISplitFactoryV2.sol"; interface ISplitProviderV0 { /** * @notice SplitInputs struct defines the inputs for requested splitters. * It is defined in a way easily communicated from the Art Blocks GenArt721V3 contract, * to allow for easy integration and minimal additional bytecode in the GenArt721V3 contract. */ struct SplitInputs { address platformProviderSecondarySalesAddress; uint16 platformProviderSecondarySalesBPS; address renderProviderSecondarySalesAddress; uint16 renderProviderSecondarySalesBPS; uint8 artistTotalRoyaltyPercentage; address artist; address additionalPayee; uint8 additionalPayeePercentage; } /** * @notice Emitted when a new splitter contract is created. * @param splitter address of the splitter contract */ event SplitterCreated(address indexed splitter); /** * @notice Gets or creates an immutable splitter contract at a deterministic address. * Splits in the splitter contract are determined by the input split parameters, * so we can safely create the splitter contract at a deterministic address (or use * the existing splitter contract if it already exists at that address). * @dev Uses the 0xSplits v2 implementation to create a splitter contract * @param splitInputs The split input parameters. * @return splitter The newly created splitter contract address. */ function getOrCreateSplitter( SplitInputs calldata splitInputs ) external returns (address); /** * @notice Indicates the type of the contract, e.g. `SplitProviderV0`. * @return type_ The type of the contract. */ function type_() external pure returns (bytes32); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. import {LibZip} from "solady/src/utils/LibZip.sol"; pragma solidity ^0.8.0; /** * @title Art Blocks Script Storage Library * @notice Utilize contract bytecode as persistent storage for large chunks of script string data. * V2 includes optional on-chain compression/decompression via solady LibZip. * This library is intended to have an external deployed copy that is released in the future, * and, as such, has been designed to support both updated V2 and V1 (versioned, with purging removed) * reads as well as backwards-compatible reads for both a) the unversioned "V0" storage contracts * which were deployed by the original version of this libary and b) contracts that were deployed * using one of the SSTORE2 implementations referenced below. * For these pre-V1 storage contracts (which themselves did not have any explicit versioning semantics) * backwards-compatible reads are optimistic, and only expected to work for contracts actually * deployed by the original version of this library – and may fail ungracefully if attempted to be * used to read from other contracts. * This library is split into two components, intended to be updated in tandem, and thus included * here in the same source file. One component is an internal library that is intended to be embedded * directly into other contracts and provides all _write_ functionality. The other is a public library * that is intended to be deployed as a standalone contract and provides all _read_ functionality. * * @author Art Blocks Inc. * @author Modified from 0xSequence (https://github.com/0xsequence/sstore2/blob/master/contracts/SSTORE2.sol) * @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol) * @author Utilizes LibZip from solady (https://github.com/Vectorized/solady/blob/main/src/utils/LibZip.sol) * * @dev Compared to the above two rerferenced libraries, this contracts-as-storage implementation makes a few * notably different design decisions: * - uses the `string` data type for input/output on reads, rather than speaking in bytes directly, * with an exception for optionally compressed data which are input as bytes * - stores the "writer" address (library user) in the deployed contract bytes, which is useful for * on-chain introspection and provenance purposes * - stores a very simple versioning string in the deployed contract bytes, which captures the version * of the library that was used to deploy the storage contract and useful for supporting future * compatibility management as this library evolves (e.g. in response to EOF v1 migration plans) * - stores a bool indicating if the stored data are compressed. * Also, given that much of this library is written in assembly, this library makes use of a slightly * different convention (when compared to the rest of the Art Blocks smart contract repo) around * pre-defining return values in some cases in order to simplify need to directly memory manage these * return values. */ /** * @title Art Blocks Script Storage Library (Public, Reads) * @author Art Blocks Inc. * @notice The public library for reading from storage contracts. This library is intended to be deployed as a * standalone contract, and provides all _read_ functionality. */ library BytecodeStorageReader { // Define the set of known valid version strings that may be stored in the deployed storage contract bytecode // note: These are all intentionally exactly 32-bytes and are null-terminated. Null-termination is used due // to this being the standard expected formatting in common web3 tooling such as ethers.js. Please see // the following for additional context: https://docs.ethers.org/v5/api/utils/strings/#Bytes32String // Used for storage contracts that were deployed by an unknown source bytes32 public constant UNKNOWN_VERSION_STRING = "UNKNOWN_VERSION_STRING_________ "; // Pre-dates versioning string, so this doesn't actually exist in any deployed contracts, // but is useful for backwards-compatible semantics with original version of this library bytes32 public constant V0_VERSION_STRING = "BytecodeStorage_V0.0.0_________ "; // The first versioned storage contract, deployed by an updated version of this library bytes32 public constant V1_VERSION_STRING = "BytecodeStorage_V1.0.0_________ "; // The first versioned storage contract, deployed by an updated version of this library bytes32 public constant V2_VERSION_STRING = "BytecodeStorage_V2.0.0_________ "; // The current version of this library. bytes32 public constant CURRENT_VERSION = V2_VERSION_STRING; //---------------------------------------------------------------------------------------------------------------// // Starting Index | Size | Ending Index | Description // //---------------------------------------------------------------------------------------------------------------// // 0 | N/A | 0 | // // 0 | 1 | 1 | single byte opcode for making the storage contract non-executable // // 1 | 32 | 33 | the 32 byte slot used for storing a basic versioning string // // 33 | 32 | 65 | the 32 bytes for storing the deploying contract's (0-padded) address // // 65 | 1 | 66 | single byte indicating if the stored data are compressed // //---------------------------------------------------------------------------------------------------------------// // Define the offset for where the "meta bytes" end, and the "data bytes" begin. Note that this is a manually // calculated value, and must be updated if the above table is changed. It is expected that tests will fail // loudly if these values are not updated in-step with eachother. uint256 private constant VERSION_OFFSET = 1; uint256 private constant ADDRESS_OFFSET = 33; uint256 private constant COMPRESSION_OFFSET = 65; uint256 private constant DATA_OFFSET = 66; // Define the set of known *historic* offset values for where the "meta bytes" end, and the "data bytes" begin. // SSTORE2 deployed storage contracts take the general format of: // concat(0x00, data) // note: this is true for both variants of the SSTORE2 library uint256 private constant SSTORE2_DATA_OFFSET = 1; // V0 deployed storage contracts take the general format of: // concat(gated-cleanup-logic, deployer-address, data) uint256 private constant V0_ADDRESS_OFFSET = 72; uint256 private constant V0_DATA_OFFSET = 104; // V1 deployed storage contracts take the general format of: // concat(invalid opcode, version, deployer-address, data) uint256 private constant V1_ADDRESS_OFFSET = 33; uint256 private constant V1_DATA_OFFSET = 65; // V2 deployed storage contracts take the general format of: // concat(invalid opcode, version, deployer-address, compression-bool, data) uint256 private constant V2_ADDRESS_OFFSET = ADDRESS_OFFSET; uint256 private constant V2_DATA_OFFSET = DATA_OFFSET; /*////////////////////////////////////////////////////////////// READ LOGIC //////////////////////////////////////////////////////////////*/ /** * @notice Read a string from contract bytecode * @param _address address of deployed contract with bytecode stored in the V0 or V1 or V2 format * @return data string read from contract bytecode * @dev This function performs input validation that the contract to read is in an expected format */ function readFromBytecode( address _address ) public view returns (string memory data) { ( uint256 dataOffset, bool isCompressed ) = _bytecodeDataOffsetAndIsCompressedAt(_address); if (isCompressed) { return string( LibZip.flzDecompress( readBytesFromBytecode(_address, dataOffset) ) ); } else { return string(readBytesFromBytecode(_address, dataOffset)); } } /** * @notice Read the bytes from contract bytecode that was written to the EVM using SSTORE2 * @param _address address of deployed contract with bytecode stored in the SSTORE2 format * @return data bytes read from contract bytecode * @dev This function performs no input validation on the provided contract, * other than that there is content to read (but not that its a "storage contract") */ function readBytesFromSSTORE2Bytecode( address _address ) public view returns (bytes memory data) { return readBytesFromBytecode(_address, SSTORE2_DATA_OFFSET); } /** * @notice Read the bytes from contract bytecode, with an explicitly provided starting offset * @param _address address of deployed contract with bytecode stored in the V0 or V1 format * @param _offset offset to read from in contract bytecode, explicitly provided (not calculated) * @return data bytes read from contract bytecode * @dev This function performs no input validation on the provided contract, * other than that there is content to read (but not that its a "storage contract") */ function readBytesFromBytecode( address _address, uint256 _offset ) public view returns (bytes memory data) { // get the size of the bytecode uint256 bytecodeSize = _bytecodeSizeAt(_address); // handle case where address contains code < _offset if (bytecodeSize < _offset) { revert("ContractAsStorage: Read Error"); } // handle case where address contains code >= dataOffset // decrement by dataOffset to account for header info uint256 size; unchecked { size = bytecodeSize - _offset; } assembly { // allocate free memory data := mload(0x40) // update free memory pointer // use and(x, not(0x1f) as cheaper equivalent to sub(x, mod(x, 0x20)). // adding 0x1f to size + logic above ensures the free memory pointer // remains word-aligned, following the Solidity convention. mstore(0x40, add(data, and(add(add(size, 0x20), 0x1f), not(0x1f)))) // store length of data in first 32 bytes mstore(data, size) // copy code to memory, excluding the deployer-address extcodecopy(_address, add(data, 0x20), _offset, size) } } /** * @notice Get address for deployer for given contract bytecode * @param _address address of deployed contract with bytecode stored in the V0 or V1 format * @return writerAddress address read from contract bytecode */ function getWriterAddressForBytecode( address _address ) public view returns (address) { // get the size of the data uint256 bytecodeSize = _bytecodeSizeAt(_address); // the dataOffset for the bytecode uint256 addressOffset = _bytecodeAddressOffsetAt(_address); // handle case where address contains code < addressOffset + 32 (address takes a whole slot) if (bytecodeSize < (addressOffset + 32)) { revert("ContractAsStorage: Read Error"); } assembly { // allocate free memory let writerAddress := mload(0x40) // shift free memory pointer by one slot mstore(0x40, add(mload(0x40), 0x20)) // copy the 32-byte address of the data contract writer to memory // note: this relies on the assumption noted at the top-level of // this file that the storage layout for the deployed // contracts-as-storage contract looks like:: // | invalid opcode | version-string (unless v0) | deployer-address (padded) | data | extcodecopy( _address, writerAddress, addressOffset, 0x20 // full 32-bytes, as address is expected to be zero-padded ) return( writerAddress, 0x20 // return size is entire slot, as it is zero-padded ) } } /** * @notice Get version for given contract bytecode * @param _address address of deployed contract with bytecode stored in the V0 or V1 format * @return version version read from contract bytecode */ function getLibraryVersionForBytecode( address _address ) public view returns (bytes32) { return _bytecodeVersionAt(_address); } /** * @notice Get if data are stored in compressed format for given contract bytecode * @param _address address of deployed contract with bytecode stored in the V0, V1, or V2 format * @return isCompressed boolean indicating if the stored data are compressed */ function getIsCompressedForBytecode( address _address ) public view returns (bool) { (, bool isCompressed) = _bytecodeDataOffsetAndIsCompressedAt(_address); return isCompressed; } /** * Utility function to get the compressed form of a message string using solady LibZip's * flz compress algorithm. * The compressed message is returned as bytes, which may be used as the input to * the function `BytecodeStorageWriter.writeToBytecodeCompressed`. * @param _data string to be compressed * @return bytes compressed bytes */ function getCompressed( string memory _data ) public pure returns (bytes memory) { return LibZip.flzCompress(bytes(_data)); } /*////////////////////////////////////////////////////////////// INTERNAL HELPER LOGIC //////////////////////////////////////////////////////////////*/ /** * @notice Returns the size of the bytecode at address `_address` * @param _address address that may or may not contain bytecode * @return size size of the bytecode code at `_address` */ function _bytecodeSizeAt( address _address ) private view returns (uint256 size) { assembly { size := extcodesize(_address) } if (size == 0) { revert("ContractAsStorage: Read Error"); } } /** * @notice Returns the offset of the data in the bytecode at address `_address` * @param _address address that may or may not contain bytecode * @return dataOffset offset of data in bytecode if a known version, otherwise 0 * @return isCompressed bool indicating if the stored data are compressed */ function _bytecodeDataOffsetAndIsCompressedAt( address _address ) private view returns (uint256 dataOffset, bool isCompressed) { bytes32 version = _bytecodeVersionAt(_address); if (version == V2_VERSION_STRING) { dataOffset = V2_DATA_OFFSET; isCompressed = _isCompressedAt(_address, version); } else if (version == V1_VERSION_STRING) { dataOffset = V1_DATA_OFFSET; // isCompressed remains false, as V1 contracts do not support compression } else if (version == V0_VERSION_STRING) { dataOffset = V0_DATA_OFFSET; // isCompressed remains false, as V0 contracts do not support compression } else { // unknown version, revert revert("ContractAsStorage: Unsupported Version"); } } /** * @notice Returns the offset of the address in the bytecode at address `_address` * @param _address address that may or may not contain bytecode * @return addressOffset offset of address in bytecode if a known version, otherwise 0 */ function _bytecodeAddressOffsetAt( address _address ) private view returns (uint256 addressOffset) { bytes32 version = _bytecodeVersionAt(_address); if (version == V2_VERSION_STRING) { addressOffset = V2_ADDRESS_OFFSET; } else if (version == V1_VERSION_STRING) { addressOffset = V1_ADDRESS_OFFSET; } else if (version == V0_VERSION_STRING) { addressOffset = V0_ADDRESS_OFFSET; } else { // unknown version, revert revert("ContractAsStorage: Unsupported Version"); } } /** * @notice Get version string for given contract bytecode * @param _address address of deployed contract with bytecode stored in the V0 or V1 format * @return version version string read from contract bytecode */ function _bytecodeVersionAt( address _address ) private view returns (bytes32 version) { // get the size of the data uint256 bytecodeSize = _bytecodeSizeAt(_address); // handle case where address contains code < minimum expected version string size, // by returning early with the unknown version string if (bytecodeSize < (VERSION_OFFSET + 32)) { return UNKNOWN_VERSION_STRING; } assembly { // allocate free memory let versionString := mload(0x40) // shift free memory pointer by one slot mstore(0x40, add(mload(0x40), 0x20)) // copy the 32-byte version string of the bytecode library to memory // note: this relies on the assumption noted at the top-level of // this file that the storage layout for the deployed // contracts-as-storage contract looks like: // | invalid opcode | version-string (unless v0) | deployer-address (padded) | data | extcodecopy( _address, versionString, VERSION_OFFSET, 0x20 // 32-byte version string ) // note: must check against literal strings, as Yul does not allow for // dynamic strings in switch statements. switch mload(versionString) case "BytecodeStorage_V2.0.0_________ " { version := V2_VERSION_STRING } case "BytecodeStorage_V1.0.0_________ " { version := V1_VERSION_STRING } case 0x2060486000396000513314601057fe5b60013614601957fe5b6000357fff0000 { // the v0 variant of this library pre-dates formal versioning w/ version strings, // so we check the first 32 bytes of the execution bytecode itself which // is static and known across all storage contracts deployed with the first version // of this library. version := V0_VERSION_STRING } default { version := UNKNOWN_VERSION_STRING } } } /** * @notice Get if stored data are compressed for given contract bytecode * @param _address address of deployed contract with bytecode stored * @param _version version string of the bytecode library used to deploy the contract at `_address` * @return isCompressed bool indicating if the stored data are compressed */ function _isCompressedAt( address _address, bytes32 _version ) private view returns (bool isCompressed) { // @dev if branch no coverage - unreachable as used, remains for redundant safety if (_version == V0_VERSION_STRING || _version == V1_VERSION_STRING) { // V0 and V1 and unknown contracts do not support compression return false; } // @dev if branch no coverage - unreachable as used, remains for redundant safety if (_version != V2_VERSION_STRING) { // unsupported version, throw error revert("ContractAsStorage: Unsupported Version"); } // get the size of the data uint256 bytecodeSize = _bytecodeSizeAt(_address); // handle case where address contains code < minimum expected version string size, // by returning early with false if (bytecodeSize < (COMPRESSION_OFFSET + 1)) { return false; } assembly { // allocate free memory let compressedByte := mload(0x40) // shift free memory pointer by one slot mstore(0x40, add(mload(0x40), 0x20)) // zero out word at compressedByte (solidity does not guarantee zeroed memory beyond free memory pointer) mstore(compressedByte, 0x00) // copy the 1-byte compressed flag of the bytecode library to memory // note: this relies on the assumption noted at the top-level of // this file that the storage layout for the deployed // contracts-as-storage contract looks like: // | invalid opcode | version-string (unless v0) | deployer-address (padded) | isCompressed | data | extcodecopy( _address, compressedByte, COMPRESSION_OFFSET, 0x1 // 1-byte version string ) // check if the compressed flag is set switch mload(compressedByte) case 0x00 { isCompressed := false } default { isCompressed := true } } } } /** * @title Art Blocks Script Storage Library (Internal, Writes) * @author Art Blocks Inc. * @notice The internal library for writing to storage contracts. This library is intended to be deployed * within library client contracts that use this library to perform _write_ operations on storage. */ library BytecodeStorageWriter { /*////////////////////////////////////////////////////////////// WRITE LOGIC //////////////////////////////////////////////////////////////*/ /** * @notice Write a string to contract bytecode * @param _data string to be written to contract. No input validation is performed on this parameter. * @return address_ address of deployed contract with bytecode stored in the V2 format */ function writeToBytecode( string memory _data ) internal returns (address address_) { // prefix bytecode with bytes memory creationCode = abi.encodePacked( //---------------------------------------------------------------------------------------------------------------// // Opcode | Opcode + Arguments | Description | Stack View // //---------------------------------------------------------------------------------------------------------------// // a.) creation code returns all code in the contract except for the first 11 (0B in hex) bytes, as these 11 // bytes are the creation code itself which we do not want to store in the deployed storage contract result //---------------------------------------------------------------------------------------------------------------// // 0x60 | 0x60_0B | PUSH1 11 | codeOffset // // 0x59 | 0x59 | MSIZE | 0 codeOffset // // 0x81 | 0x81 | DUP2 | codeOffset 0 codeOffset // // 0x38 | 0x38 | CODESIZE | codeSize codeOffset 0 codeOffset // // 0x03 | 0x03 | SUB | (codeSize - codeOffset) 0 codeOffset // // 0x80 | 0x80 | DUP | (codeSize - codeOffset) (codeSize - codeOffset) 0 codeOffset // // 0x92 | 0x92 | SWAP3 | codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) // // 0x59 | 0x59 | MSIZE | 0 codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) // // 0x39 | 0x39 | CODECOPY | 0 (codeSize - codeOffset) // // 0xF3 | 0xF3 | RETURN | // //---------------------------------------------------------------------------------------------------------------// // (11 bytes) hex"60_0B_59_81_38_03_80_92_59_39_F3", //---------------------------------------------------------------------------------------------------------------// // b.) ensure that the deployed storage contract is non-executeable (first opcode is the `invalid` opcode) //---------------------------------------------------------------------------------------------------------------// //---------------------------------------------------------------------------------------------------------------// // 0xFE | 0xFE | INVALID | // //---------------------------------------------------------------------------------------------------------------// // (1 byte) hex"FE", //---------------------------------------------------------------------------------------------------------------// // c.) store the version string, which is already represented as a 32-byte value //---------------------------------------------------------------------------------------------------------------// // (32 bytes) BytecodeStorageReader.CURRENT_VERSION, //---------------------------------------------------------------------------------------------------------------// // d.) store the deploying-contract's address with 0-padding to fit a 20-byte address into a 32-byte slot //---------------------------------------------------------------------------------------------------------------// // (12 bytes) hex"00_00_00_00_00_00_00_00_00_00_00_00", // (20 bytes) address(this), //---------------------------------------------------------------------------------------------------------------// // e.) store the bool indicating if the data is compressed. true for this function. //---------------------------------------------------------------------------------------------------------------// // (1 byte) hex"00", // uploaded data (stored as bytecode) comes last _data ); assembly { // deploy a new contract with the generated creation code. // start 32 bytes into creationCode to avoid copying the byte length. address_ := create(0, add(creationCode, 0x20), mload(creationCode)) } // address must be non-zero if contract was deployed successfully require(address_ != address(0), "ContractAsStorage: Write Error"); } /** * @notice Write a string to contract bytecode, input as compressed bytes from solady LibZip * @param _dataCompressed compressed bytes to be written to contract. No input validation is performed on this parameter. * @return address_ address of deployed contract with bytecode stored in the V2 format */ function writeToBytecodeCompressed( bytes memory _dataCompressed ) internal returns (address address_) { // prefix bytecode with bytes memory creationCode = abi.encodePacked( //---------------------------------------------------------------------------------------------------------------// // Opcode | Opcode + Arguments | Description | Stack View // //---------------------------------------------------------------------------------------------------------------// // a.) creation code returns all code in the contract except for the first 11 (0B in hex) bytes, as these 11 // bytes are the creation code itself which we do not want to store in the deployed storage contract result //---------------------------------------------------------------------------------------------------------------// // 0x60 | 0x60_0B | PUSH1 11 | codeOffset // // 0x59 | 0x59 | MSIZE | 0 codeOffset // // 0x81 | 0x81 | DUP2 | codeOffset 0 codeOffset // // 0x38 | 0x38 | CODESIZE | codeSize codeOffset 0 codeOffset // // 0x03 | 0x03 | SUB | (codeSize - codeOffset) 0 codeOffset // // 0x80 | 0x80 | DUP | (codeSize - codeOffset) (codeSize - codeOffset) 0 codeOffset // // 0x92 | 0x92 | SWAP3 | codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) // // 0x59 | 0x59 | MSIZE | 0 codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) // // 0x39 | 0x39 | CODECOPY | 0 (codeSize - codeOffset) // // 0xF3 | 0xF3 | RETURN | // //---------------------------------------------------------------------------------------------------------------// // (11 bytes) hex"60_0B_59_81_38_03_80_92_59_39_F3", //---------------------------------------------------------------------------------------------------------------// // b.) ensure that the deployed storage contract is non-executeable (first opcode is the `invalid` opcode) //---------------------------------------------------------------------------------------------------------------// //---------------------------------------------------------------------------------------------------------------// // 0xFE | 0xFE | INVALID | // //---------------------------------------------------------------------------------------------------------------// // (1 byte) hex"FE", //---------------------------------------------------------------------------------------------------------------// // c.) store the version string, which is already represented as a 32-byte value //---------------------------------------------------------------------------------------------------------------// // (32 bytes) BytecodeStorageReader.CURRENT_VERSION, //---------------------------------------------------------------------------------------------------------------// // d.) store the deploying-contract's address with 0-padding to fit a 20-byte address into a 32-byte slot //---------------------------------------------------------------------------------------------------------------// // (12 bytes) hex"00_00_00_00_00_00_00_00_00_00_00_00", // (20 bytes) address(this), //---------------------------------------------------------------------------------------------------------------// // e.) store the bool indicating if the data is compressed. true for this function. //---------------------------------------------------------------------------------------------------------------// // (1 byte) hex"01", // uploaded compressed data (stored as bytecode) comes last _dataCompressed ); assembly { // deploy a new contract with the generated creation code. // start 32 bytes into creationCode to avoid copying the byte length. address_ := create(0, add(creationCode, 0x20), mload(creationCode)) } // address must be non-zero if contract was deployed successfully require(address_ != address(0), "ContractAsStorage: Write Error"); } }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. // Inspired by: https://ethereum.stackexchange.com/a/123950/103422 pragma solidity ^0.8.0; /** * @dev Operations on bytes32 data type, dealing with conversion to string. */ library Bytes32Strings { /** * @notice Intended to convert a `bytes32`-encoded string literal to `string`. * Trims zero padding to arrive at original string literal. */ function toString( bytes32 source ) internal pure returns (string memory result) { uint8 length; while (source[length] != 0 && length < 32) { length++; } assembly { // free memory pointer result := mload(0x40) // update free memory pointer to new "memory end" // (offset is 64-bytes: 32 for length, 32 for data) mstore(0x40, add(result, 0x40)) // store length in first 32-byte memory slot mstore(result, length) // write actual data in second 32-byte memory slot mstore(add(result, 0x20), source) } } /** * @notice Intended to check if a `bytes32`-encoded string contains a given * character with UTF-8 character code `utf8CharCode exactly `targetQty` * times. Does not support searching for multi-byte characters, only * characters with UTF-8 character codes < 0x80. */ function containsExactCharacterQty( bytes32 source, uint8 utf8CharCode, uint8 targetQty ) internal pure returns (bool) { uint8 _occurrences; uint8 i; for (i; i < 32; ) { uint8 _charCode = uint8(source[i]); // if not a null byte, or a multi-byte UTF-8 character, check match if (_charCode != 0 && _charCode < 0x80) { if (_charCode == utf8CharCode) { unchecked { // no risk of overflow since max 32 iterations < max uin8=255 ++_occurrences; } } } unchecked { // no risk of overflow since max 32 iterations < max uin8=255 ++i; } } return _occurrences == targetQty; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol) pragma solidity ^0.8.20; import {IERC721} from "@openzeppelin-5.0/contracts/token/ERC721/IERC721.sol"; import {IERC721Receiver} from "@openzeppelin-5.0/contracts/token/ERC721/IERC721Receiver.sol"; import {IERC721Metadata} from "@openzeppelin-5.0/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import {Context} from "@openzeppelin-5.0/contracts/utils/Context.sol"; import {Strings} from "@openzeppelin-5.0/contracts/utils/Strings.sol"; import {IERC165, ERC165} from "@openzeppelin-5.0/contracts/utils/introspection/ERC165.sol"; import {IERC721Errors} from "@openzeppelin-5.0/contracts/interfaces/draft-IERC6093.sol"; /** * @dev Forked version of the OpenZeppelin v5.0.1 ERC721 contract. Updated * with an initialize function to ensure EIP 1167 compatibility. Utilizes * a struct to pack owner and hash seed into a single storage slot. * --------------------- * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ abstract contract ERC721_PackedHashSeedV1 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors { using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; /// ensure initialization can only be performed once bool private _initialized; /// struct to pack a token owner and hash seed into same storage slot struct OwnerAndHashSeed { // 20 bytes for address of token's owner address owner; // remaining 12 bytes allocated to token hash seed bytes12 hashSeed; } /// mapping of token ID to OwnerAndHashSeed /// @dev visibility internal so inheriting contracts can access mapping(uint256 tokenId => OwnerAndHashSeed) internal _ownersAndHashSeeds; mapping(address owner => uint256) private _balances; mapping(uint256 tokenId => address) private _tokenApprovals; mapping(address owner => mapping(address operator => bool)) private _operatorApprovals; // @dev constructor intentionally removed to allow for EIP 1167 compatibility, // see `initialize` function for contract initialization /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface( bytes4 interfaceId ) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual returns (uint256) { if (owner == address(0)) { revert ERC721InvalidOwner(address(0)); } return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual returns (address) { return _requireOwned(tokenId); } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI( uint256 tokenId ) public view virtual returns (string memory) { _requireOwned(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual { _approve(to, tokenId, _msgSender()); } /** * @dev See {IERC721-getApproved}. */ function getApproved( uint256 tokenId ) public view virtual returns (address) { _requireOwned(tokenId); return _getApproved(tokenId); } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll( address owner, address operator ) public view virtual returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom( address from, address to, uint256 tokenId ) public virtual { if (to == address(0)) { revert ERC721InvalidReceiver(address(0)); } // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. address previousOwner = _update(to, tokenId, _msgSender()); if (previousOwner != from) { revert ERC721IncorrectOwner(from, tokenId, previousOwner); } } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory data ) public virtual { transferFrom(from, to, tokenId); _checkOnERC721Received(from, to, tokenId, data); } /** * @notice Initializes the contract by setting a `name` and a `symbol` to the token collection. * This function should be called atomically, immediately after deployment. * Only callable once. * @param name_ Name for the token collection. * @param symbol_ Symbol for the token collection. */ function initialize(string memory name_, string memory symbol_) internal { require(!_initialized, "Already initialized"); _name = name_; _symbol = symbol_; _initialized = true; } /** * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist * * IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the * core ERC721 logic MUST be matched with the use of {_increaseBalance} to keep balances * consistent with ownership. The invariant to preserve is that for any address `a` the value returned by * `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`. */ function _ownerOf(uint256 tokenId) internal view virtual returns (address) { return _ownersAndHashSeeds[tokenId].owner; } /** * @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted. */ function _getApproved( uint256 tokenId ) internal view virtual returns (address) { return _tokenApprovals[tokenId]; } /** * @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in * particular (ignoring whether it is owned by `owner`). * * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this * assumption. */ function _isAuthorized( address owner, address spender, uint256 tokenId ) internal view virtual returns (bool) { return spender != address(0) && (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender); } /** * @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. * Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets * the `spender` for the specific `tokenId`. * * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this * assumption. */ function _checkAuthorized( address owner, address spender, uint256 tokenId ) internal view virtual { if (!_isAuthorized(owner, spender, tokenId)) { if (owner == address(0)) { revert ERC721NonexistentToken(tokenId); } else { revert ERC721InsufficientApproval(spender, tokenId); } } } /** * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override. * * NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that * a uint256 would ever overflow from increments when these increments are bounded to uint128 values. * * WARNING: Increasing an account's balance using this function tends to be paired with an override of the * {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership * remain consistent with one another. */ function _increaseBalance(address account, uint128 value) internal virtual { unchecked { _balances[account] += value; } } /** * @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. * * The `auth` argument is optional. If the value passed is non 0, then this function will check that * `auth` is either the owner of the token, or approved to operate on the token (by the owner). * * Emits a {Transfer} event. * * NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}. */ function _update( address to, uint256 tokenId, address auth ) internal virtual returns (address) { address from = _ownerOf(tokenId); // Perform (optional) operator check if (auth != address(0)) { _checkAuthorized(from, auth, tokenId); } // Execute the update if (from != address(0)) { // Clear approval. No need to re-authorize or emit the Approval event _approve(address(0), tokenId, address(0), false); unchecked { _balances[from] -= 1; } } if (to != address(0)) { unchecked { _balances[to] += 1; } } _ownersAndHashSeeds[tokenId].owner = to; emit Transfer(from, to, tokenId); return from; } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal { if (to == address(0)) { revert ERC721InvalidReceiver(address(0)); } address previousOwner = _update(to, tokenId, address(0)); if (previousOwner != address(0)) { revert ERC721InvalidSender(address(0)); } } /** * @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint( address to, uint256 tokenId, bytes memory data ) internal virtual { _mint(to, tokenId); _checkOnERC721Received(address(0), to, tokenId, data); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * This is an internal function that does not check if the sender is authorized to operate on the token. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal { address previousOwner = _update(address(0), tokenId, address(0)); if (previousOwner == address(0)) { revert ERC721NonexistentToken(tokenId); } } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer(address from, address to, uint256 tokenId) internal { if (to == address(0)) { revert ERC721InvalidReceiver(address(0)); } address previousOwner = _update(to, tokenId, address(0)); if (previousOwner == address(0)) { revert ERC721NonexistentToken(tokenId); } else if (previousOwner != from) { revert ERC721IncorrectOwner(from, tokenId, previousOwner); } } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients * are aware of the ERC721 standard to prevent tokens from being forever locked. * * `data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is like {safeTransferFrom} in the sense that it invokes * {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `tokenId` token must exist and be owned by `from`. * - `to` cannot be the zero address. * - `from` cannot be the zero address. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer(address from, address to, uint256 tokenId) internal { _safeTransfer(from, to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeTransfer( address from, address to, uint256 tokenId, bytes memory data ) internal virtual { _transfer(from, to, tokenId); _checkOnERC721Received(from, to, tokenId, data); } /** * @dev Approve `to` to operate on `tokenId` * * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is * either the owner of the token, or approved to operate on all tokens held by this owner. * * Emits an {Approval} event. * * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. */ function _approve(address to, uint256 tokenId, address auth) internal { _approve(to, tokenId, auth, true); } /** * @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not * emitted in the context of transfers. */ function _approve( address to, uint256 tokenId, address auth, bool emitEvent ) internal virtual { // Avoid reading the owner unless necessary if (emitEvent || auth != address(0)) { address owner = _requireOwned(tokenId); // We do not use _isAuthorized because single-token approvals should not be able to call approve if ( auth != address(0) && owner != auth && !isApprovedForAll(owner, auth) ) { revert ERC721InvalidApprover(auth); } if (emitEvent) { emit Approval(owner, to, tokenId); } } _tokenApprovals[tokenId] = to; } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Requirements: * - operator can't be the address zero. * * Emits an {ApprovalForAll} event. */ function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { if (operator == address(0)) { revert ERC721InvalidOperator(operator); } _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). * Returns the owner. * * Overrides to ownership logic should be done to {_ownerOf}. */ function _requireOwned(uint256 tokenId) internal view returns (address) { address owner = _ownerOf(tokenId); if (owner == address(0)) { revert ERC721NonexistentToken(tokenId); } return owner; } /** * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the * recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param data bytes optional data to send along with the call */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory data ) private { if (to.code.length > 0) { try IERC721Receiver(to).onERC721Received( _msgSender(), from, tokenId, data ) returns (bytes4 retval) { if (retval != IERC721Receiver.onERC721Received.selector) { revert ERC721InvalidReceiver(to); } } catch (bytes memory reason) { if (reason.length == 0) { revert ERC721InvalidReceiver(to); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for compressing and decompressing bytes. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibZip.sol) /// @author Calldata compression by clabby (https://github.com/clabby/op-kompressor) /// @author FastLZ by ariya (https://github.com/ariya/FastLZ) /// /// @dev Note: /// The accompanying solady.js library includes implementations of /// FastLZ and calldata operations for convenience. library LibZip { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* FAST LZ OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // LZ77 implementation based on FastLZ. // Equivalent to level 1 compression and decompression at the following commit: // https://github.com/ariya/FastLZ/commit/344eb4025f9ae866ebf7a2ec48850f7113a97a42 // Decompression is backwards compatible. /// @dev Returns the compressed `data`. function flzCompress(bytes memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { function ms8(d_, v_) -> _d { mstore8(d_, v_) _d := add(d_, 1) } function u24(p_) -> _u { _u := mload(p_) _u := or(shl(16, byte(2, _u)), or(shl(8, byte(1, _u)), byte(0, _u))) } function cmp(p_, q_, e_) -> _l { for { e_ := sub(e_, q_) } lt(_l, e_) { _l := add(_l, 1) } { e_ := mul(iszero(byte(0, xor(mload(add(p_, _l)), mload(add(q_, _l))))), e_) } } function literals(runs_, src_, dest_) -> _o { for { _o := dest_ } iszero(lt(runs_, 0x20)) { runs_ := sub(runs_, 0x20) } { mstore(ms8(_o, 31), mload(src_)) _o := add(_o, 0x21) src_ := add(src_, 0x20) } if iszero(runs_) { leave } mstore(ms8(_o, sub(runs_, 1)), mload(src_)) _o := add(1, add(_o, runs_)) } function mt(l_, d_, o_) -> _o { for { d_ := sub(d_, 1) } iszero(lt(l_, 263)) { l_ := sub(l_, 262) } { o_ := ms8(ms8(ms8(o_, add(224, shr(8, d_))), 253), and(0xff, d_)) } if iszero(lt(l_, 7)) { _o := ms8(ms8(ms8(o_, add(224, shr(8, d_))), sub(l_, 7)), and(0xff, d_)) leave } _o := ms8(ms8(o_, add(shl(5, l_), shr(8, d_))), and(0xff, d_)) } function setHash(i_, v_) { let p_ := add(mload(0x40), shl(2, i_)) mstore(p_, xor(mload(p_), shl(224, xor(shr(224, mload(p_)), v_)))) } function getHash(i_) -> _h { _h := shr(224, mload(add(mload(0x40), shl(2, i_)))) } function hash(v_) -> _r { _r := and(shr(19, mul(2654435769, v_)), 0x1fff) } function setNextHash(ip_, ipStart_) -> _ip { setHash(hash(u24(ip_)), sub(ip_, ipStart_)) _ip := add(ip_, 1) } result := mload(0x40) codecopy(result, codesize(), 0x8000) // Zeroize the hashmap. let op := add(result, 0x8000) let a := add(data, 0x20) let ipStart := a let ipLimit := sub(add(ipStart, mload(data)), 13) for { let ip := add(2, a) } lt(ip, ipLimit) {} { let r := 0 let d := 0 for {} 1 {} { let s := u24(ip) let h := hash(s) r := add(ipStart, getHash(h)) setHash(h, sub(ip, ipStart)) d := sub(ip, r) if iszero(lt(ip, ipLimit)) { break } ip := add(ip, 1) if iszero(gt(d, 0x1fff)) { if eq(s, u24(r)) { break } } } if iszero(lt(ip, ipLimit)) { break } ip := sub(ip, 1) if gt(ip, a) { op := literals(sub(ip, a), a, op) } let l := cmp(add(r, 3), add(ip, 3), add(ipLimit, 9)) op := mt(l, d, op) ip := setNextHash(setNextHash(add(ip, l), ipStart), ipStart) a := ip } // Copy the result to compact the memory, overwriting the hashmap. let end := sub(literals(sub(add(ipStart, mload(data)), a), a, op), 0x7fe0) let o := add(result, 0x20) mstore(result, sub(end, o)) // Store the length. for {} iszero(gt(o, end)) { o := add(o, 0x20) } { mstore(o, mload(add(o, 0x7fe0))) } mstore(end, 0) // Zeroize the slot after the string. mstore(0x40, add(end, 0x20)) // Allocate the memory. } } /// @dev Returns the decompressed `data`. function flzDecompress(bytes memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let op := add(result, 0x20) let end := add(add(data, 0x20), mload(data)) for { data := add(data, 0x20) } lt(data, end) {} { let w := mload(data) let c := byte(0, w) let t := shr(5, c) if iszero(t) { mstore(op, mload(add(data, 1))) data := add(data, add(2, c)) op := add(op, add(1, c)) continue } for { let g := eq(t, 7) let l := add(2, xor(t, mul(g, xor(t, add(7, byte(1, w)))))) // M let s := add(add(shl(8, and(0x1f, c)), byte(add(1, g), w)), 1) // R let r := sub(op, s) let f := xor(s, mul(gt(s, 0x20), xor(s, 0x20))) let j := 0 } 1 {} { mstore(add(op, j), mload(add(r, j))) j := add(j, f) if lt(j, l) { continue } data := add(data, add(2, g)) op := add(op, l) break } } mstore(result, sub(op, add(result, 0x20))) // Store the length. mstore(op, 0) // Zeroize the slot after the string. mstore(0x40, add(op, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CALLDATA OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Calldata compression and decompression using selective run length encoding: // - Sequences of 0x00 (up to 128 consecutive). // - Sequences of 0xff (up to 32 consecutive). // // A run length encoded block consists of two bytes: // (0) 0x00 // (1) A control byte with the following bit layout: // - [7] `0: 0x00, 1: 0xff`. // - [0..6] `runLength - 1`. // // The first 4 bytes are bitwise negated so that the compressed calldata // can be dispatched into the `fallback` and `receive` functions. /// @dev Returns the compressed `data`. function cdCompress(bytes memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { function rle(v_, o_, d_) -> _o, _d { mstore(o_, shl(240, or(and(0xff, add(d_, 0xff)), and(0x80, v_)))) _o := add(o_, 2) } result := mload(0x40) let o := add(result, 0x20) let z := 0 // Number of consecutive 0x00. let y := 0 // Number of consecutive 0xff. for { let end := add(data, mload(data)) } iszero(eq(data, end)) {} { data := add(data, 1) let c := byte(31, mload(data)) if iszero(c) { if y { o, y := rle(0xff, o, y) } z := add(z, 1) if eq(z, 0x80) { o, z := rle(0x00, o, 0x80) } continue } if eq(c, 0xff) { if z { o, z := rle(0x00, o, z) } y := add(y, 1) if eq(y, 0x20) { o, y := rle(0xff, o, 0x20) } continue } if y { o, y := rle(0xff, o, y) } if z { o, z := rle(0x00, o, z) } mstore8(o, c) o := add(o, 1) } if y { o, y := rle(0xff, o, y) } if z { o, z := rle(0x00, o, z) } // Bitwise negate the first 4 bytes. mstore(add(result, 4), not(mload(add(result, 4)))) mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /// @dev Returns the decompressed `data`. function cdDecompress(bytes memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { if mload(data) { result := mload(0x40) let o := add(result, 0x20) let s := add(data, 4) let v := mload(s) let end := add(data, mload(data)) mstore(s, not(v)) // Bitwise negate the first 4 bytes. for {} lt(data, end) {} { data := add(data, 1) let c := byte(31, mload(data)) if iszero(c) { data := add(data, 1) let d := byte(31, mload(data)) // Fill with either 0xff or 0x00. mstore(o, not(0)) if iszero(gt(d, 0x7f)) { codecopy(o, codesize(), add(d, 1)) } o := add(o, add(and(d, 0x7f), 1)) continue } mstore8(o, c) o := add(o, 1) } mstore(s, v) // Restore the first 4 bytes. mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } } /// @dev To be called in the `fallback` function. /// ``` /// fallback() external payable { LibZip.cdFallback(); } /// receive() external payable {} // Silence compiler warning to add a `receive` function. /// ``` /// For efficiency, this function will directly return the results, terminating the context. /// If called internally, it must be called at the end of the function. function cdFallback() internal { assembly { if iszero(calldatasize()) { return(calldatasize(), calldatasize()) } let o := 0 let f := not(3) // For negating the first 4 bytes. for { let i := 0 } lt(i, calldatasize()) {} { let c := byte(0, xor(add(i, f), calldataload(i))) i := add(i, 1) if iszero(c) { let d := byte(0, xor(add(i, f), calldataload(i))) i := add(i, 1) // Fill with either 0xff or 0x00. mstore(o, not(0)) if iszero(gt(d, 0x7f)) { codecopy(o, codesize(), add(d, 1)) } o := add(o, add(and(d, 0x7f), 1)) continue } mstore8(o, c) o := add(o, 1) } let success := delegatecall(gas(), address(), 0x00, o, codesize(), 0x00) returndatacopy(0x00, 0x00, returndatasize()) if iszero(success) { revert(0x00, returndatasize()) } return(0x00, returndatasize()) } } }
{ "optimizer": { "enabled": true, "runs": 10 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": { "contracts/libs/v0.8.x/BytecodeStorageV2.sol": { "BytecodeStorageReader": "0x000000000016a5a5ff2fa7799c4bee89ba59b74e" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"inputs":[{"internalType":"enum IGenArt721CoreContractV3_Base.ErrorCodes","name":"_errorCode","type":"uint8"}],"name":"GenArt721Error","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"length","type":"uint256"}],"name":"StringsInsufficientHexLength","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"AcceptedArtistAddressesAndSplits","type":"event"},{"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":true,"internalType":"address","name":"_to","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_currentMinter","type":"address"}],"name":"MinterUpdated","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":"bytes32","name":"_field","type":"bytes32"}],"name":"PlatformUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"royaltySplitter","type":"address"}],"name":"ProjectRoyaltySplitterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"_update","type":"bytes32"}],"name":"ProjectUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":false,"internalType":"address","name":"_artistAddress","type":"address"},{"indexed":false,"internalType":"address","name":"_additionalPayeePrimarySales","type":"address"},{"indexed":false,"internalType":"uint256","name":"_additionalPayeePrimarySalesPercentage","type":"uint256"},{"indexed":false,"internalType":"address","name":"_additionalPayeeSecondarySales","type":"address"},{"indexed":false,"internalType":"uint256","name":"_additionalPayeeSecondarySalesPercentage","type":"uint256"}],"name":"ProposedArtistAddressesAndSplits","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"},{"inputs":[{"internalType":"string","name":"_projectName","type":"string"},{"internalType":"address payable","name":"_artistAddress","type":"address"}],"name":"addProject","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"string","name":"_script","type":"string"}],"name":"addProjectScript","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"bytes","name":"_compressedScript","type":"bytes"}],"name":"addProjectScriptCompressed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_contract","type":"address"},{"internalType":"bytes4","name":"_selector","type":"bytes4"}],"name":"adminACLAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"adminACLContract","outputs":[{"internalType":"contract IAdminACLV0","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"address payable","name":"_artistAddress","type":"address"},{"internalType":"address payable","name":"_additionalPayeePrimarySales","type":"address"},{"internalType":"uint256","name":"_additionalPayeePrimarySalesPercentage","type":"uint256"},{"internalType":"address payable","name":"_additionalPayeeSecondarySales","type":"address"},{"internalType":"uint256","name":"_additionalPayeeSecondarySalesPercentage","type":"uint256"}],"name":"adminAcceptArtistAddressesAndSplits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"allowArtistProjectActivation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"artblocksDependencyRegistryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"artblocksOnChainGeneratorAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"autoApproveArtistSplitProposals","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":[],"name":"bytecodeStorageReaderContract","outputs":[{"internalType":"contract IBytecodeStorageReader_Base","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"coreType","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"coreVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"defaultBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultPlatformProviderSecondarySalesAddress","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultPlatformProviderSecondarySalesBPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultRenderProviderSecondarySalesAddress","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultRenderProviderSecondarySalesBPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forbidNewProjects","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_script","type":"string"}],"name":"getCompressed","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getHistoricalRandomizerAt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"getPrimaryRevenueSplits","outputs":[{"internalType":"uint256","name":"renderProviderRevenue_","type":"uint256"},{"internalType":"address payable","name":"renderProviderAddress_","type":"address"},{"internalType":"uint256","name":"platformProviderRevenue_","type":"uint256"},{"internalType":"address payable","name":"platformProviderAddress_","type":"address"},{"internalType":"uint256","name":"artistRevenue_","type":"uint256"},{"internalType":"address payable","name":"artistAddress_","type":"address"},{"internalType":"uint256","name":"additionalPayeePrimaryRevenue_","type":"uint256"},{"internalType":"address payable","name":"additionalPayeePrimaryAddress_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"address","name":"renderProviderAddress","type":"address"},{"internalType":"address","name":"platformProviderAddress","type":"address"},{"internalType":"address","name":"newSuperAdminAddress","type":"address"},{"internalType":"address","name":"randomizerContract","type":"address"},{"internalType":"address","name":"splitProviderAddress","type":"address"},{"internalType":"address","name":"minterFilterAddress","type":"address"},{"internalType":"uint248","name":"startingProjectId","type":"uint248"},{"internalType":"bool","name":"autoApproveArtistSplitProposals","type":"bool"},{"internalType":"bool","name":"nullPlatformProvider","type":"bool"},{"internalType":"bool","name":"allowArtistProjectActivation","type":"bool"}],"internalType":"struct EngineConfiguration","name":"engineConfiguration","type":"tuple"},{"internalType":"address","name":"adminACLContract_","type":"address"},{"internalType":"string","name":"defaultBaseURIHost","type":"string"},{"internalType":"address","name":"bytecodeStorageReaderContract_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_minter","type":"address"}],"name":"isMintWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"address","name":"_by","type":"address"}],"name":"mint_Ecf","outputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minterContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newProjectsForbidden","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextCoreContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextProjectId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nullPlatformProvider","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numHistoricalRandomizers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[],"name":"platformProviderPrimarySalesAddress","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformProviderPrimarySalesPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"projectDetails","outputs":[{"internalType":"string","name":"projectName","type":"string"},{"internalType":"string","name":"artist","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"website","type":"string"},{"internalType":"string","name":"license","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"projectIdToArtistAddress","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"projectIdToFinancials","outputs":[{"components":[{"internalType":"address payable","name":"additionalPayeePrimarySales","type":"address"},{"internalType":"uint8","name":"secondaryMarketRoyaltyPercentage","type":"uint8"},{"internalType":"address payable","name":"additionalPayeeSecondarySales","type":"address"},{"internalType":"uint8","name":"additionalPayeeSecondarySalesPercentage","type":"uint8"},{"internalType":"address payable","name":"artistAddress","type":"address"},{"internalType":"uint8","name":"additionalPayeePrimarySalesPercentage","type":"uint8"},{"internalType":"address","name":"platformProviderSecondarySalesAddress","type":"address"},{"internalType":"uint16","name":"platformProviderSecondarySalesBPS","type":"uint16"},{"internalType":"address","name":"renderProviderSecondarySalesAddress","type":"address"},{"internalType":"uint16","name":"renderProviderSecondarySalesBPS","type":"uint16"},{"internalType":"address","name":"royaltySplitter","type":"address"}],"internalType":"struct IGenArt721CoreContractV3_ProjectFinance.ProjectFinance","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"projectIdToSecondaryMarketRoyaltyPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"projectScriptByIndex","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"projectScriptBytecodeAddressByIndex","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"projectScriptDetails","outputs":[{"internalType":"string","name":"scriptTypeAndVersion","type":"string"},{"internalType":"string","name":"aspectRatio","type":"string"},{"internalType":"uint256","name":"scriptCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"projectStateData","outputs":[{"internalType":"uint256","name":"invocations","type":"uint256"},{"internalType":"uint256","name":"maxInvocations","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"uint256","name":"completedTimestamp","type":"uint256"},{"internalType":"bool","name":"locked","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"projectURIInfo","outputs":[{"internalType":"string","name":"projectBaseURI","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"address payable","name":"_artistAddress","type":"address"},{"internalType":"address payable","name":"_additionalPayeePrimarySales","type":"address"},{"internalType":"uint256","name":"_additionalPayeePrimarySalesPercentage","type":"uint256"},{"internalType":"address payable","name":"_additionalPayeeSecondarySales","type":"address"},{"internalType":"uint256","name":"_additionalPayeeSecondarySalesPercentage","type":"uint256"}],"name":"proposeArtistPaymentAddressesAndSplits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"proposedArtistAddressesAndSplitsHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"randomizerContract","outputs":[{"internalType":"contract IRandomizer_V3CoreBase","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"removeProjectLastScript","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renderProviderPrimarySalesAddress","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renderProviderPrimarySalesPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","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":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes32","name":"_hashSeed","type":"bytes32"}],"name":"setTokenHash_8PT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"splitProvider","outputs":[{"internalType":"contract ISplitProviderV0","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startingProjectId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"_projectId","type":"uint256"}],"name":"syncProviderSecondaryForProjectToDefaults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"toggleProjectIsActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"toggleProjectIsPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenIdToHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenIdToHashSeed","outputs":[{"internalType":"bytes12","name":"","type":"bytes12"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenIdToProjectId","outputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"address","name":"_artblocksDependencyRegistryAddress","type":"address"}],"name":"updateArtblocksDependencyRegistryAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_artblocksOnChainGeneratorAddress","type":"address"}],"name":"updateArtblocksOnChainGeneratorAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bytecodeStorageReaderContract","type":"address"}],"name":"updateBytecodeStorageReaderContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_defaultBaseURI","type":"string"}],"name":"updateDefaultBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"updateMinterContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nextCoreContract","type":"address"}],"name":"updateNextCoreContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"address payable","name":"_artistAddress","type":"address"}],"name":"updateProjectArtistAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"string","name":"_projectArtistName","type":"string"}],"name":"updateProjectArtistName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"string","name":"_aspectRatio","type":"string"}],"name":"updateProjectAspectRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"string","name":"_newBaseURI","type":"string"}],"name":"updateProjectBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"string","name":"_projectDescription","type":"string"}],"name":"updateProjectDescription","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"string","name":"_projectLicense","type":"string"}],"name":"updateProjectLicense","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"uint24","name":"_maxInvocations","type":"uint24"}],"name":"updateProjectMaxInvocations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"string","name":"_projectName","type":"string"}],"name":"updateProjectName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"uint256","name":"_scriptId","type":"uint256"},{"internalType":"string","name":"_script","type":"string"}],"name":"updateProjectScript","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"uint256","name":"_scriptId","type":"uint256"},{"internalType":"bytes","name":"_compressedScript","type":"bytes"}],"name":"updateProjectScriptCompressed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"bytes32","name":"_scriptTypeAndVersion","type":"bytes32"}],"name":"updateProjectScriptType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"uint256","name":"_secondaryMarketRoyalty","type":"uint256"}],"name":"updateProjectSecondaryMarketRoyaltyPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"string","name":"_projectWebsite","type":"string"}],"name":"updateProjectWebsite","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_defaultRenderProviderSecondarySalesBPS","type":"uint256"},{"internalType":"uint256","name":"_defaultPlatformProviderSecondarySalesBPS","type":"uint256"}],"name":"updateProviderDefaultSecondarySalesBPS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"renderProviderPrimarySalesPercentage_","type":"uint256"},{"internalType":"uint256","name":"platformProviderPrimarySalesPercentage_","type":"uint256"}],"name":"updateProviderPrimarySalesPercentages","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_renderProviderPrimarySalesAddress","type":"address"},{"internalType":"address payable","name":"_defaultRenderProviderSecondarySalesAddress","type":"address"},{"internalType":"address payable","name":"_platformProviderPrimarySalesAddress","type":"address"},{"internalType":"address payable","name":"_defaultPlatformProviderSecondarySalesAddress","type":"address"}],"name":"updateProviderSalesAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_randomizerAddress","type":"address"}],"name":"updateRandomizerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_splitProviderAddress","type":"address"}],"name":"updateSplitProvider","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b5061dead620000208162000027565b50620000a6565b620000328162000054565b600d80546001600160a01b0319166001600160a01b0392909216919091179055565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b61549680620000b66000396000f3fe608060405234801561001057600080fd5b506004361061046d5760003560e01c806376ee6fab1161025557806376ee6fab1461099f578063801aa941146109b25780638639415b146109c55780638997618f14610a205780638c3c9cdd14610a335780638da5cb5b14610a465780638dd91a5614610a4e57806392f0023314610a725780639523751714610a855780639549179514610a9857806395d89b4114610aab578063993c0cbf14610ab35780639a02e4fa14610ac65780639d97f4a014610afd578063a11ec70a14610b10578063a22cb46514610b23578063a3b2cca614610b36578063a47d29cb14610b49578063abcbb7b414610b75578063ac11fa1c14610b7d578063acad012414610b9d578063acd4c66f14610bb0578063ad0305ce14610bc2578063ae45ad9814610be4578063b1656ba314610bec578063b168762214610bff578063b202b56514610c12578063b75395e014610c25578063b7b04fae14610c38578063b88d4fde14610c4b578063b971136814610c5e578063bd3d10e714610c66578063c34a03b514610c79578063c87b56dd14610c8c578063cc90e72514610c9f578063ce90652014610cb2578063d03c390c14610cc5578063db2ff86114610cd8578063e32551e714610ceb578063e6032df214610cfe578063e935b7b114610d0b578063e985e9c514610d1c578063eb9cd5d414610d2f578063ed8abfda14610d51578063eef719a414610d7b578063f23f702114610d84578063f2fde38b14610d97578063f851a44014610daa578063f893c07b14610db2578063ffd43f6514610dbb57600080fd5b80611e3c146104725780615de5146104875780630132c697146104ad57806301856fd4146104c057806301ffc9a7146104d357806304143a5c146104f657806306fdde03146104fe578063081812fc14610513578063095ea7b3146105335780630a1df77a146105465780630d170673146106715780630e79c928146106845780630ea5613f1461069757806317df5366146106e15780631ab6014c146106f45780631b689c0b146107075780631c05cad71461071a5780631e9bef461461072d5780632302cbda14610740578063230448b11461075357806323b872dd1461076657806325b75d681461077957806327df6c1a1461078c5780632a55205a1461079f5780632b274166146107c05780632b65e67d146107d35780632d9c0205146107e657806330ef4c5f146107f9578063329dab731461080b57806336c7c12c1461081e578063378599631461083157806337fbc96514610844578063398a2895146108575780633e48e8481461086a57806342842e0e1461087d57806348337282146108905780634b976697146108a35780634e1d64af146108b65780635119d04b146108be5780635508fd52146108c757806357a8e574146108db57806358b9a5a9146108ee578063621a1f74146109265780636352211e1461093957806369d14faf1461094c5780636c907b7f1461095f5780636ddba4111461097257806370a0823114610984578063715018a614610997575b600080fd5b610485610480366004614419565b610dce565b005b61049a610495366004614460565b610e96565b6040519081526020015b60405180910390f35b6104856104bb3660046144a2565b611096565b6104856104ce366004614419565b61115d565b6104e66104e13660046144f0565b6111dc565b60405190151581526020016104a4565b610485611207565b61050661124f565b6040516104a4919061455d565b610526610521366004614570565b6112e1565b6040516104a49190614596565b6104856105413660046145aa565b6112f6565b610664610554366004614570565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152506000908152600f602090815260409182902082516101608101845281546001600160a01b03808216835260ff600160a01b9283900481169584019590955260018401548082169684019690965294819004841660608301526002830154808616608084015281900490931660a0820152600382015480851660c083015261ffff90849004811660e08301526004830154808616610100840152939093049092166101208301526005015490911661014082015290565b6040516104a491906145d6565b61048561067f3660046147a3565b611305565b6104856106923660046147a3565b611364565b6106aa6106a5366004614570565b6114bd565b60408051968752602087019590955292151593850193909352151560608401526080830191909152151560a082015260c0016104a4565b600954610526906001600160a01b031681565b601254610526906001600160a01b031681565b61049a610715366004614570565b611520565b6104856107283660046147e9565b61152f565b600d54610526906001600160a01b031681565b61048561074e366004614845565b61155d565b6104e6610761366004614879565b611582565b6104856107743660046148b9565b61162e565b6104856107873660046147a3565b6116b3565b61048561079a366004614419565b6116f9565b6107b26107ad366004614419565b611797565b6040516104a49291906148fa565b6104856107ce366004614913565b611863565b6104856107e1366004614930565b6118b4565b6105066107f4366004614570565b611b21565b601254600160a01b900460ff1661049a565b610485610819366004614997565b611bc6565b600b54610526906001600160a01b031681565b61048561083f3660046147a3565b611c7f565b601c54610526906001600160a01b031681565b610485610865366004614570565b611cab565b6104856108783660046147a3565b611d62565b61048561088b3660046148b9565b611d97565b61048561089e366004614913565b611db7565b601d54610526906001600160a01b031681565b610506611dd9565b61049a60165481565b6019546104e690600160f81b900460ff1681565b600854610526906001600160a01b031681565b6105266108fc366004614419565b6000918252600e60209081526040808420928452600990920190529020546001600160a01b031690565b61049a610934366004614570565b611df2565b610526610947366004614570565b611e54565b61048561095a3660046149e6565b611e5f565b61048561096d366004614913565b611ebc565b601a546104e690610100900460ff1681565b61049a610992366004614913565b611ede565b610485611f26565b6104856109ad366004614930565b611f3e565b601554610526906001600160a01b031681565b6109d86109d3366004614419565b6120d2565b604080519889526001600160a01b0397881660208a015288019590955292851660608701526080860191909152831660a085015260c08401521660e0820152610100016104a4565b600a54610526906001600160a01b031681565b610506610a41366004614419565b6121db565b61052661223a565b610a61610a5c366004614570565b61224e565b6040516104a4959493929190614a0b565b601754610526906001600160a01b031681565b610485610a93366004614913565b6124eb565b610485610aa6366004614aa8565b612526565b610506612532565b610485610ac1366004614913565b612541565b610af0610ad4366004614570565b600090815260036020526040902054600160a01b900460a01b90565b6040516104a49190614c2d565b610485610b0b366004614913565b612563565b610485610b1e366004614570565b61257c565b610485610b31366004614c42565b6125cf565b610485610b443660046147a3565b6125da565b610526610b57366004614570565b6000908152600f60205260409020600201546001600160a01b031690565b61050661269b565b61049a610b8b366004614570565b60106020526000908152604090205481565b610485610bab3660046147a3565b612729565b601154600160a01b900460ff1661049a565b6104e6610bd0366004614913565b6017546001600160a01b0390811691161490565b6105066127da565b610485610bfa366004614997565b6127fe565b610526610c0d366004614570565b612868565b610485610c203660046147a3565b6128be565b601154610526906001600160a01b031681565b610485610c463660046147a3565b6128f8565b610485610c59366004614c70565b6129a6565b600c5461049a565b610485610c74366004614419565b6129bd565b610485610c87366004614419565b612a66565b610506610c9a366004614570565b612ac8565b610485610cad366004614cdb565b612bb0565b601a546104e69062010000900460ff1681565b610485610cd3366004614570565b612d59565b610485610ce6366004614570565b612dcb565b610506610cf9366004614845565b612e96565b601a546104e69060ff1681565b6019546001600160f81b031661049a565b6104e6610d2a366004614d21565b612f1d565b610d42610d3d366004614570565b612f4b565b6040516104a493929190614d4f565b61049a610d5f366004614570565b6000908152600f6020526040902054600160a01b900460ff1690565b61049a60145481565b610485610d92366004614913565b613017565b610485610da5366004614913565b613049565b610526613084565b61049a60185481565b601354610526906001600160a01b031681565b610dd78261308e565b6000828152600360205260409020600b546001600160a01b03163314610e1c57600e60405163d327ad1b60e01b8152600401610e139190614d85565b60405180910390fd5b8054600160a01b900460a01b6001600160a01b03191615610e5357600f60405163d327ad1b60e01b8152600401610e139190614d85565b81610e7457601060405163d327ad1b60e01b8152600401610e139190614d85565b805460a09290921c600160a01b026001600160a01b0390921691909117905550565b6017546000906001600160a01b03163314610ec757600a60405163d327ad1b60e01b8152600401610e139190614d85565b6000838152600e60205260409020805462ffffff808216916001830191630100000090910416808310610f1057600b60405163d327ad1b60e01b8152600401610e139190614d85565b8354600160881b900460ff1680610f4357506000878152600f60205260409020600201546001600160a01b038781169116145b610f6357600c60405163d327ad1b60e01b8152600401610e139190614d85565b8354600160901b900460ff168015610f9857506000878152600f60205260409020600201546001600160a01b03878116911614155b15610fb957600d60405163d327ad1b60e01b8152600401610e139190614d85565b835462ffffff191662ffffff8381169182178655848116620f42408a0201919083169003610fea57610fea886130c3565b610ff489826130f8565b600b54604051635b140b8d60e11b8152600481018390526001600160a01b039091169063b628171a90602401600060405180830381600087803b15801561103a57600080fd5b505af115801561104e573d6000803e3d6000fd5b50506040518392506001600160a01b038c1691507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688590600090a39450505050505b9392505050565b61109f8261315d565b6000828152600e60205260409020805462ffffff80821691630100000090048116908416106110e457601c60405163d327ad1b60e01b8152600401610e139190614d85565b808362ffffff16101561110d57601d60405163d327ad1b60e01b8152600401610e139190614d85565b815465ffffff0000001916630100000062ffffff851602178255600b604051859060008051602061544183398151915290600090a3808362ffffff160361115757611157846130c3565b50505050565b6111668261319a565b6111768262615bf560e21b6131c3565b6000828152600e602052604090819020906111949083906001613211565b6111b457602060405163d327ad1b60e01b8152600401610e139190614d85565b60078101829055600d5b604051849060008051602061544183398151915290600090a3505050565b60006001600160e01b0319821663152a902d60e11b1480611201575061120182613285565b92915050565b6112176301050e9760e21b6132d5565b601954600160f81b900460ff161561124557601960405163d327ad1b60e01b8152600401610e139190614d85565b61124d613300565b565b60606000805461125e90614dad565b80601f016020809104026020016040519081016040528092919081815260200182805461128a90614dad565b80156112d75780601f106112ac576101008083540402835291602001916112d7565b820191906000526020600020905b8154815290600101906020018083116112ba57829003601f168201915b5050505050905090565b60006112ec82613341565b5061120182613379565b611301828233613394565b5050565b61130e8261319a565b61131f82630d17067360e01b6131c3565b611328816133a1565b6000828152600e602052604090206001016113438282614e46565b5060055b604051839060008051602061544183398151915290600090a35050565b61136d8261319a565b61137e826301cf392560e31b6131c3565b611387816133a1565b80518190600b8111156113b057602160405163d327ad1b60e01b8152600401610e139190614d85565b60008060005b8381101561145c5760008582815181106113d2576113d2614eff565b01602001516001600160f81b0319169050600360fc1b81108015906114055750603960f81b6001600160f81b0319821611155b15611414576001925050611454565b6001600160f81b03198116601760f91b036114385783611438576001935050611454565b602360405163d327ad1b60e01b8152600401610e139190614d85565b6001016113b6565b508061147e57602260405163d327ad1b60e01b8152600401610e139190614d85565b6000868152600e602052604090206008016114998682614e46565b50600e604051879060008051602061544183398151915290600090a3505050505050565b6000818152600e60205260408120805462ffffff808216936301000000830490911692600160881b830460ff90811693600160901b810490911692600160481b9091046001600160401b031691611513886133c6565b1591505091939550919395565b6000611201620f424083614f2b565b61153f631c05cad760e01b6132d5565b61154884613410565b61155183613410565b6111578484848461343a565b61156d63118165ed60e11b6132d5565b611576816133a1565b61157f8161350b565b50565b60008061158d61223a565b6001600160a01b0316141580156116265750600d546040516217798b60e61b81526001600160a01b03868116600483015285811660248301526001600160e01b031985166044830152909116906305de62c0906064016020604051808303816000875af1158015611602573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116269190614f4d565b949350505050565b6001600160a01b038216611658576000604051633250574960e11b8152600401610e139190614596565b600061166583833361351f565b9050836001600160a01b0316816001600160a01b031614611157576040516364283d7b60e01b81526001600160a01b0380861660048301526024820184905282166044820152606401610e13565b6116bc8261319a565b6116cd826304b6ebad60e31b6131c3565b6116d6816133a1565b6000828152600e602052604090206005016116f18282614e46565b50600a611347565b6117096313efb60d60e11b6132d5565b601a54610100900460ff16801561171f57508015155b1561174057602460405163d327ad1b60e01b8152600401610e139190614d85565b61271061174d8284614f6a565b111561176f57601360405163d327ad1b60e01b8152600401610e139190614d85565b6014829055601681905560095b6040516000805160206153e183398151915290600090a25050565b6000806117a38461308e565b60006117ae85611520565b6000818152600f6020526040812060058101546004820154600383015483546001600160a01b039093169850949550919361ffff600160a01b938490048116939182900416916118049160ff9104166064614f7d565b61180e9190614f6a565b6118189190614f6a565b905061271081111561184057601360405163d327ad1b60e01b8152600401610e139190614d85565b61271061184d8288614f7d565b6118579190614f2b565b93505050509250929050565b611873631593a0b360e11b6132d5565b61187c81613410565b600980546001600160a01b0319166001600160a01b03831617905560055b6040516000805160206153e183398151915290600090a250565b6118bd86613613565b6118c68661315d565b6118cf85613410565b6000868152600f6020526040902060648411806118ec5750606482115b1561190d57601460405163d327ad1b60e01b8152600401610e139190614d85565b60008411801561192457506001600160a01b038516155b1561194557601560405163d327ad1b60e01b8152600401610e139190614d85565b60008211801561195c57506001600160a01b038316155b1561197d57601660405163d327ad1b60e01b8152600401610e139190614d85565b867f6ff7d102bb3657a26dcbbcd299d821a066718a7cf76ae7cd98279f18b74da8ac87878787876040516119b5959493929190614f94565b60405180910390a2601a5460ff1680611a4057600282015482546001600160a01b039182168983161491600091811690891614806119fa57506001600160a01b038816155b60018501549091506000906001600160a01b0388811691161480611a2557506001600160a01b038716155b9050828015611a315750815b8015611a3a5750805b93505050505b8015611ad85760008881526010602052604081205560028201805483546001600160a01b038981166001600160a01b03199290921691909117855560ff808916600160a01b9081026001600160a81b0319948516848e161717909455600186018054918816909402921690871617179055611aba8861364f565b604051889060008051602061540183398151915290600090a2611b17565b8686868686604051602001611af1959493929190614f94565b60408051601f19818403018152918152815160209283012060008b815260109093529120555b5050505050505050565b6000818152600e60205260409020600601805460609190611b4190614dad565b80601f0160208091040260200160405190810160405280929190818152602001828054611b6d90614dad565b8015611bba5780601f10611b8f57610100808354040283529160200191611bba565b820191906000526020600020905b815481529060010190602001808311611b9d57829003601f168201915b50505050509050919050565b611bcf8361319a565b611be08363329dab7360e01b6131c3565b611be98161379b565b6000838152600e602052604090208054600160301b900462ffffff168310611c2757601e60405163d327ad1b60e01b8152600401610e139190614d85565b611c30826137c0565b6000848152600983016020526040902080546001600160a01b0319166001600160a01b0392909216919091179055600c604051859060008051602061544183398151915290600090a350505050565b611c888261315d565b6000828152600e60205260409020600401611ca38282614e46565b506009611347565b611cbb63398a289560e01b6132d5565b611cc481613613565b6000818152600f602052604090206015546003820180546001600160a01b039283166001600160a01b0319808316821784556016546001600160b01b0319938416909217600160a01b61ffff938416810291909117909455601354600487018054919096169181168217865560145493161791169091021790556010604051839060008051602061544183398151915290600090a36113018261364f565b611d6b8261315d565b611d74816133a1565b6000828152600e60205260409020600601611d8f8282614e46565b50600f611347565b611db2838383604051806020016040528060008152506129a6565b505050565b611dc7632419b94160e11b6132d5565b611dd081613410565b61157f8161385e565b6060611ded651d8ccb8c8b8d60d21b6138a8565b905090565b600081815260036020526040812054600160a01b900460a01b6001600160a01b031981168203611e255750600092915050565b80604051602001611e369190614c2d565b60405160208183030381529060405280519060200120915050919050565b600061120182613341565b611e6882613613565b611e79826369d14faf60e01b613913565b611e8281613410565b6000828152600f6020526040902060020180546001600160a01b0319166001600160a01b038316179055611eb58261364f565b6002611347565b611ecc636c907b7f60e01b6132d5565b611ed581613410565b61157f81613985565b60006001600160a01b038216611f0a5760006040516322718ad960e21b8152600401610e139190614596565b506001600160a01b031660009081526004602052604090205490565b611f2e6139e7565b611f36613300565b61124d613a19565b611f4786613613565b611f58866376ee6fab60e01b613913565b611f6185613410565b8484848484604051602001611f7a959493929190614f94565b60408051601f1981840301815291815281516020928301206000898152601090935291205414611fc057601760405163d327ad1b60e01b8152600401610e139190614d85565b6000600f60008881526020019081526020016000209050858160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550848160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550838160020160146101000a81548160ff021916908360ff160217905550828160010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550818160010160146101000a81548160ff021916908360ff1602179055506000801b60106000898152602001908152602001600020819055506120b08761364f565b604051879060008051602061540183398151915290600090a250505050505050565b6000828152600f602052604081206011548291829182918291829182918291908a9060649061210b90600160a01b900460ff1683614f7d565b6121159190614f2b565b99506121218a82614fc7565b60125490915060649061213e90600160a01b900460ff168d614f7d565b6121489190614f2b565b97506121548882614fc7565b600283015490915060649061217390600160a01b900460ff1683614f7d565b61217d9190614f2b565b93506121898482614fc7565b6011546012546001600160a01b039182169b50169750955085156121b85760028201546001600160a01b031694505b83156121cc5781546001600160a01b031692505b50509295985092959890939650565b6000828152600e60205260409020805460609190600160301b900462ffffff168310612217575050604080516020810190915260008152611201565b6000838152600982016020526040902054611626906001600160a01b0316613a2b565b6000611ded6007546001600160a01b031690565b60608060608060606000600e6000888152602001908152602001600020905080600101805461227c90614dad565b80601f01602080910402602001604051908101604052809291908181526020018280546122a890614dad565b80156122f55780601f106122ca576101008083540402835291602001916122f5565b820191906000526020600020905b8154815290600101906020018083116122d857829003601f168201915b5050505050955080600201805461230b90614dad565b80601f016020809104026020016040519081016040528092919081815260200182805461233790614dad565b80156123845780601f1061235957610100808354040283529160200191612384565b820191906000526020600020905b81548152906001019060200180831161236757829003601f168201915b505050506003830154919650506001600160a01b0316806123b6576040518060200160405280600081525094506123c2565b6123bf81613a2b565b94505b8160040180546123d190614dad565b80601f01602080910402602001604051908101604052809291908181526020018280546123fd90614dad565b801561244a5780601f1061241f5761010080835404028352916020019161244a565b820191906000526020600020905b81548152906001019060200180831161242d57829003601f168201915b5050505050935081600501805461246090614dad565b80601f016020809104026020016040519081016040528092919081815260200182805461248c90614dad565b80156124d95780601f106124ae576101008083540402835291602001916124d9565b820191906000526020600020905b8154815290600101906020018083116124bc57829003601f168201915b50505050509250505091939590929450565b6124fb639523751760e01b6132d5565b61250481613410565b600a80546001600160a01b0319166001600160a01b038316179055600661189a565b61115784848484613a79565b60606001805461125e90614dad565b61255163993c0cbf60e01b6132d5565b61255a81613410565b61157f81613c40565b6125736304ecbfa560e51b6132d5565b61157f81613c62565b6125858161315d565b6000818152600e60205260409020805460ff60901b198116600160901b9182900460ff161590910217905560035b604051829060008051602061544183398151915290600090a350565b611301338383613c8d565b6125e3826133c6565b1561262a576000828152600f60205260409020600201546001600160a01b0316331461262557601a60405163d327ad1b60e01b8152600401610e139190614d85565b61265c565b61263c33306351d9665360e11b611582565b61265c57601a60405163d327ad1b60e01b8152600401610e139190614d85565b61266581613d23565b6000838152600e6020526040902060030180546001600160a01b0319166001600160a01b03929092169190911790556008611347565b601b80546126a890614dad565b80601f01602080910402602001604051908101604052809291908181526020018280546126d490614dad565b80156127215780601f106126f657610100808354040283529160200191612721565b820191906000526020600020905b81548152906001019060200180831161270457829003601f168201915b505050505081565b6127328261319a565b61274382632b2b404960e21b6131c3565b61274c816133a1565b6000828152600e6020526040902061276382613d23565b8154600160301b9081900462ffffff9081166000908152600985016020526040902080546001600160a01b0319166001600160a01b03949094169390931790925582546127b592919004166001614fda565b815462ffffff91909116600160301b0262ffffff60301b19909116178155600c6111be565b6060611ded7547656e417274373231436f726556335f456e67696e6560501b6138a8565b6128078361319a565b6128188363b1656ba360e01b6131c3565b612821816133a1565b6000838152600e602052604090208054600160301b900462ffffff16831061285f57601e60405163d327ad1b60e01b8152600401610e139190614d85565b611c3082613d23565b600c54600090821061289057601260405163d327ad1b60e01b8152600401610e139190614d85565b600c82815481106128a3576128a3614eff565b6000918252602090912001546001600160a01b031692915050565b6128c78261319a565b6128d88263b202b56560e01b6131c3565b6128e18161379b565b6000828152600e60205260409020612763826137c0565b612901826133c6565b15612948576000828152600f60205260409020600201546001600160a01b0316331461294357601a60405163d327ad1b60e01b8152600401610e139190614d85565b61297a565b61295a3330635bd827d760e11b611582565b61297a57601a60405163d327ad1b60e01b8152600401610e139190614d85565b612983816133a1565b6000828152600e6020526040902060020161299e8282614e46565b506006611347565b6129b184848461162e565b61115784848484613d49565b6129cd63bd3d10e760e01b6132d5565b601a54610100900460ff1680156129e357508015155b15612a0457602460405163d327ad1b60e01b8152600401610e139190614d85565b6064612a108284614f6a565b1115612a3257601160405163d327ad1b60e01b8152600401610e139190614d85565b6011805460ff808516600160a01b90810260ff60a01b1993841617909355601280549185169093029116179055600861177c565b612a6f8261315d565b605f811115612a9457601b60405163d327ad1b60e01b8152600401610e139190614d85565b6000828152600f60205260409020805460ff60a01b1916600160a01b60ff841602179055612ac18261364f565b6007611347565b6060612ad38261308e565b6000600e6000612ae285611520565b81526020019081526020016000206006018054612afe90614dad565b80601f0160208091040260200160405190810160405280929190818152602001828054612b2a90614dad565b8015612b775780601f10612b4c57610100808354040283529160200191612b77565b820191906000526020600020905b815481529060010190602001808311612b5a57829003601f168201915b5050505050905080612b8884613e60565b604051602001612b99929190614ffd565b604051602081830303815290604052915050919050565b612bc063cc90e72560e01b6132d5565b612bc9826133a1565b612bd281613410565b601954600160f81b900460ff1615612c0057601860405163d327ad1b60e01b8152600401610e139190614d85565b6019546001600160f81b03166000818152600f602090815260408083206002810180546001600160a01b0319166001600160a01b038816179055600e909252909120600101612c4f8582614e46565b506000828152600e60205260409020805465ffffff00000060ff60901b011916613d09601e1b600160901b01178155600601612c8c601b8261502c565b50805460ff60a01b1916600560a01b1781556015546003820180546001600160a01b039283166001600160a01b0319808316821784556016546001600160b01b0319938416909217600160a01b61ffff93841681029190911790945560135460048701805491909616918116821786556014549316179116909102179055612d158260016150f8565b601980546001600160f81b0319166001600160f81b03929092169190911790556004604051839060008051602061544183398151915290600090a36111578261364f565b601a5462010000900460ff1615612d8057612d7b8163340f0e4360e21b6131c3565b612d90565b612d9063340f0e4360e21b6132d5565b612d9981613613565b6000818152600e60205260409020805460ff60881b198116600160881b9182900460ff161590910217905560016125b3565b612dd48161319a565b612de58163db2ff86160e01b6131c3565b6000818152600e6020526040812080549091600160301b90910462ffffff169003612e2657601f60405163d327ad1b60e01b8152600401610e139190614d85565b80546009820190600090612e4890600190600160301b900462ffffff16615118565b62ffffff9081168252602082019290925260400160002080546001600160a01b0319169055815462ffffff60301b198116600160301b9182900483166000190190921602178155600c611347565b6060612ea1826133a1565b60405163e32551e760e01b815273000000000016a5a5ff2fa7799c4bee89ba59b74e9063e32551e790612ed890859060040161455d565b600060405180830381865af4158015612ef5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112019190810190615164565b6001600160a01b03918216600090815260066020908152604080832093909416825291909152205460ff1690565b6000818152600e60205260408120600781015460609283929091612f6e906138a8565b9350806008018054612f7f90614dad565b80601f0160208091040260200160405190810160405280929190818152602001828054612fab90614dad565b8015612ff85780601f10612fcd57610100808354040283529160200191612ff8565b820191906000526020600020905b815481529060010190602001808311612fdb57829003601f168201915b5050935496989297505050600160301b90940462ffffff169392505050565b61302763f23f702160e01b6132d5565b600880546001600160a01b0319166001600160a01b038316179055600461189a565b6130516139e7565b6001600160a01b03811661307b576000604051631e4fbdf760e01b8152600401610e139190614596565b61157f81613ef2565b6000611ded61223a565b600061309982613f1d565b6001600160a01b03160361157f57600360405163d327ad1b60e01b8152600401610e139190614d85565b6000818152600e602052604081208054600160481b600160881b031916600160481b426001600160401b0316021790556125b3565b6001600160a01b038216613122576000604051633250574960e11b8152600401610e139190614596565b60006131308383600061351f565b90506001600160a01b03811615611db25760006040516339e3563760e11b8152600401610e139190614596565b6000818152600f60205260409020600201546001600160a01b0316331461157f57600760405163d327ad1b60e01b8152600401610e139190614d85565b6131a3816133c6565b61157f57600560405163d327ad1b60e01b8152600401610e139190614d85565b6000828152600f60205260409020600201546001600160a01b03163314806131f157506131f1333083611582565b61130157600860405163d327ad1b60e01b8152600401610e139190614d85565b60008060005b60208160ff161015613271576000868260ff166020811061323a5761323a614eff565b1a9050801580159061324f575060808160ff16105b15613268578560ff168160ff1603613268578260010192505b50600101613217565b8360ff168260ff1614925050509392505050565b60006001600160e01b031982166380ac58cd60e01b14806132b657506001600160e01b03198216635b5e139f60e01b145b8061120157506301ffc9a760e01b6001600160e01b0319831614611201565b6132e0333083611582565b61157f57600660405163d327ad1b60e01b8152600401610e139190614d85565b601954600160f81b900460ff1661124d57601980546001600160f81b0316600160f81b17905560016040516000805160206153e183398151915290600090a2565b60008061334d83613f1d565b90506001600160a01b03811661120157604051637e27328960e01b815260048101849052602401610e13565b6000908152600560205260409020546001600160a01b031690565b611db28383836001613f38565b805160000361157f57600160405163d327ad1b60e01b8152600401610e139190614d85565b60006133d182613613565b6000828152600e6020526040902054600160481b90046001600160401b03168015808061162657506224ea006134078342614fc7565b10949350505050565b6001600160a01b03811661157f57600060405163d327ad1b60e01b8152600401610e139190614d85565b601a54610100900460ff161561348f576001600160a01b03821615158061346957506001600160a01b03811615155b1561348a57602460405163d327ad1b60e01b8152600401610e139190614d85565b6134a1565b61349882613410565b6134a181613410565b601280546001600160a01b038085166001600160a01b0319928316179092556015805484841690831617905560118054878416908316179055601380549286169290911691909117905560075b6040516000805160206153e183398151915290600090a250505050565b601b6135178282614e46565b50600261189a565b60008061352b84613f1d565b90506001600160a01b0383161561354757613547818486614035565b6001600160a01b0381161561358557613564600085600080613f38565b6001600160a01b038116600090815260046020526040902080546000190190555b6001600160a01b038516156135b4576001600160a01b0385166000908152600460205260409020805460010190555b60008481526003602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b60185481108061362e57506019546001600160f81b03168110155b1561157f57600460405163d327ad1b60e01b8152600401610e139190614d85565b6000818152600f60209081526040808320601c5482516101008101845260038301546001600160a01b03818116835261ffff600160a01b92839004811697840197909752600480860154808316858901528390049097166060840152845460ff90839004811660808501526002860154821660a0850152600186015480831660c08601529290920490911660e08301529351631718245360e21b81529295949390911692635c60914c926137049291016151ac565b6020604051808303816000875af1158015613723573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137479190615234565b6005830180546001600160a01b0319166001600160a01b0383169081179091556040519192509084907f301670c9279b1d4319606681ed95e193d888fddba44d836b9e8d5585d8cc47b590600090a3505050565b805160000361157f57600260405163d327ad1b60e01b8152600401610e139190614d85565b60008060008051602061542183398151915230846040516020016137e693929190615251565b60405160208183030381529060405290508051602082016000f091506001600160a01b0382166138585760405162461bcd60e51b815260206004820152601e60248201527f436f6e7472616374417353746f726167653a205772697465204572726f7200006044820152606401610e13565b50919050565b601780546001600160a01b0319166001600160a01b0383169081179091556040517fad0f299ec81a386c98df0ac27dae11dd020ed1b56963c53a7292e7a3a314539a90600090a250565b606060005b828160ff16602081106138c2576138c2614eff565b1a60f81b6001600160f81b031916158015906138e1575060208160ff16105b156138f857806138f0816152bc565b9150506138ad565b60405191506040820160405280825282602083015250919050565b61391e333083611582565b15613927575050565b600061393161223a565b6001600160a01b031614801561396057506000828152600f60205260409020600201546001600160a01b031633145b15613969575050565b600960405163d327ad1b60e01b8152600401610e139190614d85565b600b80546001600160a01b0383166001600160a01b03199182168117909255600c80546001810182556000919091527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70180549091169091179055600361189a565b336139f061223a565b6001600160a01b03161461124d573360405163118cdaa760e01b8152600401610e139190614596565b613a216139e7565b61124d6000613ef2565b601d54604051630eacc5e760e31b81526060916001600160a01b0316906375662f3890613a5c908590600401614596565b600060405180830381865afa158015612ef5573d6000803e3d6000fd5b600a54600160a01b900460ff1615613aa757602560405163d327ad1b60e01b8152600401610e139190614d85565b600a8054600160a01b60ff60a01b199182161790915560118054909116600560a11b17905560fa601455610140840151613ae257600a613ae5565b60005b601260146101000a81548160ff021916908360ff160217905550836101400151613b105760fa613b13565b60005b60ff1660165583516020850151613b2a919061408b565b60e08401516001600160a01b031615613b4a57613b4a8460e0015161385e565b613b578460c00151613c62565b613b6081613c40565b610120840151601a805461014087015161016088015161ffff1990921693151561ff0019169390931761010093151584021762ff0000191662010000911515919091021790558401516001600160f81b031660185560408401516060850151613bcc919081908061343a565b613bd98460a00151613985565b613be283613ef2565b613c1482613bef306140ff565b604051602001613c009291906152db565b60405160208183030381529060405261350b565b610100840151601980546001600160f81b0319166001600160f81b0390921691909117905560006134ee565b601d80546001600160a01b0319166001600160a01b038316179055600b61189a565b613c6b81613410565b601c80546001600160a01b0319166001600160a01b038316179055600a61189a565b6001600160a01b038216613cb65781604051630b61174360e31b8152600401610e139190614596565b6001600160a01b03838116600081815260066020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b60008060008051602061542183398151915230846040516020016137e693929190615316565b6001600160a01b0383163b1561115757604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290613d8b90339088908790879060040161536f565b6020604051808303816000875af1925050508015613dc6575060408051601f3d908101601f19168201909252613dc3918101906153ac565b60015b613e26573d808015613df4576040519150601f19603f3d011682016040523d82523d6000602084013e613df9565b606091505b508051600003613e1e5783604051633250574960e11b8152600401610e139190614596565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b14613e595783604051633250574960e11b8152600401610e139190614596565b5050505050565b60606000613e6d83614115565b60010190506000816001600160401b03811115613e8c57613e8c6146b7565b6040519080825280601f01601f191660200182016040528015613eb6576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084613ec057509392505050565b613efb816141eb565b600d80546001600160a01b0319166001600160a01b0392909216919091179055565b6000908152600360205260409020546001600160a01b031690565b8080613f4c57506001600160a01b03821615155b15614005576000613f5c84613341565b90506001600160a01b03831615801590613f885750826001600160a01b0316816001600160a01b031614155b8015613f9b5750613f998184612f1d565b155b15613fbb578260405163a9fbf51f60e01b8152600401610e139190614596565b81156140035783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260056020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b61404083838361423d565b611db2576001600160a01b03831661406e57604051637e27328960e01b815260048101829052602401610e13565b818160405163177e802f60e01b8152600401610e139291906148fa565b60025460ff16156140d45760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b6044820152606401610e13565b60006140e08382614e46565b5060016140ed8282614e46565b50506002805460ff1916600117905550565b60606112016001600160a01b03831660146142a2565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106141545772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6904ee2d6d415b85acef8160201b831061417e576904ee2d6d415b85acef8160201b830492506020015b662386f26fc10000831061419c57662386f26fc10000830492506010015b6305f5e10083106141b4576305f5e100830492506008015b61271083106141c857612710830492506004015b606483106141da576064830492506002015b600a83106112015760010192915050565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60006001600160a01b038316158015906116265750826001600160a01b0316846001600160a01b0316148061427757506142778484612f1d565b806116265750826001600160a01b031661429083613379565b6001600160a01b031614949350505050565b60608260006142b2846002614f7d565b6142bd906002614f6a565b6001600160401b038111156142d4576142d46146b7565b6040519080825280601f01601f1916602001820160405280156142fe576020820181803683370190505b509050600360fc1b8160008151811061431957614319614eff565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061434857614348614eff565b60200101906001600160f81b031916908160001a905350600061436c856002614f7d565b614377906001614f6a565b90505b60018111156143ef576f181899199a1a9b1b9c1cb0b131b232b360811b83600f16601081106143ab576143ab614eff565b1a60f81b8282815181106143c1576143c1614eff565b60200101906001600160f81b031916908160001a90535060049290921c916143e8816153c9565b905061437a565b5081156116265760405163e22e27eb60e01b81526004810186905260248101859052604401610e13565b6000806040838503121561442c57600080fd5b50508035926020909101359150565b6001600160a01b038116811461157f57600080fd5b803561445b8161443b565b919050565b60008060006060848603121561447557600080fd5b83356144808161443b565b92506020840135915060408401356144978161443b565b809150509250925092565b600080604083850312156144b557600080fd5b82359150602083013562ffffff811681146144cf57600080fd5b809150509250929050565b6001600160e01b03198116811461157f57600080fd5b60006020828403121561450257600080fd5b813561108f816144da565b60005b83811015614528578181015183820152602001614510565b50506000910152565b6000815180845261454981602086016020860161450d565b601f01601f19169290920160200192915050565b60208152600061108f6020830184614531565b60006020828403121561458257600080fd5b5035919050565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b600080604083850312156145bd57600080fd5b82356145c88161443b565b946020939093013593505050565b6000610160820190506145ea828451614589565b60208301516145fe602084018260ff169052565b5060408301516146116040840182614589565b506060830151614626606084018260ff169052565b5060808301516146396080840182614589565b5060a083015161464e60a084018260ff169052565b5060c083015161466160c0840182614589565b5060e083015161467760e084018261ffff169052565b506101008084015161468b82850182614589565b50506101208381015161ffff1690830152610140808401516146af82850182614589565b505092915050565b634e487b7160e01b600052604160045260246000fd5b60405161018081016001600160401b03811182821017156146f0576146f06146b7565b60405290565b604051601f8201601f191681016001600160401b038111828210171561471e5761471e6146b7565b604052919050565b60006001600160401b0382111561473f5761473f6146b7565b50601f01601f191660200190565b600082601f83011261475e57600080fd5b813561477161476c82614726565b6146f6565b81815284602083860101111561478657600080fd5b816020850160208301376000918101602001919091529392505050565b600080604083850312156147b657600080fd5b8235915060208301356001600160401b038111156147d357600080fd5b6147df8582860161474d565b9150509250929050565b600080600080608085870312156147ff57600080fd5b843561480a8161443b565b9350602085013561481a8161443b565b9250604085013561482a8161443b565b9150606085013561483a8161443b565b939692955090935050565b60006020828403121561485757600080fd5b81356001600160401b0381111561486d57600080fd5b6116268482850161474d565b60008060006060848603121561488e57600080fd5b83356148998161443b565b925060208401356148a98161443b565b91506040840135614497816144da565b6000806000606084860312156148ce57600080fd5b83356148d98161443b565b925060208401356148e98161443b565b929592945050506040919091013590565b6001600160a01b03929092168252602082015260400190565b60006020828403121561492557600080fd5b813561108f8161443b565b60008060008060008060c0878903121561494957600080fd5b86359550602087013561495b8161443b565b9450604087013561496b8161443b565b93506060870135925060808701356149828161443b565b8092505060a087013590509295509295509295565b6000806000606084860312156149ac57600080fd5b833592506020840135915060408401356001600160401b038111156149d057600080fd5b6149dc8682870161474d565b9150509250925092565b600080604083850312156149f957600080fd5b8235915060208301356144cf8161443b565b60a081526000614a1e60a0830188614531565b8281036020840152614a308188614531565b90508281036040840152614a448187614531565b90508281036060840152614a588186614531565b90508281036080840152614a6c8185614531565b98975050505050505050565b80356001600160f81b038116811461445b57600080fd5b801515811461157f57600080fd5b803561445b81614a8f565b60008060008060808587031215614abe57600080fd5b84356001600160401b0380821115614ad557600080fd5b908601906101808289031215614aea57600080fd5b614af26146cd565b823582811115614b0157600080fd5b614b0d8a82860161474d565b825250602083013582811115614b2257600080fd5b614b2e8a82860161474d565b602083015250614b4060408401614450565b6040820152614b5160608401614450565b6060820152614b6260808401614450565b6080820152614b7360a08401614450565b60a0820152614b8460c08401614450565b60c0820152614b9560e08401614450565b60e0820152610100614ba8818501614a78565b90820152610120614bba848201614a9d565b90820152610140614bcc848201614a9d565b90820152610160614bde848201614a9d565b908201529550614bf060208801614450565b94506040870135915080821115614c0657600080fd5b50614c138782880161474d565b925050614c2260608601614450565b905092959194509250565b6001600160a01b031991909116815260200190565b60008060408385031215614c5557600080fd5b8235614c608161443b565b915060208301356144cf81614a8f565b60008060008060808587031215614c8657600080fd5b8435614c918161443b565b93506020850135614ca18161443b565b92506040850135915060608501356001600160401b03811115614cc357600080fd5b614ccf8782880161474d565b91505092959194509250565b60008060408385031215614cee57600080fd5b82356001600160401b03811115614d0457600080fd5b614d108582860161474d565b92505060208301356144cf8161443b565b60008060408385031215614d3457600080fd5b8235614d3f8161443b565b915060208301356144cf8161443b565b606081526000614d626060830186614531565b8281036020840152614d748186614531565b915050826040830152949350505050565b6020810160268310614da757634e487b7160e01b600052602160045260246000fd5b91905290565b600181811c90821680614dc157607f821691505b60208210810361385857634e487b7160e01b600052602260045260246000fd5b601f821115611db2576000816000526020600020601f850160051c81016020861015614e0a5750805b601f850160051c820191505b81811015614e2957828155600101614e16565b505050505050565b600019600383901b1c191660019190911b1790565b81516001600160401b03811115614e5f57614e5f6146b7565b614e7381614e6d8454614dad565b84614de1565b602080601f831160018114614ea25760008415614e905750858301515b614e9a8582614e31565b865550614e29565b600085815260208120601f198616915b82811015614ed157888601518255948401946001909101908401614eb2565b5085821015614eef5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082614f4857634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215614f5f57600080fd5b815161108f81614a8f565b8082018082111561120157611201614f15565b808202811582820484141761120157611201614f15565b6001600160a01b039586168152938516602085015260408401929092529092166060820152608081019190915260a00190565b8181038181111561120157611201614f15565b62ffffff818116838216019080821115614ff657614ff6614f15565b5092915050565b6000835161500f81846020880161450d565b83519083019061502381836020880161450d565b01949350505050565b818103615037575050565b6150418254614dad565b6001600160401b03811115615058576150586146b7565b61506681614e6d8454614dad565b6000601f82116001811461509457600083156150825750848201545b61508c8482614e31565b855550613e59565b600085815260209020601f19841690600086815260209020845b838110156150ce57828601548255600195860195909101906020016150ae565b5085831015614eef5793015460001960f8600387901b161c19169092555050600190811b01905550565b6001600160f81b03818116838216019080821115614ff657614ff6614f15565b62ffffff828116828216039080821115614ff657614ff6614f15565b600061514261476c84614726565b905082815283838301111561515657600080fd5b61108f83602083018461450d565b60006020828403121561517657600080fd5b81516001600160401b0381111561518c57600080fd5b8201601f8101841361519d57600080fd5b61162684825160208401615134565b60006101008201905060018060a01b03808451168352602084015161ffff808216602086015282604087015116604086015280606087015116606086015250505060ff608084015116608083015260a083015161520c60a0840182614589565b5060c083015161521f60c0840182614589565b5060e0830151614ff660e084018260ff169052565b60006020828403121561524657600080fd5b815161108f8161443b565b6a600b5981380380925939f360a81b8152607f60f91b600b820152600c81018490526000602c8201819052606084901b6001600160601b0319166038830152600160f81b604c83015282516152ad81604d85016020870161450d565b91909101604d01949350505050565b600060ff821660ff81036152d2576152d2614f15565b60010192915050565b600083516152ed81846020880161450d565b83519083019061530181836020880161450d565b602f60f81b9101908152600101949350505050565b6a600b5981380380925939f360a81b8152607f60f91b600b820152600c81018490526000602c8201819052606084901b6001600160601b0319166038830152604c820181905282516152ad81604d85016020870161450d565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906153a290830184614531565b9695505050505050565b6000602082840312156153be57600080fd5b815161108f816144da565b6000816153d8576153d8614f15565b50600019019056fe8b810f233ce7ee6e962ab4d98bf0277751de1f5589de3dcc812ac2047994d009c582d05e1da854143bd3271ef4529d79cf5a69fc6057ae320f357acfd291b73842797465636f646553746f726167655f56322e302e305f5f5f5f5f5f5f5f5f20b96a30340e86d03ce4be42f94ac02d7b27b4a4cdae942beb69026718dfe66afca26469706673582212208055dc95b2c5e973b7cbfa46ce14165ba0166b1dab8925c5fb13ac1c0c993cf564736f6c63430008160033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061046d5760003560e01c806376ee6fab1161025557806376ee6fab1461099f578063801aa941146109b25780638639415b146109c55780638997618f14610a205780638c3c9cdd14610a335780638da5cb5b14610a465780638dd91a5614610a4e57806392f0023314610a725780639523751714610a855780639549179514610a9857806395d89b4114610aab578063993c0cbf14610ab35780639a02e4fa14610ac65780639d97f4a014610afd578063a11ec70a14610b10578063a22cb46514610b23578063a3b2cca614610b36578063a47d29cb14610b49578063abcbb7b414610b75578063ac11fa1c14610b7d578063acad012414610b9d578063acd4c66f14610bb0578063ad0305ce14610bc2578063ae45ad9814610be4578063b1656ba314610bec578063b168762214610bff578063b202b56514610c12578063b75395e014610c25578063b7b04fae14610c38578063b88d4fde14610c4b578063b971136814610c5e578063bd3d10e714610c66578063c34a03b514610c79578063c87b56dd14610c8c578063cc90e72514610c9f578063ce90652014610cb2578063d03c390c14610cc5578063db2ff86114610cd8578063e32551e714610ceb578063e6032df214610cfe578063e935b7b114610d0b578063e985e9c514610d1c578063eb9cd5d414610d2f578063ed8abfda14610d51578063eef719a414610d7b578063f23f702114610d84578063f2fde38b14610d97578063f851a44014610daa578063f893c07b14610db2578063ffd43f6514610dbb57600080fd5b80611e3c146104725780615de5146104875780630132c697146104ad57806301856fd4146104c057806301ffc9a7146104d357806304143a5c146104f657806306fdde03146104fe578063081812fc14610513578063095ea7b3146105335780630a1df77a146105465780630d170673146106715780630e79c928146106845780630ea5613f1461069757806317df5366146106e15780631ab6014c146106f45780631b689c0b146107075780631c05cad71461071a5780631e9bef461461072d5780632302cbda14610740578063230448b11461075357806323b872dd1461076657806325b75d681461077957806327df6c1a1461078c5780632a55205a1461079f5780632b274166146107c05780632b65e67d146107d35780632d9c0205146107e657806330ef4c5f146107f9578063329dab731461080b57806336c7c12c1461081e578063378599631461083157806337fbc96514610844578063398a2895146108575780633e48e8481461086a57806342842e0e1461087d57806348337282146108905780634b976697146108a35780634e1d64af146108b65780635119d04b146108be5780635508fd52146108c757806357a8e574146108db57806358b9a5a9146108ee578063621a1f74146109265780636352211e1461093957806369d14faf1461094c5780636c907b7f1461095f5780636ddba4111461097257806370a0823114610984578063715018a614610997575b600080fd5b610485610480366004614419565b610dce565b005b61049a610495366004614460565b610e96565b6040519081526020015b60405180910390f35b6104856104bb3660046144a2565b611096565b6104856104ce366004614419565b61115d565b6104e66104e13660046144f0565b6111dc565b60405190151581526020016104a4565b610485611207565b61050661124f565b6040516104a4919061455d565b610526610521366004614570565b6112e1565b6040516104a49190614596565b6104856105413660046145aa565b6112f6565b610664610554366004614570565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152506000908152600f602090815260409182902082516101608101845281546001600160a01b03808216835260ff600160a01b9283900481169584019590955260018401548082169684019690965294819004841660608301526002830154808616608084015281900490931660a0820152600382015480851660c083015261ffff90849004811660e08301526004830154808616610100840152939093049092166101208301526005015490911661014082015290565b6040516104a491906145d6565b61048561067f3660046147a3565b611305565b6104856106923660046147a3565b611364565b6106aa6106a5366004614570565b6114bd565b60408051968752602087019590955292151593850193909352151560608401526080830191909152151560a082015260c0016104a4565b600954610526906001600160a01b031681565b601254610526906001600160a01b031681565b61049a610715366004614570565b611520565b6104856107283660046147e9565b61152f565b600d54610526906001600160a01b031681565b61048561074e366004614845565b61155d565b6104e6610761366004614879565b611582565b6104856107743660046148b9565b61162e565b6104856107873660046147a3565b6116b3565b61048561079a366004614419565b6116f9565b6107b26107ad366004614419565b611797565b6040516104a49291906148fa565b6104856107ce366004614913565b611863565b6104856107e1366004614930565b6118b4565b6105066107f4366004614570565b611b21565b601254600160a01b900460ff1661049a565b610485610819366004614997565b611bc6565b600b54610526906001600160a01b031681565b61048561083f3660046147a3565b611c7f565b601c54610526906001600160a01b031681565b610485610865366004614570565b611cab565b6104856108783660046147a3565b611d62565b61048561088b3660046148b9565b611d97565b61048561089e366004614913565b611db7565b601d54610526906001600160a01b031681565b610506611dd9565b61049a60165481565b6019546104e690600160f81b900460ff1681565b600854610526906001600160a01b031681565b6105266108fc366004614419565b6000918252600e60209081526040808420928452600990920190529020546001600160a01b031690565b61049a610934366004614570565b611df2565b610526610947366004614570565b611e54565b61048561095a3660046149e6565b611e5f565b61048561096d366004614913565b611ebc565b601a546104e690610100900460ff1681565b61049a610992366004614913565b611ede565b610485611f26565b6104856109ad366004614930565b611f3e565b601554610526906001600160a01b031681565b6109d86109d3366004614419565b6120d2565b604080519889526001600160a01b0397881660208a015288019590955292851660608701526080860191909152831660a085015260c08401521660e0820152610100016104a4565b600a54610526906001600160a01b031681565b610506610a41366004614419565b6121db565b61052661223a565b610a61610a5c366004614570565b61224e565b6040516104a4959493929190614a0b565b601754610526906001600160a01b031681565b610485610a93366004614913565b6124eb565b610485610aa6366004614aa8565b612526565b610506612532565b610485610ac1366004614913565b612541565b610af0610ad4366004614570565b600090815260036020526040902054600160a01b900460a01b90565b6040516104a49190614c2d565b610485610b0b366004614913565b612563565b610485610b1e366004614570565b61257c565b610485610b31366004614c42565b6125cf565b610485610b443660046147a3565b6125da565b610526610b57366004614570565b6000908152600f60205260409020600201546001600160a01b031690565b61050661269b565b61049a610b8b366004614570565b60106020526000908152604090205481565b610485610bab3660046147a3565b612729565b601154600160a01b900460ff1661049a565b6104e6610bd0366004614913565b6017546001600160a01b0390811691161490565b6105066127da565b610485610bfa366004614997565b6127fe565b610526610c0d366004614570565b612868565b610485610c203660046147a3565b6128be565b601154610526906001600160a01b031681565b610485610c463660046147a3565b6128f8565b610485610c59366004614c70565b6129a6565b600c5461049a565b610485610c74366004614419565b6129bd565b610485610c87366004614419565b612a66565b610506610c9a366004614570565b612ac8565b610485610cad366004614cdb565b612bb0565b601a546104e69062010000900460ff1681565b610485610cd3366004614570565b612d59565b610485610ce6366004614570565b612dcb565b610506610cf9366004614845565b612e96565b601a546104e69060ff1681565b6019546001600160f81b031661049a565b6104e6610d2a366004614d21565b612f1d565b610d42610d3d366004614570565b612f4b565b6040516104a493929190614d4f565b61049a610d5f366004614570565b6000908152600f6020526040902054600160a01b900460ff1690565b61049a60145481565b610485610d92366004614913565b613017565b610485610da5366004614913565b613049565b610526613084565b61049a60185481565b601354610526906001600160a01b031681565b610dd78261308e565b6000828152600360205260409020600b546001600160a01b03163314610e1c57600e60405163d327ad1b60e01b8152600401610e139190614d85565b60405180910390fd5b8054600160a01b900460a01b6001600160a01b03191615610e5357600f60405163d327ad1b60e01b8152600401610e139190614d85565b81610e7457601060405163d327ad1b60e01b8152600401610e139190614d85565b805460a09290921c600160a01b026001600160a01b0390921691909117905550565b6017546000906001600160a01b03163314610ec757600a60405163d327ad1b60e01b8152600401610e139190614d85565b6000838152600e60205260409020805462ffffff808216916001830191630100000090910416808310610f1057600b60405163d327ad1b60e01b8152600401610e139190614d85565b8354600160881b900460ff1680610f4357506000878152600f60205260409020600201546001600160a01b038781169116145b610f6357600c60405163d327ad1b60e01b8152600401610e139190614d85565b8354600160901b900460ff168015610f9857506000878152600f60205260409020600201546001600160a01b03878116911614155b15610fb957600d60405163d327ad1b60e01b8152600401610e139190614d85565b835462ffffff191662ffffff8381169182178655848116620f42408a0201919083169003610fea57610fea886130c3565b610ff489826130f8565b600b54604051635b140b8d60e11b8152600481018390526001600160a01b039091169063b628171a90602401600060405180830381600087803b15801561103a57600080fd5b505af115801561104e573d6000803e3d6000fd5b50506040518392506001600160a01b038c1691507f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688590600090a39450505050505b9392505050565b61109f8261315d565b6000828152600e60205260409020805462ffffff80821691630100000090048116908416106110e457601c60405163d327ad1b60e01b8152600401610e139190614d85565b808362ffffff16101561110d57601d60405163d327ad1b60e01b8152600401610e139190614d85565b815465ffffff0000001916630100000062ffffff851602178255600b604051859060008051602061544183398151915290600090a3808362ffffff160361115757611157846130c3565b50505050565b6111668261319a565b6111768262615bf560e21b6131c3565b6000828152600e602052604090819020906111949083906001613211565b6111b457602060405163d327ad1b60e01b8152600401610e139190614d85565b60078101829055600d5b604051849060008051602061544183398151915290600090a3505050565b60006001600160e01b0319821663152a902d60e11b1480611201575061120182613285565b92915050565b6112176301050e9760e21b6132d5565b601954600160f81b900460ff161561124557601960405163d327ad1b60e01b8152600401610e139190614d85565b61124d613300565b565b60606000805461125e90614dad565b80601f016020809104026020016040519081016040528092919081815260200182805461128a90614dad565b80156112d75780601f106112ac576101008083540402835291602001916112d7565b820191906000526020600020905b8154815290600101906020018083116112ba57829003601f168201915b5050505050905090565b60006112ec82613341565b5061120182613379565b611301828233613394565b5050565b61130e8261319a565b61131f82630d17067360e01b6131c3565b611328816133a1565b6000828152600e602052604090206001016113438282614e46565b5060055b604051839060008051602061544183398151915290600090a35050565b61136d8261319a565b61137e826301cf392560e31b6131c3565b611387816133a1565b80518190600b8111156113b057602160405163d327ad1b60e01b8152600401610e139190614d85565b60008060005b8381101561145c5760008582815181106113d2576113d2614eff565b01602001516001600160f81b0319169050600360fc1b81108015906114055750603960f81b6001600160f81b0319821611155b15611414576001925050611454565b6001600160f81b03198116601760f91b036114385783611438576001935050611454565b602360405163d327ad1b60e01b8152600401610e139190614d85565b6001016113b6565b508061147e57602260405163d327ad1b60e01b8152600401610e139190614d85565b6000868152600e602052604090206008016114998682614e46565b50600e604051879060008051602061544183398151915290600090a3505050505050565b6000818152600e60205260408120805462ffffff808216936301000000830490911692600160881b830460ff90811693600160901b810490911692600160481b9091046001600160401b031691611513886133c6565b1591505091939550919395565b6000611201620f424083614f2b565b61153f631c05cad760e01b6132d5565b61154884613410565b61155183613410565b6111578484848461343a565b61156d63118165ed60e11b6132d5565b611576816133a1565b61157f8161350b565b50565b60008061158d61223a565b6001600160a01b0316141580156116265750600d546040516217798b60e61b81526001600160a01b03868116600483015285811660248301526001600160e01b031985166044830152909116906305de62c0906064016020604051808303816000875af1158015611602573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116269190614f4d565b949350505050565b6001600160a01b038216611658576000604051633250574960e11b8152600401610e139190614596565b600061166583833361351f565b9050836001600160a01b0316816001600160a01b031614611157576040516364283d7b60e01b81526001600160a01b0380861660048301526024820184905282166044820152606401610e13565b6116bc8261319a565b6116cd826304b6ebad60e31b6131c3565b6116d6816133a1565b6000828152600e602052604090206005016116f18282614e46565b50600a611347565b6117096313efb60d60e11b6132d5565b601a54610100900460ff16801561171f57508015155b1561174057602460405163d327ad1b60e01b8152600401610e139190614d85565b61271061174d8284614f6a565b111561176f57601360405163d327ad1b60e01b8152600401610e139190614d85565b6014829055601681905560095b6040516000805160206153e183398151915290600090a25050565b6000806117a38461308e565b60006117ae85611520565b6000818152600f6020526040812060058101546004820154600383015483546001600160a01b039093169850949550919361ffff600160a01b938490048116939182900416916118049160ff9104166064614f7d565b61180e9190614f6a565b6118189190614f6a565b905061271081111561184057601360405163d327ad1b60e01b8152600401610e139190614d85565b61271061184d8288614f7d565b6118579190614f2b565b93505050509250929050565b611873631593a0b360e11b6132d5565b61187c81613410565b600980546001600160a01b0319166001600160a01b03831617905560055b6040516000805160206153e183398151915290600090a250565b6118bd86613613565b6118c68661315d565b6118cf85613410565b6000868152600f6020526040902060648411806118ec5750606482115b1561190d57601460405163d327ad1b60e01b8152600401610e139190614d85565b60008411801561192457506001600160a01b038516155b1561194557601560405163d327ad1b60e01b8152600401610e139190614d85565b60008211801561195c57506001600160a01b038316155b1561197d57601660405163d327ad1b60e01b8152600401610e139190614d85565b867f6ff7d102bb3657a26dcbbcd299d821a066718a7cf76ae7cd98279f18b74da8ac87878787876040516119b5959493929190614f94565b60405180910390a2601a5460ff1680611a4057600282015482546001600160a01b039182168983161491600091811690891614806119fa57506001600160a01b038816155b60018501549091506000906001600160a01b0388811691161480611a2557506001600160a01b038716155b9050828015611a315750815b8015611a3a5750805b93505050505b8015611ad85760008881526010602052604081205560028201805483546001600160a01b038981166001600160a01b03199290921691909117855560ff808916600160a01b9081026001600160a81b0319948516848e161717909455600186018054918816909402921690871617179055611aba8861364f565b604051889060008051602061540183398151915290600090a2611b17565b8686868686604051602001611af1959493929190614f94565b60408051601f19818403018152918152815160209283012060008b815260109093529120555b5050505050505050565b6000818152600e60205260409020600601805460609190611b4190614dad565b80601f0160208091040260200160405190810160405280929190818152602001828054611b6d90614dad565b8015611bba5780601f10611b8f57610100808354040283529160200191611bba565b820191906000526020600020905b815481529060010190602001808311611b9d57829003601f168201915b50505050509050919050565b611bcf8361319a565b611be08363329dab7360e01b6131c3565b611be98161379b565b6000838152600e602052604090208054600160301b900462ffffff168310611c2757601e60405163d327ad1b60e01b8152600401610e139190614d85565b611c30826137c0565b6000848152600983016020526040902080546001600160a01b0319166001600160a01b0392909216919091179055600c604051859060008051602061544183398151915290600090a350505050565b611c888261315d565b6000828152600e60205260409020600401611ca38282614e46565b506009611347565b611cbb63398a289560e01b6132d5565b611cc481613613565b6000818152600f602052604090206015546003820180546001600160a01b039283166001600160a01b0319808316821784556016546001600160b01b0319938416909217600160a01b61ffff938416810291909117909455601354600487018054919096169181168217865560145493161791169091021790556010604051839060008051602061544183398151915290600090a36113018261364f565b611d6b8261315d565b611d74816133a1565b6000828152600e60205260409020600601611d8f8282614e46565b50600f611347565b611db2838383604051806020016040528060008152506129a6565b505050565b611dc7632419b94160e11b6132d5565b611dd081613410565b61157f8161385e565b6060611ded651d8ccb8c8b8d60d21b6138a8565b905090565b600081815260036020526040812054600160a01b900460a01b6001600160a01b031981168203611e255750600092915050565b80604051602001611e369190614c2d565b60405160208183030381529060405280519060200120915050919050565b600061120182613341565b611e6882613613565b611e79826369d14faf60e01b613913565b611e8281613410565b6000828152600f6020526040902060020180546001600160a01b0319166001600160a01b038316179055611eb58261364f565b6002611347565b611ecc636c907b7f60e01b6132d5565b611ed581613410565b61157f81613985565b60006001600160a01b038216611f0a5760006040516322718ad960e21b8152600401610e139190614596565b506001600160a01b031660009081526004602052604090205490565b611f2e6139e7565b611f36613300565b61124d613a19565b611f4786613613565b611f58866376ee6fab60e01b613913565b611f6185613410565b8484848484604051602001611f7a959493929190614f94565b60408051601f1981840301815291815281516020928301206000898152601090935291205414611fc057601760405163d327ad1b60e01b8152600401610e139190614d85565b6000600f60008881526020019081526020016000209050858160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550848160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550838160020160146101000a81548160ff021916908360ff160217905550828160010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550818160010160146101000a81548160ff021916908360ff1602179055506000801b60106000898152602001908152602001600020819055506120b08761364f565b604051879060008051602061540183398151915290600090a250505050505050565b6000828152600f602052604081206011548291829182918291829182918291908a9060649061210b90600160a01b900460ff1683614f7d565b6121159190614f2b565b99506121218a82614fc7565b60125490915060649061213e90600160a01b900460ff168d614f7d565b6121489190614f2b565b97506121548882614fc7565b600283015490915060649061217390600160a01b900460ff1683614f7d565b61217d9190614f2b565b93506121898482614fc7565b6011546012546001600160a01b039182169b50169750955085156121b85760028201546001600160a01b031694505b83156121cc5781546001600160a01b031692505b50509295985092959890939650565b6000828152600e60205260409020805460609190600160301b900462ffffff168310612217575050604080516020810190915260008152611201565b6000838152600982016020526040902054611626906001600160a01b0316613a2b565b6000611ded6007546001600160a01b031690565b60608060608060606000600e6000888152602001908152602001600020905080600101805461227c90614dad565b80601f01602080910402602001604051908101604052809291908181526020018280546122a890614dad565b80156122f55780601f106122ca576101008083540402835291602001916122f5565b820191906000526020600020905b8154815290600101906020018083116122d857829003601f168201915b5050505050955080600201805461230b90614dad565b80601f016020809104026020016040519081016040528092919081815260200182805461233790614dad565b80156123845780601f1061235957610100808354040283529160200191612384565b820191906000526020600020905b81548152906001019060200180831161236757829003601f168201915b505050506003830154919650506001600160a01b0316806123b6576040518060200160405280600081525094506123c2565b6123bf81613a2b565b94505b8160040180546123d190614dad565b80601f01602080910402602001604051908101604052809291908181526020018280546123fd90614dad565b801561244a5780601f1061241f5761010080835404028352916020019161244a565b820191906000526020600020905b81548152906001019060200180831161242d57829003601f168201915b5050505050935081600501805461246090614dad565b80601f016020809104026020016040519081016040528092919081815260200182805461248c90614dad565b80156124d95780601f106124ae576101008083540402835291602001916124d9565b820191906000526020600020905b8154815290600101906020018083116124bc57829003601f168201915b50505050509250505091939590929450565b6124fb639523751760e01b6132d5565b61250481613410565b600a80546001600160a01b0319166001600160a01b038316179055600661189a565b61115784848484613a79565b60606001805461125e90614dad565b61255163993c0cbf60e01b6132d5565b61255a81613410565b61157f81613c40565b6125736304ecbfa560e51b6132d5565b61157f81613c62565b6125858161315d565b6000818152600e60205260409020805460ff60901b198116600160901b9182900460ff161590910217905560035b604051829060008051602061544183398151915290600090a350565b611301338383613c8d565b6125e3826133c6565b1561262a576000828152600f60205260409020600201546001600160a01b0316331461262557601a60405163d327ad1b60e01b8152600401610e139190614d85565b61265c565b61263c33306351d9665360e11b611582565b61265c57601a60405163d327ad1b60e01b8152600401610e139190614d85565b61266581613d23565b6000838152600e6020526040902060030180546001600160a01b0319166001600160a01b03929092169190911790556008611347565b601b80546126a890614dad565b80601f01602080910402602001604051908101604052809291908181526020018280546126d490614dad565b80156127215780601f106126f657610100808354040283529160200191612721565b820191906000526020600020905b81548152906001019060200180831161270457829003601f168201915b505050505081565b6127328261319a565b61274382632b2b404960e21b6131c3565b61274c816133a1565b6000828152600e6020526040902061276382613d23565b8154600160301b9081900462ffffff9081166000908152600985016020526040902080546001600160a01b0319166001600160a01b03949094169390931790925582546127b592919004166001614fda565b815462ffffff91909116600160301b0262ffffff60301b19909116178155600c6111be565b6060611ded7547656e417274373231436f726556335f456e67696e6560501b6138a8565b6128078361319a565b6128188363b1656ba360e01b6131c3565b612821816133a1565b6000838152600e602052604090208054600160301b900462ffffff16831061285f57601e60405163d327ad1b60e01b8152600401610e139190614d85565b611c3082613d23565b600c54600090821061289057601260405163d327ad1b60e01b8152600401610e139190614d85565b600c82815481106128a3576128a3614eff565b6000918252602090912001546001600160a01b031692915050565b6128c78261319a565b6128d88263b202b56560e01b6131c3565b6128e18161379b565b6000828152600e60205260409020612763826137c0565b612901826133c6565b15612948576000828152600f60205260409020600201546001600160a01b0316331461294357601a60405163d327ad1b60e01b8152600401610e139190614d85565b61297a565b61295a3330635bd827d760e11b611582565b61297a57601a60405163d327ad1b60e01b8152600401610e139190614d85565b612983816133a1565b6000828152600e6020526040902060020161299e8282614e46565b506006611347565b6129b184848461162e565b61115784848484613d49565b6129cd63bd3d10e760e01b6132d5565b601a54610100900460ff1680156129e357508015155b15612a0457602460405163d327ad1b60e01b8152600401610e139190614d85565b6064612a108284614f6a565b1115612a3257601160405163d327ad1b60e01b8152600401610e139190614d85565b6011805460ff808516600160a01b90810260ff60a01b1993841617909355601280549185169093029116179055600861177c565b612a6f8261315d565b605f811115612a9457601b60405163d327ad1b60e01b8152600401610e139190614d85565b6000828152600f60205260409020805460ff60a01b1916600160a01b60ff841602179055612ac18261364f565b6007611347565b6060612ad38261308e565b6000600e6000612ae285611520565b81526020019081526020016000206006018054612afe90614dad565b80601f0160208091040260200160405190810160405280929190818152602001828054612b2a90614dad565b8015612b775780601f10612b4c57610100808354040283529160200191612b77565b820191906000526020600020905b815481529060010190602001808311612b5a57829003601f168201915b5050505050905080612b8884613e60565b604051602001612b99929190614ffd565b604051602081830303815290604052915050919050565b612bc063cc90e72560e01b6132d5565b612bc9826133a1565b612bd281613410565b601954600160f81b900460ff1615612c0057601860405163d327ad1b60e01b8152600401610e139190614d85565b6019546001600160f81b03166000818152600f602090815260408083206002810180546001600160a01b0319166001600160a01b038816179055600e909252909120600101612c4f8582614e46565b506000828152600e60205260409020805465ffffff00000060ff60901b011916613d09601e1b600160901b01178155600601612c8c601b8261502c565b50805460ff60a01b1916600560a01b1781556015546003820180546001600160a01b039283166001600160a01b0319808316821784556016546001600160b01b0319938416909217600160a01b61ffff93841681029190911790945560135460048701805491909616918116821786556014549316179116909102179055612d158260016150f8565b601980546001600160f81b0319166001600160f81b03929092169190911790556004604051839060008051602061544183398151915290600090a36111578261364f565b601a5462010000900460ff1615612d8057612d7b8163340f0e4360e21b6131c3565b612d90565b612d9063340f0e4360e21b6132d5565b612d9981613613565b6000818152600e60205260409020805460ff60881b198116600160881b9182900460ff161590910217905560016125b3565b612dd48161319a565b612de58163db2ff86160e01b6131c3565b6000818152600e6020526040812080549091600160301b90910462ffffff169003612e2657601f60405163d327ad1b60e01b8152600401610e139190614d85565b80546009820190600090612e4890600190600160301b900462ffffff16615118565b62ffffff9081168252602082019290925260400160002080546001600160a01b0319169055815462ffffff60301b198116600160301b9182900483166000190190921602178155600c611347565b6060612ea1826133a1565b60405163e32551e760e01b815273000000000016a5a5ff2fa7799c4bee89ba59b74e9063e32551e790612ed890859060040161455d565b600060405180830381865af4158015612ef5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112019190810190615164565b6001600160a01b03918216600090815260066020908152604080832093909416825291909152205460ff1690565b6000818152600e60205260408120600781015460609283929091612f6e906138a8565b9350806008018054612f7f90614dad565b80601f0160208091040260200160405190810160405280929190818152602001828054612fab90614dad565b8015612ff85780601f10612fcd57610100808354040283529160200191612ff8565b820191906000526020600020905b815481529060010190602001808311612fdb57829003601f168201915b5050935496989297505050600160301b90940462ffffff169392505050565b61302763f23f702160e01b6132d5565b600880546001600160a01b0319166001600160a01b038316179055600461189a565b6130516139e7565b6001600160a01b03811661307b576000604051631e4fbdf760e01b8152600401610e139190614596565b61157f81613ef2565b6000611ded61223a565b600061309982613f1d565b6001600160a01b03160361157f57600360405163d327ad1b60e01b8152600401610e139190614d85565b6000818152600e602052604081208054600160481b600160881b031916600160481b426001600160401b0316021790556125b3565b6001600160a01b038216613122576000604051633250574960e11b8152600401610e139190614596565b60006131308383600061351f565b90506001600160a01b03811615611db25760006040516339e3563760e11b8152600401610e139190614596565b6000818152600f60205260409020600201546001600160a01b0316331461157f57600760405163d327ad1b60e01b8152600401610e139190614d85565b6131a3816133c6565b61157f57600560405163d327ad1b60e01b8152600401610e139190614d85565b6000828152600f60205260409020600201546001600160a01b03163314806131f157506131f1333083611582565b61130157600860405163d327ad1b60e01b8152600401610e139190614d85565b60008060005b60208160ff161015613271576000868260ff166020811061323a5761323a614eff565b1a9050801580159061324f575060808160ff16105b15613268578560ff168160ff1603613268578260010192505b50600101613217565b8360ff168260ff1614925050509392505050565b60006001600160e01b031982166380ac58cd60e01b14806132b657506001600160e01b03198216635b5e139f60e01b145b8061120157506301ffc9a760e01b6001600160e01b0319831614611201565b6132e0333083611582565b61157f57600660405163d327ad1b60e01b8152600401610e139190614d85565b601954600160f81b900460ff1661124d57601980546001600160f81b0316600160f81b17905560016040516000805160206153e183398151915290600090a2565b60008061334d83613f1d565b90506001600160a01b03811661120157604051637e27328960e01b815260048101849052602401610e13565b6000908152600560205260409020546001600160a01b031690565b611db28383836001613f38565b805160000361157f57600160405163d327ad1b60e01b8152600401610e139190614d85565b60006133d182613613565b6000828152600e6020526040902054600160481b90046001600160401b03168015808061162657506224ea006134078342614fc7565b10949350505050565b6001600160a01b03811661157f57600060405163d327ad1b60e01b8152600401610e139190614d85565b601a54610100900460ff161561348f576001600160a01b03821615158061346957506001600160a01b03811615155b1561348a57602460405163d327ad1b60e01b8152600401610e139190614d85565b6134a1565b61349882613410565b6134a181613410565b601280546001600160a01b038085166001600160a01b0319928316179092556015805484841690831617905560118054878416908316179055601380549286169290911691909117905560075b6040516000805160206153e183398151915290600090a250505050565b601b6135178282614e46565b50600261189a565b60008061352b84613f1d565b90506001600160a01b0383161561354757613547818486614035565b6001600160a01b0381161561358557613564600085600080613f38565b6001600160a01b038116600090815260046020526040902080546000190190555b6001600160a01b038516156135b4576001600160a01b0385166000908152600460205260409020805460010190555b60008481526003602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b60185481108061362e57506019546001600160f81b03168110155b1561157f57600460405163d327ad1b60e01b8152600401610e139190614d85565b6000818152600f60209081526040808320601c5482516101008101845260038301546001600160a01b03818116835261ffff600160a01b92839004811697840197909752600480860154808316858901528390049097166060840152845460ff90839004811660808501526002860154821660a0850152600186015480831660c08601529290920490911660e08301529351631718245360e21b81529295949390911692635c60914c926137049291016151ac565b6020604051808303816000875af1158015613723573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137479190615234565b6005830180546001600160a01b0319166001600160a01b0383169081179091556040519192509084907f301670c9279b1d4319606681ed95e193d888fddba44d836b9e8d5585d8cc47b590600090a3505050565b805160000361157f57600260405163d327ad1b60e01b8152600401610e139190614d85565b60008060008051602061542183398151915230846040516020016137e693929190615251565b60405160208183030381529060405290508051602082016000f091506001600160a01b0382166138585760405162461bcd60e51b815260206004820152601e60248201527f436f6e7472616374417353746f726167653a205772697465204572726f7200006044820152606401610e13565b50919050565b601780546001600160a01b0319166001600160a01b0383169081179091556040517fad0f299ec81a386c98df0ac27dae11dd020ed1b56963c53a7292e7a3a314539a90600090a250565b606060005b828160ff16602081106138c2576138c2614eff565b1a60f81b6001600160f81b031916158015906138e1575060208160ff16105b156138f857806138f0816152bc565b9150506138ad565b60405191506040820160405280825282602083015250919050565b61391e333083611582565b15613927575050565b600061393161223a565b6001600160a01b031614801561396057506000828152600f60205260409020600201546001600160a01b031633145b15613969575050565b600960405163d327ad1b60e01b8152600401610e139190614d85565b600b80546001600160a01b0383166001600160a01b03199182168117909255600c80546001810182556000919091527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70180549091169091179055600361189a565b336139f061223a565b6001600160a01b03161461124d573360405163118cdaa760e01b8152600401610e139190614596565b613a216139e7565b61124d6000613ef2565b601d54604051630eacc5e760e31b81526060916001600160a01b0316906375662f3890613a5c908590600401614596565b600060405180830381865afa158015612ef5573d6000803e3d6000fd5b600a54600160a01b900460ff1615613aa757602560405163d327ad1b60e01b8152600401610e139190614d85565b600a8054600160a01b60ff60a01b199182161790915560118054909116600560a11b17905560fa601455610140840151613ae257600a613ae5565b60005b601260146101000a81548160ff021916908360ff160217905550836101400151613b105760fa613b13565b60005b60ff1660165583516020850151613b2a919061408b565b60e08401516001600160a01b031615613b4a57613b4a8460e0015161385e565b613b578460c00151613c62565b613b6081613c40565b610120840151601a805461014087015161016088015161ffff1990921693151561ff0019169390931761010093151584021762ff0000191662010000911515919091021790558401516001600160f81b031660185560408401516060850151613bcc919081908061343a565b613bd98460a00151613985565b613be283613ef2565b613c1482613bef306140ff565b604051602001613c009291906152db565b60405160208183030381529060405261350b565b610100840151601980546001600160f81b0319166001600160f81b0390921691909117905560006134ee565b601d80546001600160a01b0319166001600160a01b038316179055600b61189a565b613c6b81613410565b601c80546001600160a01b0319166001600160a01b038316179055600a61189a565b6001600160a01b038216613cb65781604051630b61174360e31b8152600401610e139190614596565b6001600160a01b03838116600081815260066020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b60008060008051602061542183398151915230846040516020016137e693929190615316565b6001600160a01b0383163b1561115757604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290613d8b90339088908790879060040161536f565b6020604051808303816000875af1925050508015613dc6575060408051601f3d908101601f19168201909252613dc3918101906153ac565b60015b613e26573d808015613df4576040519150601f19603f3d011682016040523d82523d6000602084013e613df9565b606091505b508051600003613e1e5783604051633250574960e11b8152600401610e139190614596565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b14613e595783604051633250574960e11b8152600401610e139190614596565b5050505050565b60606000613e6d83614115565b60010190506000816001600160401b03811115613e8c57613e8c6146b7565b6040519080825280601f01601f191660200182016040528015613eb6576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084613ec057509392505050565b613efb816141eb565b600d80546001600160a01b0319166001600160a01b0392909216919091179055565b6000908152600360205260409020546001600160a01b031690565b8080613f4c57506001600160a01b03821615155b15614005576000613f5c84613341565b90506001600160a01b03831615801590613f885750826001600160a01b0316816001600160a01b031614155b8015613f9b5750613f998184612f1d565b155b15613fbb578260405163a9fbf51f60e01b8152600401610e139190614596565b81156140035783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260056020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b61404083838361423d565b611db2576001600160a01b03831661406e57604051637e27328960e01b815260048101829052602401610e13565b818160405163177e802f60e01b8152600401610e139291906148fa565b60025460ff16156140d45760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b6044820152606401610e13565b60006140e08382614e46565b5060016140ed8282614e46565b50506002805460ff1916600117905550565b60606112016001600160a01b03831660146142a2565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106141545772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6904ee2d6d415b85acef8160201b831061417e576904ee2d6d415b85acef8160201b830492506020015b662386f26fc10000831061419c57662386f26fc10000830492506010015b6305f5e10083106141b4576305f5e100830492506008015b61271083106141c857612710830492506004015b606483106141da576064830492506002015b600a83106112015760010192915050565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60006001600160a01b038316158015906116265750826001600160a01b0316846001600160a01b0316148061427757506142778484612f1d565b806116265750826001600160a01b031661429083613379565b6001600160a01b031614949350505050565b60608260006142b2846002614f7d565b6142bd906002614f6a565b6001600160401b038111156142d4576142d46146b7565b6040519080825280601f01601f1916602001820160405280156142fe576020820181803683370190505b509050600360fc1b8160008151811061431957614319614eff565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061434857614348614eff565b60200101906001600160f81b031916908160001a905350600061436c856002614f7d565b614377906001614f6a565b90505b60018111156143ef576f181899199a1a9b1b9c1cb0b131b232b360811b83600f16601081106143ab576143ab614eff565b1a60f81b8282815181106143c1576143c1614eff565b60200101906001600160f81b031916908160001a90535060049290921c916143e8816153c9565b905061437a565b5081156116265760405163e22e27eb60e01b81526004810186905260248101859052604401610e13565b6000806040838503121561442c57600080fd5b50508035926020909101359150565b6001600160a01b038116811461157f57600080fd5b803561445b8161443b565b919050565b60008060006060848603121561447557600080fd5b83356144808161443b565b92506020840135915060408401356144978161443b565b809150509250925092565b600080604083850312156144b557600080fd5b82359150602083013562ffffff811681146144cf57600080fd5b809150509250929050565b6001600160e01b03198116811461157f57600080fd5b60006020828403121561450257600080fd5b813561108f816144da565b60005b83811015614528578181015183820152602001614510565b50506000910152565b6000815180845261454981602086016020860161450d565b601f01601f19169290920160200192915050565b60208152600061108f6020830184614531565b60006020828403121561458257600080fd5b5035919050565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b600080604083850312156145bd57600080fd5b82356145c88161443b565b946020939093013593505050565b6000610160820190506145ea828451614589565b60208301516145fe602084018260ff169052565b5060408301516146116040840182614589565b506060830151614626606084018260ff169052565b5060808301516146396080840182614589565b5060a083015161464e60a084018260ff169052565b5060c083015161466160c0840182614589565b5060e083015161467760e084018261ffff169052565b506101008084015161468b82850182614589565b50506101208381015161ffff1690830152610140808401516146af82850182614589565b505092915050565b634e487b7160e01b600052604160045260246000fd5b60405161018081016001600160401b03811182821017156146f0576146f06146b7565b60405290565b604051601f8201601f191681016001600160401b038111828210171561471e5761471e6146b7565b604052919050565b60006001600160401b0382111561473f5761473f6146b7565b50601f01601f191660200190565b600082601f83011261475e57600080fd5b813561477161476c82614726565b6146f6565b81815284602083860101111561478657600080fd5b816020850160208301376000918101602001919091529392505050565b600080604083850312156147b657600080fd5b8235915060208301356001600160401b038111156147d357600080fd5b6147df8582860161474d565b9150509250929050565b600080600080608085870312156147ff57600080fd5b843561480a8161443b565b9350602085013561481a8161443b565b9250604085013561482a8161443b565b9150606085013561483a8161443b565b939692955090935050565b60006020828403121561485757600080fd5b81356001600160401b0381111561486d57600080fd5b6116268482850161474d565b60008060006060848603121561488e57600080fd5b83356148998161443b565b925060208401356148a98161443b565b91506040840135614497816144da565b6000806000606084860312156148ce57600080fd5b83356148d98161443b565b925060208401356148e98161443b565b929592945050506040919091013590565b6001600160a01b03929092168252602082015260400190565b60006020828403121561492557600080fd5b813561108f8161443b565b60008060008060008060c0878903121561494957600080fd5b86359550602087013561495b8161443b565b9450604087013561496b8161443b565b93506060870135925060808701356149828161443b565b8092505060a087013590509295509295509295565b6000806000606084860312156149ac57600080fd5b833592506020840135915060408401356001600160401b038111156149d057600080fd5b6149dc8682870161474d565b9150509250925092565b600080604083850312156149f957600080fd5b8235915060208301356144cf8161443b565b60a081526000614a1e60a0830188614531565b8281036020840152614a308188614531565b90508281036040840152614a448187614531565b90508281036060840152614a588186614531565b90508281036080840152614a6c8185614531565b98975050505050505050565b80356001600160f81b038116811461445b57600080fd5b801515811461157f57600080fd5b803561445b81614a8f565b60008060008060808587031215614abe57600080fd5b84356001600160401b0380821115614ad557600080fd5b908601906101808289031215614aea57600080fd5b614af26146cd565b823582811115614b0157600080fd5b614b0d8a82860161474d565b825250602083013582811115614b2257600080fd5b614b2e8a82860161474d565b602083015250614b4060408401614450565b6040820152614b5160608401614450565b6060820152614b6260808401614450565b6080820152614b7360a08401614450565b60a0820152614b8460c08401614450565b60c0820152614b9560e08401614450565b60e0820152610100614ba8818501614a78565b90820152610120614bba848201614a9d565b90820152610140614bcc848201614a9d565b90820152610160614bde848201614a9d565b908201529550614bf060208801614450565b94506040870135915080821115614c0657600080fd5b50614c138782880161474d565b925050614c2260608601614450565b905092959194509250565b6001600160a01b031991909116815260200190565b60008060408385031215614c5557600080fd5b8235614c608161443b565b915060208301356144cf81614a8f565b60008060008060808587031215614c8657600080fd5b8435614c918161443b565b93506020850135614ca18161443b565b92506040850135915060608501356001600160401b03811115614cc357600080fd5b614ccf8782880161474d565b91505092959194509250565b60008060408385031215614cee57600080fd5b82356001600160401b03811115614d0457600080fd5b614d108582860161474d565b92505060208301356144cf8161443b565b60008060408385031215614d3457600080fd5b8235614d3f8161443b565b915060208301356144cf8161443b565b606081526000614d626060830186614531565b8281036020840152614d748186614531565b915050826040830152949350505050565b6020810160268310614da757634e487b7160e01b600052602160045260246000fd5b91905290565b600181811c90821680614dc157607f821691505b60208210810361385857634e487b7160e01b600052602260045260246000fd5b601f821115611db2576000816000526020600020601f850160051c81016020861015614e0a5750805b601f850160051c820191505b81811015614e2957828155600101614e16565b505050505050565b600019600383901b1c191660019190911b1790565b81516001600160401b03811115614e5f57614e5f6146b7565b614e7381614e6d8454614dad565b84614de1565b602080601f831160018114614ea25760008415614e905750858301515b614e9a8582614e31565b865550614e29565b600085815260208120601f198616915b82811015614ed157888601518255948401946001909101908401614eb2565b5085821015614eef5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082614f4857634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215614f5f57600080fd5b815161108f81614a8f565b8082018082111561120157611201614f15565b808202811582820484141761120157611201614f15565b6001600160a01b039586168152938516602085015260408401929092529092166060820152608081019190915260a00190565b8181038181111561120157611201614f15565b62ffffff818116838216019080821115614ff657614ff6614f15565b5092915050565b6000835161500f81846020880161450d565b83519083019061502381836020880161450d565b01949350505050565b818103615037575050565b6150418254614dad565b6001600160401b03811115615058576150586146b7565b61506681614e6d8454614dad565b6000601f82116001811461509457600083156150825750848201545b61508c8482614e31565b855550613e59565b600085815260209020601f19841690600086815260209020845b838110156150ce57828601548255600195860195909101906020016150ae565b5085831015614eef5793015460001960f8600387901b161c19169092555050600190811b01905550565b6001600160f81b03818116838216019080821115614ff657614ff6614f15565b62ffffff828116828216039080821115614ff657614ff6614f15565b600061514261476c84614726565b905082815283838301111561515657600080fd5b61108f83602083018461450d565b60006020828403121561517657600080fd5b81516001600160401b0381111561518c57600080fd5b8201601f8101841361519d57600080fd5b61162684825160208401615134565b60006101008201905060018060a01b03808451168352602084015161ffff808216602086015282604087015116604086015280606087015116606086015250505060ff608084015116608083015260a083015161520c60a0840182614589565b5060c083015161521f60c0840182614589565b5060e0830151614ff660e084018260ff169052565b60006020828403121561524657600080fd5b815161108f8161443b565b6a600b5981380380925939f360a81b8152607f60f91b600b820152600c81018490526000602c8201819052606084901b6001600160601b0319166038830152600160f81b604c83015282516152ad81604d85016020870161450d565b91909101604d01949350505050565b600060ff821660ff81036152d2576152d2614f15565b60010192915050565b600083516152ed81846020880161450d565b83519083019061530181836020880161450d565b602f60f81b9101908152600101949350505050565b6a600b5981380380925939f360a81b8152607f60f91b600b820152600c81018490526000602c8201819052606084901b6001600160601b0319166038830152604c820181905282516152ad81604d85016020870161450d565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906153a290830184614531565b9695505050505050565b6000602082840312156153be57600080fd5b815161108f816144da565b6000816153d8576153d8614f15565b50600019019056fe8b810f233ce7ee6e962ab4d98bf0277751de1f5589de3dcc812ac2047994d009c582d05e1da854143bd3271ef4529d79cf5a69fc6057ae320f357acfd291b73842797465636f646553746f726167655f56322e302e305f5f5f5f5f5f5f5f5f20b96a30340e86d03ce4be42f94ac02d7b27b4a4cdae942beb69026718dfe66afca26469706673582212208055dc95b2c5e973b7cbfa46ce14165ba0166b1dab8925c5fb13ac1c0c993cf564736f6c63430008160033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.