账户
0x48...02b7
EVOPIX

EVOPIX

US$0.00
此合同的源代码已经过验证!
合同元数据
编译器
0.8.17+commit.8df45f5f
语言
Solidity
合同源代码
文件 1 的 49:AccessControl.sol
合同源代码
文件 2 的 49:AccessControlEnumerable.sol
合同源代码
文件 3 的 49:Address.sol
合同源代码
文件 4 的 49:BaseSellable.sol
合同源代码
文件 5 的 49:BaseTokenURI.sol
合同源代码
文件 6 的 49:BytecodeStorage.sol
合同源代码
文件 7 的 49:Bytes32Strings.sol
合同源代码
文件 8 的 49:Context.sol
合同源代码
文件 9 的 49:DefaultOperatorFilterer.sol
合同源代码
文件 10 的 49:ECDSA.sol
合同源代码
文件 11 的 49:ERC165.sol
合同源代码
文件 12 的 49:ERC2981.sol
合同源代码
文件 13 的 49:ERC4906.sol
合同源代码
文件 14 的 49:ERC721A.sol
合同源代码
文件 15 的 49:ERC721ACommon.sol
合同源代码
文件 16 的 49:EntropyOracle.sol
合同源代码
文件 17 的 49:EnumerableSet.sol
合同源代码
文件 18 的 49:EvolvingPixels.sol
// SPDX-License-Identifier: MIT
// Copyright 2023 Proof Holdings Inc.
pragma solidity >=0.8.17;

import {Strings} from "openzeppelin-contracts/utils/Strings.sol";
import {IERC721Metadata} from "openzeppelin-contracts/token/ERC721/extensions/IERC721Metadata.sol";
import {GenArt721CoreV3_Engine_Flex_PROOF} from "artblocks-contracts/GenArt721CoreV3_Engine_Flex_PROOF.sol";

import {AccessControlEnumerable, ERC721ACommon} from "ethier/erc721/ERC721ACommon.sol";
import {ERC721A, BaseTokenURI, ERC721ACommonBaseTokenURI} from "ethier/erc721/BaseTokenURI.sol";
import {OperatorFilterOS} from "ethier/erc721/OperatorFilterOS.sol";
import {ERC4906} from "ethier/erc721/ERC4906.sol";

import {SellableERC721ACommon} from "proof/sellers/sellable/SellableERC721ACommon.sol";
import {Seller} from "proof/sellers/base/Seller.sol";
import {IEntropyOracleV2} from "proof/entropy/IEntropyOracleV2.sol";
import {artblocksTokenID} from "proof/artblocks/TokenIDMapping.sol";
import {IGenArt721CoreContractV3_Mintable} from "proof/artblocks/IGenArt721CoreContractV3_Mintable.sol";

import {SettablePrimaryRevenueForwarder} from "./PrimaryRevenueForwarder.sol";
import {ProjectsConfig} from "./ProjectsConfig.sol";
import {TokenInfoManager} from "./TokenInfoManager.sol";
import {Randomiser} from "./Randomiser.sol";

/**
 * @notice PROOF Curated: Evolving Pixels.
 * @author David Huber (@cxkoda)
 * @custom:reviewer Arran Schlosberg (@divergencearran)
 */
contract EvolvingPixels is
    SellableERC721ACommon,
    SettablePrimaryRevenueForwarder,
    TokenInfoManager,
    ERC721ACommonBaseTokenURI,
    OperatorFilterOS,
    Randomiser,
    ProjectsConfig
{
    // =================================================================================================================
    //                          Errors
    // =================================================================================================================

    /**
     * @notice Thrown if the number of requested purchases exceeds the number of remaining tokens.
     */
    error ExceedingMaxTotalSupply(uint256 num, uint256 numLeft);

    /**
     * @notice Thrown if the contract owner attempts to mint the reserve twice.
     */
    error DontGetGreedy();

    // =================================================================================================================
    //                          Types
    // =================================================================================================================

    /**
     * @notice Encodes a stage of the sale.
     */
    enum Stage {
        Closed,
        TokenGated,
        SignatureGated,
        Public
    }

    // =================================================================================================================
    //                          Constants
    // =================================================================================================================

    /**
     * @notice The ArtBlocks engine flex contract.
     */
    GenArt721CoreV3_Engine_Flex_PROOF public immutable flex;

    /**
     * @notice The ArtBlocks engine flex contract or a minter multiplexer.
     */
    IGenArt721CoreContractV3_Mintable public immutable flexMintGateway;

    // =================================================================================================================
    //                          Storage
    // =================================================================================================================

    /**
     * @notice The stage of the sale.
     */
    Stage public stage;

    /**
     * @notice Flag indicating whether the owner reserve has been minted.
     */
    bool internal _reserveMinted;

    /**
     * @notice The number of tokens minted per project.
     */
    uint8[_NUM_PROJECTS] public numPurchasedPerProject;

    /**
     * @notice The seller contracts for different contract stages.
     */
    mapping(Stage => Seller) public stageSellers;

    // =================================================================================================================
    //                          Construction
    // =================================================================================================================

    struct ConstructorParams {
        address admin;
        address steerer;
        address payable primaryReceiver;
        address payable secondaryReceiver;
        string baseTokenURI;
        IEntropyOracleV2 entropyOracle;
        GenArt721CoreV3_Engine_Flex_PROOF flex;
        IGenArt721CoreContractV3_Mintable flexMintGateway;
    }

    constructor(ConstructorParams memory params)
        ERC721ACommon(
            params.admin,
            params.steerer,
            "PROOF Curated: Evolving Pixels",
            "EVOPIX",
            params.secondaryReceiver,
            750
        )
        BaseTokenURI(params.baseTokenURI)
        Randomiser(params.entropyOracle)
    {
        flex = params.flex;
        flexMintGateway = params.flexMintGateway;
        _setPrimaryReceiver(params.primaryReceiver);
        assert(maxTotalSupply == 891);
    }

    // =================================================================================================================
    //                          Selling
    // =================================================================================================================

    /**
     * @inheritdoc SellableERC721ACommon
     */
    function _handleSale(address to, uint64 num, bytes calldata data) internal virtual override {
        if (num + _totalMinted() > maxTotalSupply) {
            revert ExceedingMaxTotalSupply(num, maxTotalSupply - _totalMinted());
        }

        _forwardRevenue(msg.value);
        _commitAndRequestEntropy(_nextTokenId(), num);
        SellableERC721ACommon._handleSale(to, num, data);
    }

    /**
     * @inheritdoc Randomiser
     */
    function _assignProject(uint256 tokenId, uint8 projectId) internal virtual override {
        uint8 edition = numPurchasedPerProject[projectId]++;
        if (_isLongformProject(projectId)) {
            flexMintGateway.mint_Ecf(address(this), _artblocksProjectId(projectId), address(this));
        }
        _setTokenInfo(tokenId, projectId, edition);
    }

    /**
     * @inheritdoc ERC721A
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        TokenInfo memory info = _tokenInfo(tokenId);

        if (!info.revealed) {
            return string.concat(_baseURI(), "placeholder/", Strings.toString(tokenId));
        }

        if (_projectType(info.projectId) == ProjectType.Curated) {
            return string.concat(_baseURI(), "curated/", Strings.toString(tokenId));
        }

        return flex.tokenURI(artblocksTokenID(_artblocksProjectId(info.projectId), info.edition));
    }

    /**
     * @notice Returns all tokenIds for a given project.
     * @dev Intended for front-end consumption and not optimised for gas.
     */
    function tokenIdsByProjectId(uint8 projectId) external view returns (uint256[] memory) {
        uint256[] memory tokenIds = new uint256[](numPurchasedPerProject[projectId]);

        uint256 cursor;
        uint256 num = totalSupply();
        for (uint256 i = 0; i < num; ++i) {
            if (_tokenInfo(i).projectId == projectId) {
                tokenIds[cursor++] = i;
            }
        }

        return tokenIds;
    }

    // =================================================================================================================
    //                          Steering
    // =================================================================================================================

    /**
     * @notice Mints the owner reserve.
     */
    function ownerMint(address to) external onlyRole(DEFAULT_STEERING_ROLE) {
        if (_reserveMinted) {
            revert DontGetGreedy();
        }
        _reserveMinted = true;

        uint256 tokenId = _nextTokenId();
        _mint(to, _NUM_PROJECTS);

        for (uint8 projectId = 0; projectId < _NUM_PROJECTS; ++projectId) {
            _assignProject(tokenId, projectId);
            ++tokenId;
        }
    }

    /**
     * @notice Sets the seller contract for a given stage.
     */
    function setStageSeller(Stage stage_, Seller seller) external onlyRole(DEFAULT_STEERING_ROLE) {
        stageSellers[stage_] = seller;
    }

    /**
     *
     * @notice Sets the entropy oracle contract.
     */
    function setEntropyOracle(IEntropyOracleV2 newOracle) external onlyRole(DEFAULT_STEERING_ROLE) {
        entropyOracle = newOracle;
    }

    /**
     * @notice Changes the primary revenue receiver.
     */
    function setStage(Stage stage_) external onlyRole(DEFAULT_STEERING_ROLE) {
        _setStage(stage_);
    }

    function _setStage(Stage stage_) internal {
        stage = stage_;
        _revokeAllSellers();
        address seller = address(stageSellers[stage_]);
        if (seller != address(0)) {
            _grantRole(AUTHORISED_SELLER_ROLE, seller);
        }
    }

    // =================================================================================================================
    //                          Inheritance resolution
    // =================================================================================================================

    /**
     * @notice Helper function that returns true if the token belongs to a longform project.
     */
    function _isLongformToken(uint256 tokenId) internal view virtual returns (bool) {
        return _isLongformProject(_tokenInfo(tokenId).projectId);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(ERC4906, ERC721ACommon, AccessControlEnumerable, ERC721ACommonBaseTokenURI, SellableERC721ACommon)
        returns (bool)
    {
        return ERC721ACommonBaseTokenURI.supportsInterface(interfaceId) || ERC4906.supportsInterface(interfaceId);
    }

    function _baseURI() internal view virtual override(ERC721A, ERC721ACommonBaseTokenURI) returns (string memory) {
        return ERC721ACommonBaseTokenURI._baseURI();
    }

    function setApprovalForAll(address operator, bool approved) public virtual override(ERC721A, OperatorFilterOS) {
        ERC721A.setApprovalForAll(operator, approved);
    }

    function approve(address operator, uint256 tokenId) public payable virtual override(ERC721A, OperatorFilterOS) {
        if (_isLongformToken(tokenId)) {
            ERC721A.approve(operator, tokenId);
        } else {
            OperatorFilterOS.approve(operator, tokenId);
        }
    }

    function transferFrom(address from, address to, uint256 tokenId)
        public
        payable
        virtual
        override(ERC721A, OperatorFilterOS)
    {
        if (_isLongformToken(tokenId)) {
            ERC721A.transferFrom(from, to, tokenId);
        } else {
            OperatorFilterOS.transferFrom(from, to, tokenId);
        }
    }

    function safeTransferFrom(address from, address to, uint256 tokenId)
        public
        payable
        virtual
        override(ERC721A, OperatorFilterOS)
    {
        if (_isLongformToken(tokenId)) {
            ERC721A.safeTransferFrom(from, to, tokenId);
        } else {
            OperatorFilterOS.safeTransferFrom(from, to, tokenId);
        }
    }

    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data)
        public
        payable
        virtual
        override(ERC721A, OperatorFilterOS)
    {
        if (_isLongformToken(tokenId)) {
            ERC721A.safeTransferFrom(from, to, tokenId, data);
        } else {
            OperatorFilterOS.safeTransferFrom(from, to, tokenId, data);
        }
    }

    function _projectSizes() internal pure virtual override(ProjectsConfig, Randomiser) returns (uint256[] memory) {
        return ProjectsConfig._projectSizes();
    }
}
合同源代码
文件 19 的 49:GenArt721CoreV3_Engine_Flex_PROOF.sol
合同源代码
文件 20 的 49:IAccessControlEnumerable.sol
合同源代码
文件 21 的 49:IAdminACLV0.sol
合同源代码
文件 22 的 49:IDependencyRegistryCompatibleV0.sol
合同源代码
文件 23 的 49:IERC165.sol
合同源代码
文件 24 的 49:IERC2981.sol
合同源代码
文件 25 的 49:IERC721.sol
合同源代码
文件 26 的 49:IERC721Metadata.sol
合同源代码
文件 27 的 49:IERC721Receiver.sol
合同源代码
文件 28 的 49:IEngineRegistryV0.sol
合同源代码
文件 29 的 49:IEntropyOracle.sol
合同源代码
文件 30 的 49:IEntropyOracleV2.sol
合同源代码
文件 31 的 49:IGenArt721CoreContractV3_Base.sol
合同源代码
文件 32 的 49:IGenArt721CoreContractV3_Engine.sol
合同源代码
文件 33 的 49:IGenArt721CoreContractV3_Engine_Flex.sol
合同源代码
文件 34 的 49:IGenArt721CoreContractV3_Mintable.sol
合同源代码
文件 35 的 49:IOperatorFilterRegistry.sol
合同源代码
文件 36 的 49:IRandomizerV2.sol
合同源代码
文件 37 的 49:ISellable.sol
合同源代码
文件 38 的 49:Ownable.sol
合同源代码
文件 39 的 49:PRNG.sol
合同源代码
文件 40 的 49:PrimaryRevenueForwarder.sol
// SPDX-License-Identifier: MIT
// Copyright 2023 Proof Holdings Inc.
pragma solidity >=0.8.17;

import {Address} from "openzeppelin-contracts/utils/Address.sol";
import {AccessControlEnumerable} from "ethier/erc721/ERC721ACommon.sol";

contract PrimaryRevenueForwarder {
    using Address for address payable;

    /**
     * @notice The primary revenue receiver.
     */
    address payable private _primaryReceiver;

    /**
     * @notice Changes the primary revenue receiver.
     */
    function _setPrimaryReceiver(address payable newReceiver) internal {
        _primaryReceiver = newReceiver;
    }

    /**
     * @notice Returns the primary revenue receiver.
     */
    function primaryReceiver() public view returns (address payable) {
        return _primaryReceiver;
    }

    /**
     * @notice Forwards revenue to the primary receiver.
     */
    function _forwardRevenue(uint256 value) internal {
        _primaryReceiver.sendValue(value);
    }
}

contract SettablePrimaryRevenueForwarder is PrimaryRevenueForwarder, AccessControlEnumerable {
    /**
     * @notice Changes the primary revenue receiver.
     */
    function setPrimaryReceiver(address payable newReceiver) external onlyRole(DEFAULT_STEERING_ROLE) {
        _setPrimaryReceiver(newReceiver);
    }
}
合同源代码
文件 41 的 49:ProjectsConfig.sol
// SPDX-License-Identifier: MIT
// Copyright 2023 Proof Holdings Inc.
pragma solidity >=0.8.17;

/**
 * @notice PROOF Curated: Evolving Pixels - Projects configuration.
 * @author David Huber (@cxkoda)
 * @custom:reviewer Arran Schlosberg (@divergencearran)
 */
contract ProjectsConfig {
    /**
     * @notice The number of longform projects.
     */
    uint8 internal constant _NUM_LONGFORM_PROJECTS = 4;

    /**
     * @notice The number of pre-curated projects.
     */
    uint8 internal constant _NUM_CURATED_PROJECTS = 6;

    /**
     * @notice The total number of projects.
     */
    uint8 public constant _NUM_PROJECTS = _NUM_LONGFORM_PROJECTS + _NUM_CURATED_PROJECTS;

    /**
     * @notice Returns the ArtBlocks engine project IDs for the longform projects.
     */
    function artblocksProjectIds() external pure returns (uint8[_NUM_LONGFORM_PROJECTS] memory) {
        return _artblocksProjectIds();
    }

    /**
     * @notice Returns the number of projects than can be minted per project.
     */
    function projectSizes() external pure virtual returns (uint256[] memory) {
        return _projectSizes();
    }

    /**
     * @notice Returns the ArtBlocks engine project IDs for the longform projects.
     */
    function _artblocksProjectIds() internal pure virtual returns (uint8[_NUM_LONGFORM_PROJECTS] memory) {
        return [1, 3, 2, 4];
    }

    /**
     * @notice Returns the number of projects than can be minted per project.
     */
    function _projectSizes() internal pure virtual returns (uint256[] memory) {
        uint256[] memory sizes = new uint256[](_NUM_PROJECTS);
        // Longform
        sizes[0] = 100; // Fingacode
        sizes[1] = 19; // Lars Wander
        sizes[2] = 150; // Juan Rodriguez Garcia
        sizes[3] = 100; // Nan Zhao + Xin Liu
        // Curated
        sizes[4] = 150; // Cory Haber
        sizes[5] = 75; // Dean Blacc
        sizes[6] = 32; // Entangled Others
        sizes[7] = 101; // Helena Sarin
        sizes[8] = 64; // Ivona Tau
        sizes[9] = 100; // Sasha Stiles
        return sizes;
    }

    /**
     * @notice The different types of projects.
     */
    enum ProjectType {
        Longform,
        Curated
    }

    /**
     * @notice Returns the project type for a given project ID.
     */
    function _projectType(uint8 projectId) internal pure returns (ProjectType) {
        if (projectId < _NUM_LONGFORM_PROJECTS) return ProjectType.Longform;

        return ProjectType.Curated;
    }

    /**
     * @notice Returns true iff the project is a longform project.
     */
    function _isLongformProject(uint8 projectId) internal pure virtual returns (bool) {
        return _projectType(projectId) == ProjectType.Longform;
    }

    /**
     * @notice Returns the ArtBlocks engine project ID for a given EvolvingPixels project ID.
     * @dev Reverts if the project is not long-form.
     */
    function _artblocksProjectId(uint8 projectId) internal pure returns (uint256) {
        assert(_isLongformProject(projectId));
        return _artblocksProjectIds()[projectId];
    }
}
合同源代码
文件 42 的 49:PurchaseExecuter.sol
合同源代码
文件 43 的 49:Randomiser.sol
// SPDX-License-Identifier: MIT
// Copyright 2023 Proof Holdings Inc.
pragma solidity >=0.8.17;

import {SafeCast} from "openzeppelin-contracts/utils/math/SafeCast.sol";
import {Math} from "openzeppelin-contracts/utils/math/Math.sol";

import {NextShuffler} from "ethier/random/NextShuffler.sol";
import {PRNG} from "ethier/random/PRNG.sol";
import {ERC4906} from "ethier/erc721/ERC4906.sol";

import {IEntropyConsumer, IEntropyOracleV2} from "proof/entropy/EntropyOracleV2.sol";

import {TokenInfoManager} from "./TokenInfoManager.sol";

/**
 * @notice Project randomisation module for Evolving Pixels.
 * @author David Huber (@cxkoda)
 * @custom:reviewer Arran Schlosberg (@divergencearran)
 */
abstract contract Randomiser is ERC4906, IEntropyConsumer, TokenInfoManager {
    using NextShuffler for NextShuffler.State;
    using PRNG for PRNG.Source;

    // =================================================================================================================
    //                          Errors
    // =================================================================================================================

    /**
     * @notice Thrown when the caller is not the oracle.
     */
    error CallerNotOracle();

    // =================================================================================================================
    //                          Types
    // =================================================================================================================

    /**
     * @notice Encodes a range of tokens [start,end) that are revealed in the same entropy oracle callback.
     * @param revealed Whether the tokens in this range have already been revealed.
     * @param start The first token ID in the range (included).
     * @param end The last token ID in the range (excluded).
     */
    struct RevealBatch {
        bool revealed;
        uint64 start;
        uint64 end;
    }

    // =================================================================================================================
    //                          Constants
    // =================================================================================================================

    /**
     * @notice The maximum number of tokens that can be revealed in a single entropy oracle callback.
     * @dev With <200k gas per reveal, this puts us at a <10M gas per callback.
     */
    uint256 internal constant _MAX_TOKENS_PER_ENTROPY_CALLBACK = 50;

    /**
     * @notice The maximum supply of tokens.
     */
    uint64 public immutable maxTotalSupply;

    // =================================================================================================================
    //                          Storage
    // =================================================================================================================

    /**
     * @notice The entropy oracle.
     */
    IEntropyOracleV2 public entropyOracle;

    /**
     * @notice The shuffler used to sample project IDs via pool sampling during reveal.
     */
    NextShuffler.State internal _shuffler;

    /**
     * @notice The token ranges awaiting reveal keyed by block number and callback ID.
     */
    mapping(uint256 => mapping(uint96 => RevealBatch)) internal _batches;

    /**
     * @notice The current callback ID for a given block number.
     * @dev This counter will be increased if the number of tokens to be revealed exceeds the maximum number of tokens
     * per callback.
     */
    mapping(uint256 => uint96) internal _currentCallbackId;

    // =================================================================================================================
    //                          Construction
    // =================================================================================================================

    constructor(IEntropyOracleV2 oracle) {
        entropyOracle = oracle;

        uint64 total;
        uint256[] memory sizes = _projectSizes();
        for (uint256 i = 0; i < sizes.length; ++i) {
            total += uint64(sizes[i]);
        }
        maxTotalSupply = total;
        _shuffler.init(total);
    }

    // =================================================================================================================
    //                          The meat
    // =================================================================================================================

    /**
     * @notice Commits the purchased tokens to be revealed through future entropy; adding them to a reveal batch and
     * requesting the required entropy from the oracle.
     * @dev Must be called without gaps in sequential order for all token ranges, i.e.
     * `(0, num_1), (num_1, num_2), (num_1 + num_2, num_3), ...`.
     */
    function _commitAndRequestEntropy(uint256 tokenId, uint256 num) internal {
        if (num == 0) {
            return;
        }

        uint256 entropyBlockNumber = block.number;
        uint96 callbackId = _currentCallbackId[entropyBlockNumber];

        RevealBatch memory batch = _batches[entropyBlockNumber][callbackId];
        assert(!batch.revealed);

        uint256 batchSize = batch.end - batch.start;
        if (batchSize == 0) {
            // This batch has not been initialised yet.
            batch.start = SafeCast.toUint64(tokenId);
            entropyOracle.requestEntropyWithCallback(entropyBlockNumber, callbackId);
        }

        uint256 batchSizeLeft = _MAX_TOKENS_PER_ENTROPY_CALLBACK - batchSize;
        uint256 numThisBatch = Math.min(num, batchSizeLeft);

        batch.end = SafeCast.toUint64(tokenId + numThisBatch);
        _batches[entropyBlockNumber][callbackId] = batch;

        if (numThisBatch == batchSizeLeft) {
            // The commitment exhausts the current batch. Moving to the next one.
            ++_currentCallbackId[entropyBlockNumber];
        }

        // if `num - numThisBatch == 0` this will return early.
        _commitAndRequestEntropy(tokenId + numThisBatch, num - numThisBatch);
    }

    /**
     * @notice Consumes the entropy provided by the oracle and reveals the tokens in the corresponding reveal batch.
     * @dev The randomised reveal can be understood as shuffling a deck that contains each project ID
     * `_projectSizes()[pID]` times.
     */
    function consumeEntropy(uint256 blockNumber, uint96 callbackId, bytes32 entropy) external {
        if (msg.sender != address(entropyOracle)) {
            revert CallerNotOracle();
        }

        RevealBatch storage $batch = _batches[blockNumber][callbackId];
        RevealBatch memory batch = $batch;
        assert(!batch.revealed);
        $batch.revealed = true;

        // Doing this before actually revealing the tokens to simplify detecting this event while testing.
        _refreshMetadata(batch.start, batch.end);

        uint256[] memory sizes = _projectSizes();
        PRNG.Source rng = PRNG.newSource(keccak256(abi.encode(entropy, batch)));
        uint256 end = batch.end;
        for (uint256 tokenId = batch.start; tokenId < end; ++tokenId) {
            uint256 randIdx = _shuffler.next(rng);
            uint8 projectId = _findProjectId(randIdx, sizes);
            _assignProject(tokenId, projectId);
        }
    }

    /**
     * @notice Finds the project ID for a given index.
     * @dev The project ID is determined by stepping through the project sizes. It can also be understood by accessing
     * the array `[pID_0,...,pID_0,pID_1,...,pID_n]` where each project ID is contained `projectSizes[pID]` times at the
     * given index.
     */
    function _findProjectId(uint256 index, uint256[] memory projectSizes) internal pure returns (uint8) {
        uint8 projectId = 0;

        while (index >= projectSizes[projectId]) {
            index -= projectSizes[projectId];
            ++projectId;
        }

        return projectId;
    }

    // =================================================================================================================
    //                          Internal linking
    // =================================================================================================================

    /**
     * @notice Hook that is called after the project ID has been reavealed, assigning the project and its next edition
     * to a token.
     * @dev This is intended to trigger ArtBlock's rendering engine if the revealed project is a longform one.
     */
    function _assignProject(uint256 tokenId, uint8 projectId) internal virtual;

    /**
     * @notice Returns the number of tokens for each project.
     */
    function _projectSizes() internal pure virtual returns (uint256[] memory);
}
合同源代码
文件 44 的 49:ReentrancyGuard.sol
合同源代码
文件 45 的 49:SafeCast.sol
合同源代码
文件 46 的 49:SellableERC721ACommon.sol
合同源代码
文件 47 的 49:Seller.sol
合同源代码
文件 48 的 49:Strings.sol
合同源代码
文件 49 的 49:TokenIDMapping.sol
设置
{
  "compilationTarget": {
    "src/EvolvingPixels.sol": "EvolvingPixels"
  },
  "evmVersion": "london",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 9999
  },
  "remappings": [
    ":@divergencetech/ethier/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ethier_0-55-0/",
    ":@divergencetech/ethier/=/home/dave/proof/proof-seller/contracts/entropy/../../bazel-proof/external/ethier_0-54-0/",
    ":@openzeppelin-4-7-0/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts_4-7-0_exact_remap/",
    ":@openzeppelin-4.7/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts_4-7-0_exact_remap/",
    ":@openzeppelin/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts_4-8-1/",
    ":ERC721A/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ERC721A_4-2-3/contracts/",
    ":ERC721A_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ERC721A_4-2-3/",
    ":artblocks-contracts/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/artblocks-contracts_fa1dc466/contracts/",
    ":artblocks-contracts_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/artblocks-contracts_fa1dc466/",
    ":artblocks/=/home/dave/proof/proof-seller/contracts/artblocks/src/",
    ":constants/=../../constants/src/",
    ":delegate/=../../delegate/",
    ":delegation-registry/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/delegation-registry_2d1a158b/src/",
    ":delegation-registry_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/delegation-registry_2d1a158b/",
    ":demo/=/home/dave/proof/proof-seller/contracts/artblocks/../../demo/",
    ":ds-test/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ds-test_013e6c64/src/",
    ":ds-test_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ds-test_013e6c64/",
    ":entropy/=/home/dave/proof/proof-seller/contracts/entropy/",
    ":erc/=../../erc/",
    ":erc721a/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ERC721A_4-2-3/",
    ":ethier/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ethier_0-55-0/contracts/",
    ":ethier_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ethier_0-55-0/",
    ":forge-std/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/forge-std_1-4-0/src/",
    ":forge-std_root/=/home/dave/proof/proof-seller/contracts/entropy/../../bazel-proof/external/forge-std_1-4-0/",
    ":openzeppelin-contracts-4-7-0/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts_4-7-0_exact_remap/contracts/",
    ":openzeppelin-contracts/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts_4-8-1/contracts/",
    ":openzeppelin-contracts/contracts/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts_4-8-1/contracts/",
    ":openzeppelin-contracts_root-4-7-0/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts_4-7-0_exact_remap/",
    ":openzeppelin-contracts_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts_4-8-1/",
    ":operator-filter-registry/src/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/operator-filter-registry_1-4-1/src/",
    ":operator-filter-registry_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/operator-filter-registry_1-4-1/",
    ":projects/=/home/dave/proof/proof-seller/contracts/artblocks/../../projects/",
    ":proof/artblocks/=/home/dave/proof/proof-seller/contracts/artblocks/src/",
    ":proof/constants/=/home/dave/proof/proof-seller/contracts/constants/src/",
    ":proof/entropy/=/home/dave/proof/proof-seller/contracts/entropy/",
    ":proof/sellers/=/home/dave/proof/proof-seller/contracts/sellers/src/",
    ":sellers/=/home/dave/proof/proof-seller/contracts/sellers/src/"
  ]
}
ABI
[{"inputs":[{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"steerer","type":"address"},{"internalType":"address payable","name":"primaryReceiver","type":"address"},{"internalType":"address payable","name":"secondaryReceiver","type":"address"},{"internalType":"string","name":"baseTokenURI","type":"string"},{"internalType":"contract IEntropyOracleV2","name":"entropyOracle","type":"address"},{"internalType":"contract GenArt721CoreV3_Engine_Flex_PROOF","name":"flex","type":"address"},{"internalType":"contract IGenArt721CoreContractV3_Mintable","name":"flexMintGateway","type":"address"}],"internalType":"struct EvolvingPixels.ConstructorParams","name":"params","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"CallerNotOracle","type":"error"},{"inputs":[],"name":"DontGetGreedy","type":"error"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"},{"internalType":"uint256","name":"numLeft","type":"uint256"}],"name":"ExceedingMaxTotalSupply","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"OperatorNotAllowed","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"AUTHORISED_SELLER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_STEERING_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPERATOR_FILTER_REGISTRY","outputs":[{"internalType":"contract IOperatorFilterRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_NUM_PROJECTS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"artblocksProjectIds","outputs":[{"internalType":"uint8[4]","name":"","type":"uint8[4]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseTokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"cdata","type":"bytes"}],"name":"callOperatorFilterRegistry","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint96","name":"callbackId","type":"uint96"},{"internalType":"bytes32","name":"entropy","type":"bytes32"}],"name":"consumeEntropy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emitMetadataUpdateForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"entropyOracle","outputs":[{"internalType":"contract IEntropyOracleV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flex","outputs":[{"internalType":"contract GenArt721CoreV3_Engine_Flex_PROOF","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flexMintGateway","outputs":[{"internalType":"contract IGenArt721CoreContractV3_Mintable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint64","name":"num","type":"uint64"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"handleSale","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","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":[],"name":"lockSellers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxTotalSupply","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"numPurchasedPerProject","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"ownerMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"primaryReceiver","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"projectSizes","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","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":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseTokenURI_","type":"string"}],"name":"setBaseTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"basisPoints","type":"uint96"}],"name":"setDefaultRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IEntropyOracleV2","name":"newOracle","type":"address"}],"name":"setEntropyOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newReceiver","type":"address"}],"name":"setPrimaryReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum EvolvingPixels.Stage","name":"stage_","type":"uint8"}],"name":"setStage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum EvolvingPixels.Stage","name":"stage_","type":"uint8"},{"internalType":"contract Seller","name":"seller","type":"address"}],"name":"setStageSeller","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stage","outputs":[{"internalType":"enum EvolvingPixels.Stage","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum EvolvingPixels.Stage","name":"","type":"uint8"}],"name":"stageSellers","outputs":[{"internalType":"contract Seller","name":"","type":"address"}],"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":"uint8","name":"projectId","type":"uint8"}],"name":"tokenIdsByProjectId","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"tokenInfos","outputs":[{"components":[{"internalType":"bool","name":"revealed","type":"bool"},{"internalType":"uint8","name":"projectId","type":"uint8"},{"internalType":"uint8","name":"edition","type":"uint8"}],"internalType":"struct TokenInfoManager.TokenInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]