EthereumEthereum
0x4f...9a64
Black Eyed Creatures

Black Eyed Creatures

BEC

收藏品
底价
0.0002 ETH
$2,345.34
大小
1,049 件
1,560 版
所有者
244
16% 独特的所有者
此合同的源代码已经过验证!
合同元数据
编译器
0.8.25+commit.b61c2a91
语言
Solidity
合同源代码
文件 1 的 34:AccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    mapping(bytes32 role => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        return _roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        return _roles[role].adminRole;
    }

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

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

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

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        if (!hasRole(role, account)) {
            _roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        if (hasRole(role, account)) {
            _roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}
合同源代码
文件 2 的 34:BECAccessControl.sol
// contracts/BECAccessControl.sol
// SPDX-License-Identifier: MIT

/**

    /3333333     /33333333     /333333    
   | 33__  33   | 33_____/    /33__  33   
   | 33  \ 33   | 33         | 33  \__/   
   | 3333333    | 33333      | 33         
   | 33__  33   | 33__/      | 33         
   | 33  \ 33   | 33         | 33    33   
   | 3333333/   | 33333333   |  333333/   
   |_______/    |________/    \______/    

 # https://blackeyedcreatures.com

 */

pragma solidity ^0.8.25;

import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";

/**
 * @title Black Eyed Creatures Access Control
 * @author https://42i.co
 */
abstract contract BECAccessControl is AccessControl {

  /// @dev Role identifier for the GENETICIST role.
  bytes32 public constant GENETICIST = keccak256("GENETICIST");

  /// @dev Constructor grants the GENETICIST role to the address deploying the contract.
  constructor() {
    _setRoleAdmin(GENETICIST, GENETICIST);
    _grantRole(GENETICIST, msg.sender);
  }
}
合同源代码
文件 3 的 34:BECCore.sol
// contracts/BECCore.sol
// SPDX-License-Identifier: MIT

/**

    /3333333     /33333333     /333333    
   | 33__  33   | 33_____/    /33__  33   
   | 33  \ 33   | 33         | 33  \__/   
   | 3333333    | 33333      | 33         
   | 33__  33   | 33__/      | 33         
   | 33  \ 33   | 33         | 33    33   
   | 3333333/   | 33333333   |  333333/   
   |_______/    |________/    \______/    

 # https://blackeyedcreatures.com

 */

pragma solidity ^0.8.25;

import {ERC404B} from "./erc404/ERC404B.sol";
import {BECURIStorage} from "./BECURIStorage.sol";

/**
 * @title Black Eyed Creatures Core Contract
 * @dev This is the base contract for Black Eyed Creatures (BEC).
 * @author https://42i.co
 */
contract BECCore is BECURIStorage {
  /// @dev Role constants for managing access to specific methods.
  bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

  /// @dev Mapping between creature ID and the seed that generates its DNA.
  /// 0: Type (8, 3bit), Strategy (32, 5bit), Generation (4, 2bit), Seed (212bit)
  mapping(uint256 creatureId => bytes32 seed) internal creatureSeed;

  /// @dev Constructor initializes the ERC404 token with name "Black Eyed Creatures" and symbol "BEC".
  constructor() ERC404B("Black Eyed Creatures", "BEC", 333) {
    _setRoleAdmin(MINTER_ROLE, GENETICIST);
  }

  /**
   * @notice Mints new creatures with given DNA seeds for a specified address.
   * @dev Only addresses with MINTER_ROLE can call this function.
   * @param _creatureOwner Address of the new owner of the minted creatures.
   * @param _seed A seed value used to generate creature DNAs.
   * @param _quantity Quantity of minted creatures.
   * @return creatureIds Array of IDs for the newly minted creatures.
   */
  function mintWithSeed(
    address _creatureOwner,
    bytes32 _seed,
    uint256 _quantity
  ) public payable onlyRole(MINTER_ROLE) returns (uint256[] memory) {
    if (_quantity == 0) revert BECZeroQuantityMinting();
    uint256 baseCreatureId = nextTokenId();
    if (baseCreatureId + _quantity > 133333) revert BECCapLimitReached();
    uint256[] memory mintedCreatureIds = new uint256[](_quantity);

    _mint(_creatureOwner, _quantity);
    creatureSeed[baseCreatureId] = _seed;

    for (uint256 i = 0; i < _quantity; i++) {
      mintedCreatureIds[i] = baseCreatureId + i;
    }
    return mintedCreatureIds;
  }

  /**
   * @notice Retrieves the next available token ID for minting new creatures.
   * @dev This function returns the token ID that will be assigned to the next minted creature.
   * @return uint256 Next available token ID.
   */
  function nextTokenId() public view virtual returns (uint256) {
    return _nextTokenId;
  }

  /**
   * @notice Retrieves the seed of a creature by ID.
   * @param _creatureId ID of the creature.
   * @return bytes32 Seed of the creatures.
   */
  function getSeed(uint256 _creatureId) public view returns (bytes32) {
    bytes32 seed = 0;
    for (uint256 i = 0; seed == 0; i++) {
      seed = creatureSeed[_creatureId - i];
    }
    return seed;
  }

  /**
   * @notice Retrieves the seeds of a set creatures by ID.
   * @param _creatureIds ID of the creatures.
   * @return bytes32[] Seeds of the creatures.
   */
  function getSeeds(uint256[] calldata _creatureIds) public view returns (bytes32[] memory) {
    bytes32[] memory seeds = new bytes32[](_creatureIds.length);
    for (uint256 j = 0; j < _creatureIds.length; j++) {
      seeds[j] = getSeed(_creatureIds[j]);
    }
    return seeds;
  }

  /**
   * @notice Retrieves the total number of tokens currently in circulation.
   * @dev This function returns the total count of tokens that have been minted and are currently in existence.
   * @return uint256 Total number of tokens in circulation.
   */
  function totalTokens() public view returns (uint256) {
    return _totalTokens();
  }

  /**
   * @notice Burns a creature by ID.
   * @dev Only owner or approved senders can call this function.
   * @param _creatureId ID of the creature to be burned.
   */
  function burn(uint256 _creatureId) public {
    if (!_isApprovedOrOwner(msg.sender, _creatureId)) revert ERC721InsufficientApproval(msg.sender, _creatureId);
    _burn(_creatureId);
  }

  /**
   * @notice Retrieves the number of creatures that have been burned.
   * @return uint256 Number of burned creatures.
   */
  function burned() public view returns (uint256) {
    return _burned();
  }

  /**
   * @dev Forces the exemption status for ERC-721 transfers for the caller.
   *      This function can only be called by the owner, and is created for setting as exempt DEXs & LPs.
   *      An address that is not a contract, cannot be forced.
   * 
   * Emits:
   * - {Transfer} event for each target_ ERC721 token from/to the stash.
   * 
   * @param _target The address to be setted as exempt.
   * @param _state The new exemption state to set (true for exempt, false for non-exempt).
   */
  function forceERC721TransferExempt(address _target, bool _state) external onlyOwner {
    if (_target.code.length == 0) revert BECInvalidAddress(_target);
    _setERC721TransferExempt(_target, _state);
  }
}
合同源代码
文件 4 的 34:BECEnabler.sol
// contracts/BECEnabler.sol
// SPDX-License-Identifier: MIT

/**

   /3333333    /33333333    /333333 
  | 33__  33  | 33_____/   /33__  33
  | 33  \ 33  | 33        | 33  \__/
  | 3333333   | 33333     | 33      
  | 33__  33  | 33__/     | 33      
  | 33  \ 33  | 33        | 33    33
  | 3333333/  | 33333333  |  333333/
  |_______/   |________/   \______/ 

 # https://blackeyedcreatures.com

 */

pragma solidity ^0.8.25;

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

/**
 * @title Black Eyed Creatures Enabler
 * @author https://42i.co
 */
contract BECEnabler is BECWithdrawable {

  event BECEnabled(address contractAddress);

  /// @dev Internal state variable to track whether the BEC ecosystem is enabled.
  bool internal enabled = false;

  /**
   * @notice Checks whether the contract enabled.
   * @return bool True if the contract is enabled, false otherwise.
   */
  function isEnabled() external view returns (bool) {
    return enabled;
  }

  /**
   * @notice Enables the BEC ecosystem functionalities.
   * @dev Sets the internal `enabled` state variable to true, activating the functionalities of the BEC ecosystem that depend on this state. 
   *      This action can typically control the operational state of various contract features, such as minting or token transfers.
   */
  function enable() external onlyOwner {
    enabled = true;
    emit BECEnabled(address(this));
  }
}
合同源代码
文件 5 的 34:BECGenesisEngine.sol
// contracts/BECGenesisEngine.sol
// SPDX-License-Identifier: MIT

/**

   /3333333    /33333333    /333333 
  | 33__  33  | 33_____/   /33__  33
  | 33  \ 33  | 33        | 33  \__/
  | 3333333   | 33333     | 33      
  | 33__  33  | 33__/     | 33      
  | 33  \ 33  | 33        | 33    33
  | 3333333/  | 33333333  |  333333/
  |_______/   |________/   \______/ 

 # http://blackeyedcreatures.com

 */

pragma solidity ^0.8.25;

import {BECCore} from "./BECCore.sol";
import {BECLab} from "./BECLab.sol";
import {BECWithdrawable} from "./BECWithdrawable.sol";
import {BECAccessControl} from "./BECAccessControl.sol";
import {IBECDnaStrategy} from "./strategies/IBECDnaStrategy.sol";
import {IBECMetaExtension} from "./meta-extensions/IBECMetaExtension.sol";
import {IERC721Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";

/**
 * @title Black Eyed Creatures Genesis Engine Contract
 * @notice Orchestrates the unveiling of creature DNA within the Black Eyed Creatures universe.
 * @dev Manages the revelation of creature DNA based on different logics.
 * @author https://42i.co
 */
contract BECGenesisEngine is BECWithdrawable, BECAccessControl, IERC721Errors {

  /// @dev A constant identifier for the role that is permitted to update the genesis storage.
  bytes32 public constant GENESIS_STORAGE_UPDATER = keccak256("GENESIS_STORAGE_UPDATER");

  /// @dev Core contract address.
  address private immutable coreContractAddress;

  /// @dev Nested mapping structure to store the probability information of each variation for each phenotype and family, represented bitwise.
  /// The outermost mapping categorizes by [distribution].
  /// The intermediate mapping categorizes by [phenotype].
  /// The innermost mapping categorizes by [family].
  /// The uint256 value associated with each [distribution][phenotype][family] contains:
  ///   - familyTickets (32b): Represents the quantity of tickets allocated to this specific family, influencing the probability of selection.
  ///   - variationsCount (8b): Indicates the total number of variations available within the family.
  ///   - variationExponent (3b): Specifies the bit length used to represent the rarity of each family and variation. This value acts as an exponent for calculating their respective ticket quantities.
  mapping(uint256 distribution => mapping(uint256 phenotype => mapping(uint256 family => uint256 tickets))) public tickets;

  /// @dev A mapping storing uint256s, each containing 32-bit segments representing the total tickets for each phenotype in a specific distribution.
  mapping(uint256 distribution => uint256 tickets) public phenotypeTickets;

  /// @dev A mapping to store specific data associated with each creature, indexed by the creature's ID.
  mapping(uint256 creatureId => uint256 value) public genesisStorage;

  /// @dev A mapping that associates each dna strategy with a strategy contract address, indexed by the strategy ID.
  mapping(uint256 strategyId => address contractAddress) public dnaStrategies;

  /// @dev An array of metadata extensions.
  IBECMetaExtension[] public extensions;

  /**
   * @notice Initializes the Genesis Engine.
   * @dev Sets the coreContractAddress to the provided BEC core contract address.
   * @param _becCore The address of the BEC core contract.
   */
  constructor(address _becCore) {
    coreContractAddress = _becCore;
    _setRoleAdmin(GENESIS_STORAGE_UPDATER, GENETICIST);
  }

  /**
   * @notice Sets the genesis storage value for a specific creature.
   * @dev The function requires that the storage value for the creature has not been set previously. It can only be called by an address with the GENESIS_STORAGE_UPDATER role.
   * @param _creatureId The ID of the creature for which the storage value is to be set.
   * @param _value The value to be stored.
   */
  function setGenesisStorage(uint256 _creatureId, uint256 _value) public onlyRole(GENESIS_STORAGE_UPDATER) {
    if (genesisStorage[_creatureId] != 0) revert BECGenesisStoreAlreadySet(_creatureId);
    genesisStorage[_creatureId] = _value;
  }

  /**
   * @notice Retrieves the DNA of a specific creature.
   * @dev The function fetches the seed associated with the creature from the core contract, 
   *      determines the strategy using the seed, and then retrieves the DNA using the strategy. 
   *      It requires that the creature with the given ID exists.
   * @param _creatureId The ID of the creature whose DNA is to be retrieved.
   * @return uint256 The DNA of the specified creature.
   */
  function getDna(uint256 _creatureId) public view returns (uint256) {
    BECCore coreContract = BECCore(payable(coreContractAddress));
    if (!coreContract.exists(_creatureId)) revert ERC721NonexistentToken(_creatureId);
    bytes32 seed = coreContract.getSeed(_creatureId);
    IBECDnaStrategy strategy = IBECDnaStrategy(dnaStrategies[uint256(uint8(seed[0]) >> 3) & 0x1F]);
    return strategy.getDna(_creatureId);
  }

  /**
   * @notice Retrieves the token URI of a specific creature.
   * @dev The function fetches the seed associated with the creature from the core contract, determines the strategy using the seed, and then retrieves the token URI using the strategy.
   * @param _creatureId The ID of the creature whose token URI is to be retrieved.
   * @return string The token URI of the specified creature.
   */
  function tokenURI(uint256 _creatureId) public view returns (string memory) {
    BECCore coreContract = BECCore(payable(coreContractAddress));
    bytes32 seed = coreContract.getSeed(_creatureId);
    IBECDnaStrategy strategy = IBECDnaStrategy(dnaStrategies[uint256(uint8(seed[0]) >> 3) & 0x1F]);
    return strategy.tokenURI(_creatureId);
  }

  /**
   * @notice Retrieves the genesis storage value for a specific creature.
   * @dev Returns the stored value associated with the given creature ID from the genesisStorage mapping.
   * @param _creatureId The ID of the creature whose genesis storage value is to be retrieved.
   * @return uint256 The genesis storage value of the specified creature.
   */
  function getGenesisStorage(uint256 _creatureId) public view returns (uint256) {
    return genesisStorage[_creatureId];
  }

  /**
   * @notice Retrieves the amount of tickets of a family for a specific phenotype within a given distribution ID.
   * @dev Accesses the tickets mapping with the provided _distribution, _phenotype, and _family to return the associated family ticket information.
   * @param _distribution The distribution identifier.
   * @param _phenotype The phenotype identifier.
   * @param _family The family identifier within the phenotype.
   * @return uint256 The family ticket information of the specified phenotype and family.
   */
  function getFamilyTickets(uint256 _distribution, uint256 _phenotype, uint256 _family) public view returns (uint256) {
    return tickets[_distribution][_phenotype][_family] & 0xFFFFFFFF;
  }

  /**
   * @notice Retrieves the amount of tickets of a variation for a specific phenotype and family within a given distribution ID.
   * @dev Calculates the variation ticket information based on the stored ticket information and the provided _variation.
   * @param _distribution The distribution identifier.
   * @param _phenotype The phenotype identifier.
   * @param _family The family identifier within the phenotype.
   * @param _variation The variation identifier within the family.
   * @return uint256 The variation ticket information of the specified phenotype, family, and variation.
   */
  function getVariationTickets(uint256 _distribution, uint256 _phenotype, uint256 _family, uint256 _variation) public view returns (uint256) {
    return 1 << ((tickets[_distribution][_phenotype][_family] >> (40 + (_variation * 3))) & 0x7);
  }

  /**
   * @notice Retrieves the count of variations for a specific phenotype and family within a given distribution ID.
   * @dev Calculates the variations count based on the stored ticket information.
   * @param _distribution The distribution identifier.
   * @param _phenotype The phenotype identifier.
   * @param _family The family identifier within the phenotype.
   * @return uint256 The count of variations for the specified phenotype and family.
   */
  function getVariationsCount(uint256 _distribution, uint256 _phenotype, uint256 _family) public view returns (uint256) {
    return (tickets[_distribution][_phenotype][_family] >> 32) & 0xFF;
  }

  /**
   * @notice Retrieves the total number of tickets for each phenotype within a given distribution.
   * @dev Accesses the ticketsPerPhenotype mapping with the provided _distribution ID to return the associated ticket count.
   * @param _distribution The ID of the distribution.
   * @return uint256 The total number of tickets for each phenotype in the specified distribution.
   */
  function getPhenotypeTickets(uint256 _distribution) public view returns (uint256) {
    return phenotypeTickets[_distribution];
  }

  /**
   * @notice Adds ticket information for a specific distribution.
   * @dev Requires that the distribution has not been previously set. Iterates through the _tickets parameter to populate the tickets mapping for the given distribution. Can only be called by an address with the GENETICIST role.
   * @param _distribution The ID of the distribution to which the tickets are to be added.
   * @param _phenotypeTickets The total number of tickets for each phenotype within the distribution.
   * @param _tickets A two-dimensional array representing the ticket information to be added for each phenotype and family.
   */
  function addTickets(uint256 _distribution, uint256 _phenotypeTickets, uint256[][] memory _tickets) public onlyRole(GENETICIST) {
    if (phenotypeTickets[_distribution] != 0) revert BECDistributionAlreadySet(_distribution);
    phenotypeTickets[_distribution] = _phenotypeTickets;
    for (uint256 i = 0; i < _tickets.length; i++) {
      for (uint256 j = 0; j < _tickets[i].length; j++) {
        tickets[_distribution][i][j] = _tickets[i][j];
      }
    }
  }

  /**
   * @notice Registers a DNA strategy for a distribution.
   * @dev Can only be called by an address with the GENETICIST role.
   * @param _dnaStrategy The address of the DNA strategy contract to be registered.
   */
  function registerStrategy(address _dnaStrategy) public onlyRole(GENETICIST) {
    IBECDnaStrategy dnaStrategy = IBECDnaStrategy(_dnaStrategy);
    uint256 distributionId = dnaStrategy.getDistributionId();
    if (tickets[distributionId][0][0] == 0) revert BECWrongDistributionId(distributionId);

    uint256 strategyId = dnaStrategy.getStrategyId();
    dnaStrategies[strategyId] = _dnaStrategy;
  }

  /**
   * @notice Adds a new metadata extension to the Genesis Engine.
   * @dev Appends a new extension contract address to the `extensions` array. 
   *      This function can only be invoked by an address with the GENETICIST role. 
   *      Each extension should implement the IBECMetaExtension interface.
   * @param _extensionAddress The address of the metadata extension contract to add.
   */
  function addExtension(address _extensionAddress) public onlyRole(GENETICIST) {
    IBECMetaExtension extension = IBECMetaExtension(_extensionAddress);
    extensions.push(extension);
  }

  /**
   * @notice Clears all registered metadata extensions from the Genesis Engine.
   * @dev Deletes the `extensions` array, effectively removing all metadata extension contracts. 
   *      This action cannot be undone. This function can only be invoked by an address with the GENETICIST role.
   */
  function clearExtensions() public onlyRole(GENETICIST) {
    delete extensions;
  }

  /**
   * @notice Retrieves the addresses of all registered metadata extensions.
   * @dev Returns an array of addresses for each metadata extension contract currently registered in the `extensions` array.
   * @return An array of IBECMetaExtension contract addresses currently registered.
   */
  function getExtensions() external view returns (IBECMetaExtension[] memory) {
    return extensions;
  }
}
合同源代码
文件 6 的 34:BECLab.sol
// contracts/BECLab.sol
// SPDX-License-Identifier: MIT

/**

   /3333333    /33333333    /333333 
  | 33__  33  | 33_____/   /33__  33
  | 33  \ 33  | 33        | 33  \__/
  | 3333333   | 33333     | 33      
  | 33__  33  | 33__/     | 33      
  | 33  \ 33  | 33        | 33    33
  | 3333333/  | 33333333  |  333333/
  |_______/   |________/   \______/ 

 # https://blackeyedcreatures.com

 */

pragma solidity ^0.8.25;

import {BECCore} from "./BECCore.sol";
import {BECEnabler} from "./BECEnabler.sol";
import {BECAccessControl} from "./BECAccessControl.sol";
import {BECGenesisEngine} from "./BECGenesisEngine.sol";
import {EIP712} from "./eip712/EIP712.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {IERC721Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";

/**
 * @title Black Eyed Creatures Lab Contract
 * @author https://42i.co
 */
contract BECLab is BECEnabler, BECAccessControl, EIP712, IERC721Errors {
  using ECDSA for bytes32;

  event FamilyNameSet(uint256 indexed phenotype, uint256 indexed family, uint256[] ambassadors, string name);
  event VariationNameSet(uint256 indexed phenotype, uint256 indexed family, uint256 indexed variation, uint256[] ambassadors, string name);
  event CreatureNameSet(uint256 indexed creatureId, string name);

  /// @dev Core contract address.
  address private immutable coreContractAddress;

  /// @dev Genesis engine contract address.
  address private immutable genesisEngineAddress;

  /// @dev Blcksphr contract address.
  address private immutable blcksphrsAddress;

  /// @dev Mapping of the lab registry
  /// Structure:
  /// [bucket] each bucket stores 8 creature registries, of 4 bytes each
  /// - isVariationAmbassador (1bit)
  /// - isFamilyAmbassador (1bit)
  /// - ambassadorPhenotype (3bit)
  /// - ambassadorFamily (5bit)
  /// - ambassadorVariation (6bit)
  /// - omegas (16bit)
  mapping(uint256 bucket => uint256 registries) internal labRegistry;

  /// @dev Mapping that keeps track of each family name.
  mapping(uint256 phenotype => mapping(uint256 family => string name)) public familyNames;

  /// @dev Mapping that keeps track of each variation name.
  mapping(uint256 phenotype => mapping(uint256 family => mapping(uint256 variation => string name))) public variationNames;

  /// @dev Names of the creatures.
  mapping(uint256 creatureId => string name) public names;

  /// @dev Hash of names, and if they are used or not (default not).
  mapping(bytes32 nameHash => bool isUsed) internal nameUsed;

  /// @dev Mapping storing the amount of families and variations set by the address.
  mapping(address caller => uint256 count) public familyVariationAndNamesSet;

  /// @dev A constant identifier for the role that is permitted to update the lab register.
  bytes32 public constant LAB_REGISTER_UPDATER = keccak256("LAB_REGISTER_UPDATER");

  /// @dev The typehash for the data type specified in the family structured data.
  /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-typehash
  bytes32 public constant VERIFY_FAMILY_TYPEHASH = keccak256("VerifyFamilyName(uint256 phenotype,uint256 family,uint256[] ambassadors,string name,address wallet)");

  /// @dev The typehash for the data type specified in the variation structured data.
  /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-typehash
  bytes32 public constant VERIFY_VARIATION_TYPEHASH = keccak256("VerifyVariationName(uint256 phenotype,uint256 family,uint256 variation,uint256[] ambassadors,string name,address wallet)");

  /**
   * @dev Constructor for the Lab contract.
   * @param _becCore The core contract address.
   * @param _becGenesisEngine The genesis engine contract address.
   * @param _blcksphrsAddress The blcksphr contract address.
   */
  constructor(address _becCore, address _becGenesisEngine, address _blcksphrsAddress) {
    coreContractAddress = _becCore;
    genesisEngineAddress = _becGenesisEngine;
    blcksphrsAddress = _blcksphrsAddress;
    _setRoleAdmin(LAB_REGISTER_UPDATER, GENETICIST);
  }

  /**
   * @notice Checks if a variation name proposal meets the necessary criteria for a given phenotype, family, and variation.
   * @dev This function examines the validity of a name proposal for a variation by assessing the criteria regarding
   *      the phenotype, family, variation, and the three proposed ambassador creatures.
   *      A successful execution of this function indicates the name proposal meets all established conditions.
   * @param _phenotype The phenotype within which the family resides.
   * @param _family The family within which the variation exists.
   * @param _variation The specific variation for which the name validity is being verified.
   * @param _ambassadorIds The 3 ambassador ids.
   * @param _name The proposed name for the variation.
   *
   * Requirements:
   * - Phenotype number must be less than 6.
   * - Name length should be up to 8 characters.
   * - Name must be alphanumeric.
   * - The proposed ambassador creatures must be distinct.
   * - The creatures cannot already be variation ambassadors.
   * - Each proposed ambassador must be associated with the specified phenotype, family, and variation.
   */
  function verifyVariationName(
    uint256 _phenotype,
    uint256 _family,
    uint256 _variation,
    uint256[] memory _ambassadorIds,
    string memory _name
  ) public view {
    // Verify basics
    if (_phenotype > 5) revert BECInvalidPhenotype(_phenotype);
    if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name);
    if (!isAZ(bytes(_name))) revert BECInvalidName(_name);
    if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name);
    if (_ambassadorIds.length != 3) revert BECInvalidAmbassadorsLength(_ambassadorIds.length);
    if (bytes(variationNames[_phenotype][_family][_variation]).length != 0)
      revert BECVariationNameAlreadySet(_phenotype, _family, _variation);

    // Verify creatures
    if (
      _ambassadorIds[0] == _ambassadorIds[1] ||
      _ambassadorIds[0] == _ambassadorIds[2] ||
      _ambassadorIds[1] == _ambassadorIds[2]
    ) revert BECInvalidAmbassadors(_ambassadorIds[0], _ambassadorIds[1], _ambassadorIds[2]);

    // Verifying ambassadors and family & variation for each creature
    for (uint256 i = 0; i < 3; i++) {
      uint256 registry = (labRegistry[_ambassadorIds[i] / 8] >> ((_ambassadorIds[i] % 8) * 32)) & 0xFFFFFFFF;
      if (registry & 0x1 != 0) revert BECAlreadyVariationAmbassador(_ambassadorIds[i]);
      verifyFamilyAndVariation(_phenotype, _family, _variation, _ambassadorIds[i]);
    }
  }

  /**
   * @notice Verifies if a creature's family and variation match the provided family and variation within a specified phenotype.
   * @dev Extracts the creature's DNA related to the provided phenotype. It then verifies if the extracted DNA matches the provided family and variation.
   *      A successful execution indicates that the creature has the expected family and variation within the specified phenotype.
   * @param _phenotype The phenotype within which the family and variation reside.
   * @param _family The expected family of the creature within the given phenotype.
   * @param _variation The expected variation of the creature within the provided family.
   * @param _creatureId The ID of the creature (creature) to be verified.
   *
   * Requirements:
   * - The creature's family and variation, as determined from its DNA for the given phenotype, must match `_family` and `_variation` respectively.
   */
  function verifyFamilyAndVariation(
    uint256 _phenotype,
    uint256 _family,
    uint256 _variation,
    uint256 _creatureId
  ) internal view {
    unchecked {
      uint256 phenotypeTraits = BECGenesisEngine(payable(genesisEngineAddress)).getDna(_creatureId) >> ((_phenotype * 16));
      uint256 dnaVariation = (phenotypeTraits >> 8) & 0xFF;
      uint256 dnaFamily = (phenotypeTraits) & 0xFF;

      if (dnaFamily != _family) revert BECInvalidFamily(_creatureId);
      if (dnaVariation != _variation) revert BECInvalidVariation(_creatureId);
    }
  }

  /**
   * @notice Allows a user to propose a name for a variation by specifying the phenotype, family, variation, ambassador creatures,
   *         and the name itself.
   * @dev This function allows users to suggest a name for a specific variation by proposing three creatures as ambassadors.
   *      Before calling this function, users should call verifyVariationNameProposal() with the same parameters
   *      to ensure that the proposal is valid.
   *      The proposal will be checked by a validator backend after submission.
   *      The proposal is validated through a signature. If the proposal meets all criteria, the name is set for the variation.
   * @param _phenotype The phenotype within which the family resides.
   * @param _family The family within which the variation exists.
   * @param _variation The specific variation for which a name is being proposed.
   * @param _ambassadorIds An array of ambassador creature IDs proposed for the naming.
   * @param _name The proposed name for the variation.
   *
   * Requirements:
   * - Phenotype number must be less than 6.
   * - Name length should be up to 8 characters.
   * - Name must be alphanumeric.
   * - The proposal price must be met.
   * - The caller must own all three proposed ambassador creatures.
   * - The proposed ambassador creatures must be distinct.
   * - The creatures cannot already be variation ambassadors.
   * - There shouldn't be a pre-existing name or proposal for the specified variation.
   */
  function setVariationName(
    uint256 _phenotype,
    uint256 _family,
    uint256 _variation,
    uint256[] memory _ambassadorIds,
    string memory _name,
    bytes calldata _signature
  ) public {
    if (!enabled) revert BECNotEnabled();
    // Verify basics
    if (!validateVariationSignature(_phenotype, _family, _variation, _ambassadorIds, _name, _signature)) revert EIP712InvalidSignature(_signature);
    if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name);
    if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name);
    if (bytes(variationNames[_phenotype][_family][_variation]).length != 0)
      revert BECVariationNameAlreadySet(_phenotype, _family, _variation);

    BECCore coreContract = BECCore(payable(coreContractAddress));
    for (uint256 i = 0; i < 3; i++) {
      // Verify ownership
      if (msg.sender != coreContract.ownerOf(_ambassadorIds[i])) revert BECInvalidOwner(msg.sender, _ambassadorIds[i]);

      // Verifying creature was not used for being ambassador
      uint256 registry = (labRegistry[_ambassadorIds[i] / 8] >> ((_ambassadorIds[i] % 8) * 32)) & 0xFFFFFFFF;
      if (registry & 0x1 != 0) revert BECAlreadyVariationAmbassador(_ambassadorIds[i]);

      // Setting creature as ambassador in the registry
      setVariationAmbassadorToRegistry(_ambassadorIds[i], _phenotype, _family, _variation);
    }

    // Set variation name
    variationNames[_phenotype][_family][_variation] = _name;
    nameUsed[keccak256(abi.encodePacked(_name))] = true;
    familyVariationAndNamesSet[msg.sender] += 1;

    emit VariationNameSet(_phenotype, _family, _variation, _ambassadorIds, _name);
  }

  /**
   * @notice Validates the signature for a variation name proposal.
   * @dev Checks if the provided signature is valid for the given variation name proposal details.
   * @param _phenotype The phenotype ID involved in the proposal.
   * @param _family The family ID involved in the proposal.
   * @param _variation The variation ID for which the name is proposed.
   * @param _ambassadorIds The IDs of the ambassador creatures proposed.
   * @param _name The proposed name for the variation.
   * @param _signature The signature to validate.
   * @return bool Returns true if the signature is valid, false otherwise.
   */
  function validateVariationSignature(
    uint256 _phenotype,
    uint256 _family,
    uint256 _variation,
    uint256[] memory _ambassadorIds,
    string memory _name,
    bytes calldata _signature
  ) internal view returns (bool) {
    if (allowlistSigningKey == address(0)) revert EIP712BECSigningKeyNotSet();

    bytes32 digest = keccak256(
      abi.encodePacked(
        "\x19\x01",
        EIP712_DOMAIN_SEPARATOR,
        keccak256(
          abi.encode(
            VERIFY_VARIATION_TYPEHASH,
            _phenotype,
            _family,
            _variation,
            keccak256(abi.encodePacked(_ambassadorIds)),
            keccak256(bytes(_name)),
            msg.sender
          )
        )
      )
    );

    address recoveredAddress = digest.recover(_signature);
    return recoveredAddress == allowlistSigningKey;
  }

  /**
   * @notice Updates the registry entry to set the creature as a variation ambassador.
   * @dev This function performs bitwise operations on the provided registry entry to indicate
   *      that the creature is now an ambassador for a specified variation. It updates and returns
   *      the modified registry entry by setting the appropriate bits based on the phenotype, family,
   *      and variation passed as arguments.
   * @param _creatureId The creature Id.
   * @param _variationAmbassadorPhenotype The phenotype associated with the variation ambassador.
   * @param _variationAmbassadorFamily The family associated with the variation ambassador.
   * @param _variationAmbassadorVariation The specific variation the creature is an ambassador for.
   */
  function setVariationAmbassadorToRegistry(
    uint256 _creatureId,
    uint256 _variationAmbassadorPhenotype,
    uint256 _variationAmbassadorFamily,
    uint256 _variationAmbassadorVariation
  ) private {
    unchecked {
      labRegistry[_creatureId / 8] |=
        (1 |
          (_variationAmbassadorPhenotype << 2) |
          (_variationAmbassadorFamily << 5) |
          (_variationAmbassadorVariation << 10)) <<
        ((_creatureId % 8) * 32);
    }
  }

  /**
   * @notice Retrieves the name of a specified variation. If the variation hasn't been approved by ambassadors,
   *         it returns a default name based on the family and variation numbers.
   * @dev Checks the approval status of the variation using the variationAmbassadorsProposal mapping. If approved,
   *      it fetches the name from the variationNames mapping. Otherwise, it constructs a default name.
   * @param _phenotype The phenotype of the variation.
   * @param _family The family of the variation.
   * @param _variation The specific variation number.
   * @return variationName The name of the variation or a default name if not approved.
   */
  function getVariationName(
    uint256 _phenotype,
    uint256 _family,
    uint256 _variation
  ) public view returns (string memory) {
    if (bytes(variationNames[_phenotype][_family][_variation]).length != 0) {
      return capitalized(variationNames[_phenotype][_family][_variation]);
    }
    return string(abi.encodePacked("#(", Strings.toString(_family), ", ", Strings.toString(_variation), ")"));
  }

  /**
   * @notice Checks if a family name proposal meets the necessary criteria for a given phenotype and family.
   * @dev This function examines the validity of a name proposal for a family by assessing the criteria regarding
   *      the phenotype, family, and the three proposed ambassador creatures.
   *      A successful execution of this function indicates the name proposal meets all established conditions.
   *      The checks include validations for phenotype number, name length, name format,
   *      ambassador uniqueness, and ambassador association with the specific phenotype and family.
   *      It also ensures all variations within the family have been named before a family name is proposed.
   * @param _phenotype The phenotype within which the family resides.
   * @param _family The family for which the name validity is being verified.
   * @param _ambassadorIds An array of ambassador creature IDs proposed for the naming.
   * @param _name The proposed name for the family.
   *
   * Requirements:
   * - Phenotype number must be less than 6.
   * - Name length should be up to 8 characters.
   * - Name must be alphanumeric.
   * - The proposed ambassador creatures must be distinct.
   * - Each proposed ambassador must be associated with the specified phenotype and family.
   * - All variations within the family must have been named.
   *
   * @return Returns `true` if the name proposal is valid; reverts otherwise.
   */
  function verifyFamilyName(
    uint256 _phenotype,
    uint256 _family,
    uint256[] memory _ambassadorIds,
    string memory _name
  ) public view returns (bool) {
    unchecked {
      // Verify basics
      if (_phenotype > 5) revert BECInvalidPhenotype(_phenotype);
      if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name);
      if (!isAZ(bytes(_name))) revert BECInvalidName(_name);
      if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name);
      if (_ambassadorIds.length != 3) revert BECInvalidAmbassadorsLength(_ambassadorIds.length);
      if (bytes(familyNames[_phenotype][_family]).length != 0) revert BECFamilyNameAlreadySet(_phenotype, _family);

      BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineAddress));

      // Verify all variations of the family set up
      uint256 variationsCount = genesisEngineContract.getVariationsCount(0, _phenotype, _family);
      for (uint256 v = 0; v < variationsCount; v++) {
        if (bytes(variationNames[_phenotype][_family][v]).length == 0) revert BECNotAllVariationsSet(_phenotype, _family, v);
      }

      // Verify creatures are different
      if (
        _ambassadorIds[0] == _ambassadorIds[1] ||
        _ambassadorIds[0] == _ambassadorIds[2] ||
        _ambassadorIds[1] == _ambassadorIds[2]
      ) revert BECInvalidAmbassadors(_ambassadorIds[0], _ambassadorIds[1], _ambassadorIds[2]);

      // Verifying ambassadors and family & variation for each creature
      for (uint256 i = 0; i < 3; i++) {
        uint256 registry = (labRegistry[_ambassadorIds[i] / 8] >> ((_ambassadorIds[i] % 8) * 32)) & 0xFFFFFFFF;
        verifyFamilyAmbassador(_ambassadorIds[i], registry);
        verifyFamily(_phenotype, _family, _ambassadorIds[i]);
      }

      return true;
    }
  }

  /**
   * @notice Validates if a creature can be designated as a family ambassador.
   * @dev Evaluates the provided creature's registry to determine if the creature can be designated as a family ambassador.
   *      A successful execution indicates that the creature meets the criteria to become a family ambassador,
   *      i.e., it is not already a family ambassador and it is a variation ambassador.
   * @param _creatureId The creatureId to be verified.
   * @param _registry The registry entry of the creature (creature) to be verified.
   *
   * Requirements:
   * - The creature should not already be a family ambassador.
   * - The creature must be a variation ambassador.
   */
  function verifyFamilyAmbassador(uint256 _creatureId, uint256 _registry) internal pure {
    unchecked {
      if ((_registry & 2) != 0) revert BECAlreadyFamilyAmbassador(_creatureId); // Checks that the second bit (isFamilyAmbassador) is 0
      if ((_registry & 1) == 0) revert BECNotVariationAmbassador(_creatureId); // Checks that the first bit (isVariationAmbassador) is 1
    }
  }

  /**
   * @notice Verifies if the family of a creature corresponds to the specified family within a given phenotype.
   * @dev Extracts the creature's DNA related to the given phenotype and checks if its family matches the provided `_family`.
   *      A successful execution indicates the creature belongs to the expected family within the specified phenotype.
   * @param _phenotype The phenotype within which the family resides.
   * @param _family The expected family of the creature within the given phenotype.
   * @param _creatureId The ID of the creature (creature) to be verified.
   *
   * Requirements:
   * - The creature's family, as determined from its DNA for the given phenotype, must match `_family`.
   */
  function verifyFamily(uint256 _phenotype, uint256 _family, uint256 _creatureId) internal view {
    unchecked {
      uint256 phenotypeTraits = BECGenesisEngine(payable(genesisEngineAddress)).getDna(_creatureId) >>
        ((_phenotype * 16));
      uint256 dnaFamily = (phenotypeTraits) & 0xFF;
      if (dnaFamily != _family) revert BECInvalidFamily(_creatureId);
    }
  }

  /**
   * @notice Proposes a name for a family within a specific phenotype.
   * @dev This function allows users to suggest a name for a specific family by proposing three creatures as ambassadors.
   *      The proposal will be checked by a validator backend after submission. If valid, the name will be approved.
   *      The function includes basic validation for phenotype number, name length, name format, proposal price, 
   *      creature ownership, ambassador uniqueness, and previous proposals for the same family.
   * @param _phenotype The phenotype within which the family resides.
   * @param _family The family for which a name is being proposed.
   * @param _ambassadorIds An array of ambassador creature IDs proposed for the naming.
   * @param _name The proposed name for the family.
   *
   * Requirements:
   * - Phenotype number must be less than 6.
   * - Name length should be up to 8 characters.
   * - Name must be alphanumeric.
   * - The proposal price must be met.
   * - The caller must own all three proposed ambassador creatures.
   * - The proposed ambassador creatures must be distinct.
   * - All family variations should have their names set.
   * - The creatures cannot already be family ambassadors.
   * - There shouldn't be a pre-existing name or proposal for the specified family.
   */
  function setFamilyName(
    uint256 _phenotype,
    uint256 _family,
    uint256[] memory _ambassadorIds,
    string memory _name,
    bytes calldata _signature
  ) public {
    if (!enabled) revert BECNotEnabled();
    // Verify not already set
    if (!validateFamilySignature(_phenotype, _family, _ambassadorIds, _name, _signature)) revert EIP712InvalidSignature(_signature);
    if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name);
    if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name);
    if (bytes(familyNames[_phenotype][_family]).length != 0) revert BECFamilyNameAlreadySet(_phenotype, _family);

    BECCore coreContract = BECCore(payable(coreContractAddress));
    for (uint256 i = 0; i < 3; i++) {
      if (msg.sender != coreContract.ownerOf(_ambassadorIds[i])) revert BECInvalidOwner(msg.sender, _ambassadorIds[i]);
      uint256 registry = (labRegistry[_ambassadorIds[i] / 8] >> ((_ambassadorIds[i] % 8) * 32)) & 0xFFFFFFFF;
      verifyFamilyAmbassador(_ambassadorIds[i], registry);
      setFamilyAmbassadorToRegistry(_ambassadorIds[i], _phenotype, _family);
    }

    familyNames[_phenotype][_family] = _name;
    nameUsed[keccak256(abi.encodePacked(_name))] = true;
    familyVariationAndNamesSet[msg.sender] += 1 << 64;

    emit FamilyNameSet(_phenotype, _family, _ambassadorIds, _name);
  }

  /**
   * @notice Validates the signature for a family name proposal.
   * @dev Checks if the provided signature is valid for the given family name proposal details.
   * @param _phenotype The phenotype ID involved in the proposal.
   * @param _family The family ID for which the name is proposed.
   * @param _ambassadorIds The IDs of the ambassador creatures proposed.
   * @param _name The proposed name for the family.
   * @param _signature The signature to validate.
   * @return bool Returns true if the signature is valid, false otherwise.
   */
  function validateFamilySignature(
    uint256 _phenotype,
    uint256 _family,
    uint256[] memory _ambassadorIds,
    string memory _name,
    bytes calldata _signature
  ) internal view returns (bool) {
    if (allowlistSigningKey == address(0)) revert EIP712BECSigningKeyNotSet();

    bytes32 digest = keccak256(
      abi.encodePacked(
        "\x19\x01",
        EIP712_DOMAIN_SEPARATOR,
        keccak256(
          abi.encode(
            VERIFY_FAMILY_TYPEHASH,
            _phenotype,
            _family,
            keccak256(abi.encodePacked(_ambassadorIds)),
            keccak256(bytes(_name)),
            msg.sender
          )
        )
      )
    );

    address recoveredAddress = digest.recover(_signature);
    return recoveredAddress == allowlistSigningKey;
  }

  /**
   * @notice Retrieves the name of a family within a specific phenotype.
   * @dev This function returns the name of a family based on the given phenotype and family parameters.
   *      If the ambassador proposal for the family name has been approved, it returns the assigned family name.
   *      Otherwise, it returns a default placeholder name constructed with the family number.
   * @param _phenotype The phenotype within which the family resides.
   * @param _family The specific family for which the name is being queried.
   * @return A string representing either the assigned name of the family (if the name proposal was approved)
   *         or a default placeholder name indicating the family number.
   */
  function getFamilyName(uint256 _phenotype, uint256 _family) public view returns (string memory) {
    if (bytes(familyNames[_phenotype][_family]).length != 0) {
      return capitalized(familyNames[_phenotype][_family]);
    }
    return string(abi.encodePacked("#(", Strings.toString(_family), ")"));
  }

  /**
   * @notice Updates the registry entry to set the creature as a family ambassador.
   * @dev This function performs bitwise operations on the provided registry entry to indicate
   *      that the creature is now an ambassador for a specified family. It updates and returns
   *      the modified registry entry by setting the appropriate bits based on the laphenotypeyer and family
   *      passed as arguments.
   * @param _creatureId The creature Id.
   * @param _phenotype The phenotype associated with the family ambassador.
   * @param _family The specific family the creature is an ambassador for.
   */
  function setFamilyAmbassadorToRegistry(uint256 _creatureId, uint256 _phenotype, uint256 _family) private {
    unchecked {
      labRegistry[_creatureId / 8] |= (2 | (_phenotype << 2) | (_family << 5)) << ((_creatureId % 8) * 32);
    }
  }

  /**
   * @notice Determines whether the provided string consists only of A-Z characters.
   * @dev The function checks each character of the input string to ensure it's a letter (A-Z).
   *      Non-alphabetic characters will result in a return value of false.
   *      ^[A-Z]{0,6}$
   * @param _string The input string, given as a byte array, to be verified.
   * @return bool Returns true if all characters in the string are A-Z, otherwise returns false.
   */
  function isAZ(bytes memory _string) internal pure returns (bool) {
    unchecked {
      if (_string.length < 3 || _string.length > 7) {
        return false;
      }
      for (uint256 i = 0; i < _string.length; i++) {
        bytes1 char = _string[i];
        if (char < 0x41 || char > 0x5A) { // not A-Z
          return false;
        }
      }
      return true;
    }
  }

  /**
   * @notice Removes the capitalization of all characters besides the first one.
   * @dev This function iterates over all the elements of the string array and transforms it to lowercase.
   * @param _caps the string all in caps.
   * @return A string capitalized. (First leter in uppercase, the rest in lowercase).
   */
  function capitalized(string memory _caps) internal pure returns (string memory) {
    bytes memory b = bytes(_caps);
    for (uint i = 1; i < b.length; i++) {
      if (uint8(b[i]) >= 65 && uint8(b[i]) <= 90) {
        b[i] = bytes1(uint8(b[i]) + 32);
      }
    }
    return string(b);
  }

  /**
   * @notice Sets the allowlist signing key for validating signatures.
   * @dev Updates the allowlist signing key used for signature validation in name proposals.
   * @param newSigningKey The new signing key to be used for validation.
   */
  function setAllowlistSigningAddress(address newSigningKey) public onlyRole(GENETICIST) {
    _setAllowlistSigningAddress(newSigningKey);
  }

  /**
   * @notice Retrieves the lab registry record for a specific creature.
   * @dev Fetches the registry record for a creature based on its ID.
   *      The record contains information about the creature's ambassador status and other traits.
   * @param _creatureId The ID of the creature.
   * @return uint256 The registry record of the specified creature.
   */
  function getLabRegistryRecord(uint256 _creatureId) external view returns (uint256) {
    return (labRegistry[_creatureId / 8] >> ((_creatureId % 8) * 32)) & 0xFFFFFFFF;
  }

  /**
   * @notice Retrieves the number of Omegas for a specific creature.
   * @dev Fetches the Omega count for a creature from the lab registry based on its ID.
   * @param _creatureId The ID of the creature.
   * @return uint256 The number of Omegas associated with the creature.
   */
  function getOmegas(uint256 _creatureId) external view returns (uint256) {
    return (labRegistry[_creatureId / 8] >> ((((_creatureId % 8) * 32)) + 16)) & 0xFFFF;
  }

  /**
   * @notice Increments the Omega count for a specific creature.
   * @dev Adds a specified quantity to the Omega count of a creature in the lab registry.
   * @param _creatureId The ID of the creature.
   * @param _quantity The quantity to add to the creature's Omega count.
   */
  function incrementOmegas(uint256 _creatureId, uint256 _quantity) external onlyRole(LAB_REGISTER_UPDATER) {
    labRegistry[_creatureId / 8] += _quantity << (16 + ((_creatureId % 8) * 32));
  }

  /**
   * @notice Grants the LAB_REGISTER_UPDATER role to a specified address.
   * @dev Assigns the role responsible for updating lab registry entries to a given address.
   * @param _address The address to be granted the LAB_REGISTER_UPDATER role.
   */
  function grantLabRegisterUpdaterRole(address _address) external onlyRole(GENETICIST) {
    grantRole(LAB_REGISTER_UPDATER, _address);
  }

  /**
   * @notice Sets a name for a specific creature.
   * @dev Assigns a name to a creature based on its ID. The caller must be the owner of the creature.
   * @param _creatureId The ID of the creature.
   * @param _name The name to assign to the creature.
   */
  function setCreatureName(uint256 _creatureId, string memory _name) public {
    BECCore coreContract = BECCore(payable(coreContractAddress));
    if (msg.sender != coreContract.ownerOf(_creatureId)) revert BECInvalidOwner(msg.sender, _creatureId);
    if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name);
    if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name);
    if (!isAZ(bytes(_name))) revert BECInvalidName(_name);

    names[_creatureId] = _name;
    nameUsed[keccak256(abi.encodePacked(_name))] = true;
    familyVariationAndNamesSet[msg.sender] += 1 << 128;

    emit CreatureNameSet(_creatureId, _name);
  }

  /**
   * @notice Retrieves the name of a specific creature.
   * @dev Returns the name of a creature based on its ID. If the creature does not have a custom name, a default name is generated.
   * @param _creatureId The ID of the creature.
   * @return string The name of the creature or a default name if no custom name is set.
   */
  function getCreatureName(uint256 _creatureId) external view virtual returns (string memory) {
    if (bytes(names[_creatureId]).length > 0) {
      return capitalized(names[_creatureId]);
    }
    return string(abi.encodePacked("BEC #", Strings.toString(_creatureId)));
  }
}
合同源代码
文件 7 的 34:BECURIStorage.sol
// contracts/BECURIStorage.sol
// SPDX-License-Identifier: MIT

/**

   /3333333    /33333333    /333333 
  | 33__  33  | 33_____/   /33__  33
  | 33  \ 33  | 33        | 33  \__/
  | 3333333   | 33333     | 33      
  | 33__  33  | 33__/     | 33      
  | 33  \ 33  | 33        | 33    33
  | 3333333/  | 33333333  |  333333/
  |_______/   |________/   \______/ 

 # http://blackeyedcreatures.com

 */

pragma solidity ^0.8.25;

import {ERC404B} from "./erc404/ERC404B.sol";
import {BECAccessControl} from "./BECAccessControl.sol";
import {BECGenesisEngine} from "./BECGenesisEngine.sol";
import {BECWithdrawable} from "./BECWithdrawable.sol";
import {EIP712} from "./eip712/EIP712.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

/**
 * @title Black Eyed Creatures URI Storage
 * @dev Contract for managing URIs and IPFS-related functionality for Black Eyed Creatures (BEC) tokens.
 * @author https://42i.co
 */
abstract contract BECURIStorage is ERC404B, BECAccessControl, BECWithdrawable, EIP712 {

  /// @dev Using Elliptic Curve Digital Signature Algorithm (ECDSA).
  using ECDSA for bytes32;

  /// @dev Base URI for retrieve creature images.
  string _tokenBaseURI;

  /// @dev Base URL for the site.
  string internal _siteBaseUrl;

  /// @dev Genesis engine contract address.
  address genesisEngineContractAddress;

  /// @dev Mapping containing the IPFS uri of each token.
  mapping(uint256 tokenId => string ipfsUri) public ipfsUris;

  // The typehash for the data type specified in the structured data.
  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-typehash
  bytes32 public constant IPFS_URI_TYPEHASH = keccak256("SetIPFSUri(uint256 creatureId,string uri)");

  /**
   * @dev See {IERC165-supportsInterface}.
   */
  function supportsInterface(bytes4 _interfaceId) public view virtual override(ERC404B, AccessControl) returns (bool) {
    return super.supportsInterface(_interfaceId);
  }

  /**
   * @notice Sets the Base Token URI.
   * @param _uri the URI to set.
   */
  function setBaseURI(string memory _uri) public onlyOwner {
    _tokenBaseURI = _uri;
  }

  /**
   * @notice Sets the Site Base Token URI.
   * @dev Allows the owner to set the base URL for the site.
   * @param _uri The new site base URI to set.
   */
  function setSiteBaseURI(string memory _uri) public onlyOwner {
    _siteBaseUrl = _uri;
  }

  /**
   * @notice Sets the IPFS-specific Token URI.
   * @dev Allows setting a specific IPFS URI for a creature token.
   * @param _creatureId The ID of the creature token.
   * @param _uri The IPFS URI to set for the token.
   * @param _signature The signature to validate the operation.
   */
  function setIPFSTokenURI(uint256 _creatureId, string calldata _uri, bytes calldata _signature) public {
    if (!validateIPFSUriSignature(_creatureId, _uri, _signature)) revert EIP712InvalidSignature(_signature);
    ipfsUris[_creatureId] = _uri;
  }

  /**
   * @notice Gets the Site Base Token URI.
   * @dev Returns the current site base URI.
   * @return uri The current site base URI.
   */
  function getSiteBaseURI() public view returns (string memory uri) {
    return _siteBaseUrl;
  }

  /**
   * @notice Gets the image URI for a creature token.
   * @dev Generates and returns the image URI for a given creature token ID.
   * @param _creatureId The ID of the creature token.
   * @return uri The image URI for the creature token.
   */
  function getImageURI(uint256 _creatureId) public view returns (string memory uri) {
    if (bytes(ipfsUris[_creatureId]).length > 0) {
      return ipfsUris[_creatureId];
    }
    else {
      return string(
        abi.encodePacked(
          _tokenBaseURI,
          Strings.toHexString(uint256(uint160(address(this))), 20),
          "/",
          Strings.toString(_creatureId),
          ".png"
        )
      );
    }
  }

  /**
   * @dev See {IERC721Metadata-tokenURI}.
   */
  function tokenURI(uint256 _creatureId) public view virtual override returns (string memory) {
    BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineContractAddress));
    return genesisEngineContract.tokenURI(_creatureId);
  }

  /**
   * @notice Sets the address of the Genesis Engine contract.
   * @dev Allows the contract to interact with the Genesis Engine, enabling dynamic token URI generation based on creature DNA.
   * @param _genesisEngineContractAddress The address of the Genesis Engine contract.
   */
  function setGenesisEngineContractAddress(address _genesisEngineContractAddress) public onlyRole(GENETICIST) {
    genesisEngineContractAddress = _genesisEngineContractAddress;
  }

  /**
   * @notice Sets a new signing key for the allowlist.
   * @dev Updates the signing key used to validate signatures for certain privileged operations.
   * @param _signingKey The new public address to be used as the signing key.
   */
  function setAllowlistSigningAddress(address _signingKey) public onlyOwner {
    _setAllowlistSigningAddress(_signingKey);
  }

    /**
   * @notice Validates the signature for setting IPFS image creature uri.
   * @dev Uses EIP-712 signing standard to verify the signature against the expected message format and content,
   *      including the creatureId, and the IPFS URI of the creature.
   * @param _creatureId The creature.
   * @param _uri The IPFS uri for the creature.
   * @param _signature The signature to validate.
   * @return bool True if the signature is valid, false otherwise.
   */
  function validateIPFSUriSignature(
    uint256 _creatureId,
    string calldata _uri,
    bytes calldata _signature
  ) internal view returns (bool) {
    if (allowlistSigningKey == address(0)) revert EIP712BECSigningKeyNotSet();

    bytes32 digest = keccak256(
      abi.encodePacked(
        "\x19\x01",
        EIP712_DOMAIN_SEPARATOR,
        keccak256(abi.encode(IPFS_URI_TYPEHASH, _creatureId, keccak256(bytes(_uri)), msg.sender))
      )
    );

    address recoveredAddress = digest.recover(_signature);
    return recoveredAddress == allowlistSigningKey;
  }
}
合同源代码
文件 8 的 34:BECWithdrawable.sol
// contracts/BECWithdrawable.sol
// SPDX-License-Identifier: MIT

/**

   /3333333    /33333333    /333333 
  | 33__  33  | 33_____/   /33__  33
  | 33  \ 33  | 33        | 33  \__/
  | 3333333   | 33333     | 33      
  | 33__  33  | 33__/     | 33      
  | 33  \ 33  | 33        | 33    33
  | 3333333/  | 33333333  |  333333/
  |_______/   |________/   \______/ 

 # http://blackeyedcreatures.com

 */

pragma solidity ^0.8.25;

import {IBECErrors} from "./IBECErrors.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";

/**
 * @title Black Eyed Creatures Widthdrawable Contract
 * @dev This contract adds the availablitily to extract ether and erc-20 token balance from the contract that
 *      implements it.
 * @author https://42i.co
 */
abstract contract BECWithdrawable is Ownable, IBECErrors {

  /// @dev Event emitted when the contract receives ether from an address.
  event Received(address from, uint256 amount);

  /// @dev Constructor for Withdrawable.
  constructor () Ownable(msg.sender) {}

  /**
   * @dev Withdraws specified amount of royalties from contract to address.
   * @param _amount amount of royalties to withdraw.
   * @param _address address to withdraw the balance to.
   */
  function withdraw(uint256 _amount, address payable _address) public payable onlyOwner {
    if (_address == address(0)) revert BECInvalidAddress(_address);
    if (_amount > address(this).balance) revert BECInsufficientFunds(_amount, address(this).balance);
    _address.transfer(_amount);
  }

  /**
   * @dev Withdraws token specified ERC20 amount to the given address.
   * @param _tokenAddress Address of the token to withdraw.
   * @param _amount Amount of tokens to withdraw.
   * @param _address Address to withdraw the tokens to.
   */
  function withdrawERC20Token(
    address _tokenAddress,
    uint256 _amount,
    address payable _address
  ) public payable onlyOwner {
    IERC20 tokenContract = IERC20(_tokenAddress);
    if (_address == address(0)) revert BECInvalidAddress(_address);
    if (_amount > tokenContract.balanceOf(address(this))) revert BECInsufficientFunds(_amount, tokenContract.balanceOf(address(this)));
    tokenContract.transfer(_address, _amount);
  }

  /**
   * @dev Withdraws token specified ERC721 tokenId to the given address.
   * @param _tokenAddress Address of the token to withdraw.
   * @param _tokenId The id of the token to withdraw.
   * @param _address Address to withdraw the tokens to.
   */
  function withdrawERC721Token(
    address _tokenAddress,
    uint256 _tokenId,
    address _address
  ) public payable onlyOwner {
    IERC721 tokenContract = IERC721(_tokenAddress);
    if (_address == address(0)) revert BECInvalidAddress(_address);
    if (address(this) != tokenContract.ownerOf(_tokenId)) revert BECInvalidOwner(address(this), _tokenId);
    tokenContract.safeTransferFrom(address(this), _address, _tokenId);
  }

  /**
   * @dev Function to receive Ether. msg.data must be empty.
   */
  receive() external payable {
    emit Received(msg.sender, msg.value);
  }

  /**
   * @dev Fallback function is called when msg.data is not empty.
   */
  fallback() external payable {}
}
合同源代码
文件 9 的 34:BitMaps.sol
// SPDX-License-Identifier: MIT
/**
   _____       ___     ___ __           ____  _ __      
  / ___/____  / (_)___/ (_) /___  __   / __ )(_) /______
  \__ \/ __ \/ / / __  / / __/ / / /  / __  / / __/ ___/
 ___/ / /_/ / / / /_/ / / /_/ /_/ /  / /_/ / / /_(__  ) 
/____/\____/_/_/\__,_/_/\__/\__, /  /_____/_/\__/____/  
                           /____/                        

- npm: https://www.npmjs.com/package/solidity-bits
- github: https://github.com/estarriolvetch/solidity-bits

 */
pragma solidity ^0.8.0;

import "./BitScan.sol";
import "./Popcount.sol";

/**
 * @dev This Library is a modified version of Openzeppelin's BitMaps library with extra features.
 *
 * 1. Functions of finding the index of the closest set bit from a given index are added.
 *    The indexing of each bucket is modifed to count from the MSB to the LSB instead of from the LSB to the MSB.
 *    The modification of indexing makes finding the closest previous set bit more efficient in gas usage.
 * 2. Setting and unsetting the bitmap consecutively.
 * 3. Accounting number of set bits within a given range.   
 *
*/

/**
 * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential.
 * Largelly inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor].
 */

library BitMaps {
    using BitScan for uint256;
    uint256 private constant MASK_INDEX_ZERO = (1 << 255);
    uint256 private constant MASK_FULL = type(uint256).max;

    struct BitMap {
        mapping(uint256 => uint256) _data;
    }

    /**
     * @dev Returns whether the bit at `index` is set.
     */
    function get(BitMap storage bitmap, uint256 index) internal view returns (bool) {
        uint256 bucket = index >> 8;
        uint256 mask = MASK_INDEX_ZERO >> (index & 0xff);
        return bitmap._data[bucket] & mask != 0;
    }

    /**
     * @dev Sets the bit at `index` to the boolean `value`.
     */
    function setTo(
        BitMap storage bitmap,
        uint256 index,
        bool value
    ) internal {
        if (value) {
            set(bitmap, index);
        } else {
            unset(bitmap, index);
        }
    }

    /**
     * @dev Sets the bit at `index`.
     */
    function set(BitMap storage bitmap, uint256 index) internal {
        uint256 bucket = index >> 8;
        uint256 mask = MASK_INDEX_ZERO >> (index & 0xff);
        bitmap._data[bucket] |= mask;
    }

    /**
     * @dev Unsets the bit at `index`.
     */
    function unset(BitMap storage bitmap, uint256 index) internal {
        uint256 bucket = index >> 8;
        uint256 mask = MASK_INDEX_ZERO >> (index & 0xff);
        bitmap._data[bucket] &= ~mask;
    }


    /**
     * @dev Consecutively sets `amount` of bits starting from the bit at `startIndex`.
     */    
    function setBatch(BitMap storage bitmap, uint256 startIndex, uint256 amount) internal {
        uint256 bucket = startIndex >> 8;

        uint256 bucketStartIndex = (startIndex & 0xff);

        unchecked {
            if(bucketStartIndex + amount < 256) {
                bitmap._data[bucket] |= MASK_FULL << (256 - amount) >> bucketStartIndex;
            } else {
                bitmap._data[bucket] |= MASK_FULL >> bucketStartIndex;
                amount -= (256 - bucketStartIndex);
                bucket++;

                while(amount > 256) {
                    bitmap._data[bucket] = MASK_FULL;
                    amount -= 256;
                    bucket++;
                }

                bitmap._data[bucket] |= MASK_FULL << (256 - amount);
            }
        }
    }


    /**
     * @dev Consecutively unsets `amount` of bits starting from the bit at `startIndex`.
     */    
    function unsetBatch(BitMap storage bitmap, uint256 startIndex, uint256 amount) internal {
        uint256 bucket = startIndex >> 8;

        uint256 bucketStartIndex = (startIndex & 0xff);

        unchecked {
            if(bucketStartIndex + amount < 256) {
                bitmap._data[bucket] &= ~(MASK_FULL << (256 - amount) >> bucketStartIndex);
            } else {
                bitmap._data[bucket] &= ~(MASK_FULL >> bucketStartIndex);
                amount -= (256 - bucketStartIndex);
                bucket++;

                while(amount > 256) {
                    bitmap._data[bucket] = 0;
                    amount -= 256;
                    bucket++;
                }

                bitmap._data[bucket] &= ~(MASK_FULL << (256 - amount));
            }
        }
    }

    /**
     * @dev Returns number of set bits within a range.
     */
    function popcountA(BitMap storage bitmap, uint256 startIndex, uint256 amount) internal view returns(uint256 count) {
        uint256 bucket = startIndex >> 8;

        uint256 bucketStartIndex = (startIndex & 0xff);

        unchecked {
            if(bucketStartIndex + amount < 256) {
                count +=  Popcount.popcount256A(
                    bitmap._data[bucket] & (MASK_FULL << (256 - amount) >> bucketStartIndex)
                );
            } else {
                count += Popcount.popcount256A(
                    bitmap._data[bucket] & (MASK_FULL >> bucketStartIndex)
                );
                amount -= (256 - bucketStartIndex);
                bucket++;

                while(amount > 256) {
                    count += Popcount.popcount256A(bitmap._data[bucket]);
                    amount -= 256;
                    bucket++;
                }
                count += Popcount.popcount256A(
                    bitmap._data[bucket] & (MASK_FULL << (256 - amount))
                );
            }
        }
    }

    /**
     * @dev Returns number of set bits within a range.
     */
    function popcountB(BitMap storage bitmap, uint256 startIndex, uint256 amount) internal view returns(uint256 count) {
        uint256 bucket = startIndex >> 8;

        uint256 bucketStartIndex = (startIndex & 0xff);

        unchecked {
            if(bucketStartIndex + amount < 256) {
                count +=  Popcount.popcount256B(
                    bitmap._data[bucket] & (MASK_FULL << (256 - amount) >> bucketStartIndex)
                );
            } else {
                count += Popcount.popcount256B(
                    bitmap._data[bucket] & (MASK_FULL >> bucketStartIndex)
                );
                amount -= (256 - bucketStartIndex);
                bucket++;

                while(amount > 256) {
                    count += Popcount.popcount256B(bitmap._data[bucket]);
                    amount -= 256;
                    bucket++;
                }
                count += Popcount.popcount256B(
                    bitmap._data[bucket] & (MASK_FULL << (256 - amount))
                );
            }
        }
    }


    /**
     * @dev Find the closest index of the set bit before `index`.
     */
    function scanForward(BitMap storage bitmap, uint256 index) internal view returns (uint256 setBitIndex) {
        uint256 bucket = index >> 8;

        // index within the bucket
        uint256 bucketIndex = (index & 0xff);

        // load a bitboard from the bitmap.
        uint256 bb = bitmap._data[bucket];

        // offset the bitboard to scan from `bucketIndex`.
        bb = bb >> (0xff ^ bucketIndex); // bb >> (255 - bucketIndex)
        
        if(bb > 0) {
            unchecked {
                setBitIndex = (bucket << 8) | (bucketIndex -  bb.bitScanForward256());    
            }
        } else {
            while(true) {
                require(bucket > 0, "BitMaps: The set bit before the index doesn't exist.");
                unchecked {
                    bucket--;
                }
                // No offset. Always scan from the least significiant bit now.
                bb = bitmap._data[bucket];
                
                if(bb > 0) {
                    unchecked {
                        setBitIndex = (bucket << 8) | (255 -  bb.bitScanForward256());
                        break;
                    }
                } 
            }
        }
    }

    function getBucket(BitMap storage bitmap, uint256 bucket) internal view returns (uint256) {
        return bitmap._data[bucket];
    }
}
合同源代码
文件 10 的 34:BitScan.sol
// SPDX-License-Identifier: MIT
/**
   _____       ___     ___ __           ____  _ __      
  / ___/____  / (_)___/ (_) /___  __   / __ )(_) /______
  \__ \/ __ \/ / / __  / / __/ / / /  / __  / / __/ ___/
 ___/ / /_/ / / / /_/ / / /_/ /_/ /  / /_/ / / /_(__  ) 
/____/\____/_/_/\__,_/_/\__/\__, /  /_____/_/\__/____/  
                           /____/                        

- npm: https://www.npmjs.com/package/solidity-bits
- github: https://github.com/estarriolvetch/solidity-bits

 */

pragma solidity ^0.8.0;


library BitScan {
    uint256 constant private DEBRUIJN_256 = 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff;
    bytes constant private LOOKUP_TABLE_256 = hex"0001020903110a19042112290b311a3905412245134d2a550c5d32651b6d3a7506264262237d468514804e8d2b95569d0d495ea533a966b11c886eb93bc176c9071727374353637324837e9b47af86c7155181ad4fd18ed32c9096db57d59ee30e2e4a6a5f92a6be3498aae067ddb2eb1d5989b56fd7baf33ca0c2ee77e5caf7ff0810182028303840444c545c646c7425617c847f8c949c48a4a8b087b8c0c816365272829aaec650acd0d28fdad4e22d6991bd97dfdcea58b4d6f29fede4f6fe0f1f2f3f4b5b6b607b8b93a3a7b7bf357199c5abcfd9e168bcdee9b3f1ecf5fd1e3e5a7a8aa2b670c4ced8bbe8f0f4fc3d79a1c3cde7effb78cce6facbf9f8";

    /**
        @dev Isolate the least significant set bit.
     */ 
    function isolateLS1B256(uint256 bb) pure internal returns (uint256) {
        require(bb > 0);
        unchecked {
            return bb & (0 - bb);
        }
    } 

    /**
        @dev Isolate the most significant set bit.
     */ 
    function isolateMS1B256(uint256 bb) pure internal returns (uint256) {
        require(bb > 0);
        unchecked {
            bb |= bb >> 128;
            bb |= bb >> 64;
            bb |= bb >> 32;
            bb |= bb >> 16;
            bb |= bb >> 8;
            bb |= bb >> 4;
            bb |= bb >> 2;
            bb |= bb >> 1;
            
            return (bb >> 1) + 1;
        }
    } 

    /**
        @dev Find the index of the lest significant set bit. (trailing zero count)
     */ 
    function bitScanForward256(uint256 bb) pure internal returns (uint8) {
        unchecked {
            return uint8(LOOKUP_TABLE_256[(isolateLS1B256(bb) * DEBRUIJN_256) >> 248]);
        }   
    }

    /**
        @dev Find the index of the most significant set bit.
     */ 
    function bitScanReverse256(uint256 bb) pure internal returns (uint8) {
        unchecked {
            return 255 - uint8(LOOKUP_TABLE_256[((isolateMS1B256(bb) * DEBRUIJN_256) >> 248)]);
        }   
    }

    function log2(uint256 bb) pure internal returns (uint8) {
        unchecked {
            return uint8(LOOKUP_TABLE_256[(isolateMS1B256(bb) * DEBRUIJN_256) >> 248]);
        } 
    }
}
合同源代码
文件 11 的 34:Context.sol
// 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;
    }
}
合同源代码
文件 12 的 34:DoubleEndedQueue.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/DoubleEndedQueue.sol)
// Modified by Pandora Labs to support native uint256 operations
// Modified by 42i.co to retriveQueueItems && setIndexValue
pragma solidity ^0.8.25;

/**
 * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of
 * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and
 * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that
 * the existing queue contents are left in storage.
 *
 * The struct is called `Uint256Deque`. This data structure can only be used in storage, and not in memory.
 *
 * ```solidity
 * DoubleEndedQueue.Uint256Deque queue;
 * ```
 */
library DoubleEndedQueue {
  /**
   * @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty.
   */
  error QueueEmpty();

  /**
   * @dev A push operation couldn't be completed due to the queue being full.
   */
  error QueueFull();

  /**
   * @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds.
   */
  error QueueOutOfBounds();

  /**
   * @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access.
   *
   * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to
   * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
   * lead to unexpected behavior.
   *
   * The first item is at data[begin] and the last item is at data[end - 1]. This range can wrap around.
   */
  struct Uint256Deque {
    uint128 _begin;
    uint128 _end;
    mapping(uint128 index => uint256) _data;
  }

  /**
   * @dev Retrieves all items from the queue as an array of uint256 values.
   * This function does not modify the state of the queue.
   */
  function retriveQueueItems(Uint256Deque storage deque) internal view returns (uint256[] memory dequeTokens) {
    unchecked {
      uint128 beginIndex = deque._begin;
      uint128 queueLenght = deque._end - beginIndex;
      dequeTokens = new uint256[](queueLenght);
      for (uint128 i = 0; i < queueLenght; ++i) {
        dequeTokens[i] = deque._data[beginIndex+i];
      }
    }
  }

  /**
   * @dev Sets the value at a specific index in the queue. The index is relative to the current `begin` of the queue.
   * This function allows for direct manipulation of queue items at a given index, and should be used with caution as
   * improper usage can lead to logical errors in the queue state.
   *
   * Reverts with `QueueOutOfBounds` if the index is out of bounds.
   */
  function setIndexValue(Uint256Deque storage deque, uint128 index, uint256 value) internal {
    if (index >= length(deque)) revert QueueOutOfBounds();
    deque._data[index+deque._begin] = value;
  }

  /**
   * @dev Inserts an item at the end of the queue.
   *
   * Reverts with {QueueFull} if the queue is full.
   */
  function pushBack(Uint256Deque storage deque, uint256 value) internal {
    unchecked {
      uint128 backIndex = deque._end;
      if (backIndex + 1 == deque._begin) revert QueueFull();
      deque._data[backIndex] = value;
      deque._end = backIndex + 1;
    }
  }

  /**
   * @dev Removes the item at the end of the queue and returns it.
   *
   * Reverts with {QueueEmpty} if the queue is empty.
   */
  function popBack(
    Uint256Deque storage deque
  ) internal returns (uint256 value) {
    unchecked {
      uint128 backIndex = deque._end;
      if (backIndex == deque._begin) revert QueueEmpty();
      --backIndex;
      value = deque._data[backIndex];
      delete deque._data[backIndex];
      deque._end = backIndex;
    }
  }

  /**
   * @dev Inserts an item at the beginning of the queue.
   *
   * Reverts with {QueueFull} if the queue is full.
   */
  function pushFront(Uint256Deque storage deque, uint256 value) internal {
    unchecked {
      uint128 frontIndex = deque._begin - 1;
      if (frontIndex == deque._end) revert QueueFull();
      deque._data[frontIndex] = value;
      deque._begin = frontIndex;
    }
  }

  /**
   * @dev Removes the item at the beginning of the queue and returns it.
   *
   * Reverts with `QueueEmpty` if the queue is empty.
   */
  function popFront(
    Uint256Deque storage deque
  ) internal returns (uint256 value) {
    unchecked {
      uint128 frontIndex = deque._begin;
      if (frontIndex == deque._end) revert QueueEmpty();
      value = deque._data[frontIndex];
      delete deque._data[frontIndex];
      deque._begin = frontIndex + 1;
    }
  }

  /**
   * @dev Returns the item at the beginning of the queue.
   *
   * Reverts with `QueueEmpty` if the queue is empty.
   */
  function front(
    Uint256Deque storage deque
  ) internal view returns (uint256 value) {
    if (empty(deque)) revert QueueEmpty();
    return deque._data[deque._begin];
  }

  /**
   * @dev Returns the item at the end of the queue.
   *
   * Reverts with `QueueEmpty` if the queue is empty.
   */
  function back(
    Uint256Deque storage deque
  ) internal view returns (uint256 value) {
    if (empty(deque)) revert QueueEmpty();
    unchecked {
      return deque._data[deque._end - 1];
    }
  }

  /**
   * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at
   * `length(deque) - 1`.
   *
   * Reverts with `QueueOutOfBounds` if the index is out of bounds.
   */
  function at(
    Uint256Deque storage deque,
    uint256 index
  ) internal view returns (uint256 value) {
    if (index >= length(deque)) revert QueueOutOfBounds();
    // By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128
    unchecked {
      return deque._data[deque._begin + uint128(index)];
    }
  }

  /**
   * @dev Resets the queue back to being empty.
   *
   * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses
   * out on potential gas refunds.
   */
  function clear(Uint256Deque storage deque) internal {
    deque._begin = 0;
    deque._end = 0;
  }

  /**
   * @dev Returns the number of items in the queue.
   */
  function length(Uint256Deque storage deque) internal view returns (uint256) {
    unchecked {
      return uint256(deque._end - deque._begin);
    }
  }

  /**
   * @dev Returns true if the queue is empty.
   */
  function empty(Uint256Deque storage deque) internal view returns (bool) {
    return deque._end == deque._begin;
  }
}
合同源代码
文件 13 的 34:ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError, bytes32) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}
合同源代码
文件 14 的 34:EIP712.sol
// contracts/eip712/EIP712.sol
// SPDX-License-Identifier: MIT

/**

   /3333333    /33333333    /333333 
  | 33__  33  | 33_____/   /33__  33
  | 33  \ 33  | 33        | 33  \__/
  | 3333333   | 33333     | 33      
  | 33__  33  | 33__/     | 33      
  | 33  \ 33  | 33        | 33    33
  | 3333333/  | 33333333  |  333333/
  |_______/   |________/   \______/ 

 # http://blackeyedcreatures.com

 */

pragma solidity ^0.8.25;

import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

/**
 * @title EIP712 Base Contract for Typed Structured Data Hashing and Signing
 * @dev Implements EIP-712 standard providing a secure method for generating off-chain signatures 
 *      that can be verified on-chain. Utilizes OpenZeppelin's ECDSA library for cryptographic operations, 
 *      ensuring robust and secure handling of digital signatures.
 * @author https://42i.co
 */
contract EIP712 {

  /**
   * @dev Indicates that the signature was invalid.
   * @param signature The used signature.
   */
  error EIP712InvalidSignature(bytes signature);

  /**
   * @dev Indicates that the signing key was not set.
   */
  error EIP712BECSigningKeyNotSet();

  /// @dev Using Elliptic Curve Digital Signature Algorithm (ECDSA)
  using ECDSA for bytes32;

  /// @dev The key used to sign allowlist signatures.
  address allowlistSigningKey = address(0);

  /// @dev EIP-712 Domain Separator, providing protection against replay attacks across different contracts and networks.
  /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#definition-of-domainseparator
  bytes32 public immutable EIP712_DOMAIN_SEPARATOR;

  /**
   * @dev Initializes the contract by setting up the DOMAIN_SEPARATOR to include the contract's details 
   *      and the current chain ID, ensuring signatures are valid for specific interactions on the intended network.
   */
  constructor() {
    // This should match whats in the client side allowlist signing code
    EIP712_DOMAIN_SEPARATOR = keccak256(
      abi.encode(
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
        keccak256(bytes("BEC")),
        keccak256(bytes("3")),
        block.chainid,
        address(this)
      )
    );
  }

  /**
   * @notice Sets a new signing key for the allowlist, updating the key used for signature validation.
   * @dev Internal function to update the allowlist signing key, ensuring only authorized signatures are considered valid.
   * @param _signingKey The new signing key address to be used for validating signatures.
   */
  function _setAllowlistSigningAddress(address _signingKey) internal {
    allowlistSigningKey = _signingKey;
  }
}
合同源代码
文件 15 的 34:ERC165.sol
// 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;
    }
}
合同源代码
文件 16 的 34:ERC404B.sol
// contracts/erc404/ERC404B.sol
// SPDX-License-Identifier: MIT

/**

    /3333333     /33333333     /333333    
   | 33__  33   | 33_____/    /33__  33   
   | 33  \ 33   | 33         | 33  \__/   
   | 3333333    | 33333      | 33         
   | 33__  33   | 33__/      | 33         
   | 33  \ 33   | 33         | 33    33   
   | 3333333/   | 33333333   |  333333/   
   |_______/    |________/    \______/    

 # https://blackeyedcreatures.com

 */
pragma solidity ^0.8.25;

import {IERC404B} from "./IERC404B.sol";
import {IERC404BErrors} from "./IERC404BErrors.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import {IERC20Errors, IERC721Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import {DoubleEndedQueue} from "./lib/DoubleEndedQueue.sol";
import {BitMaps} from "solidity-bits/contracts/BitMaps.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";

/**
 * @title Stash Contract
 * @dev This empty contract serves as the designated address for ERC721 tokens that have been minted but not yet burned and currently have no owner.
 */
contract Stash {}


/**
 * @title ERC404B Contract
 * @dev Implements the IERC404 interface to provide a hybrid token mechanism supporting both ERC-20 and ERC-721 functionalities.
 * This contract diverts tokens without current ownership to a "stash" address instead of sending them to the zero address (0x00) as is common with burns.
 * It also enables the actual burning of tokens, sending them irreversibly to the zero address.
 * Features include batch minting for ERC-721 tokens to optimize minting operations, gas savings optimizations, and support for EIP-2612 permit-based transactions.
 * @author https://42i.co
 */
contract ERC404B is IERC404B, IERC20Errors, IERC721Errors, IERC404BErrors {
  using Strings for uint256;
  using BitMaps for BitMaps.BitMap;
  using DoubleEndedQueue for DoubleEndedQueue.Uint256Deque; // DoubleEndedQueue.Uint32Deque would be great

  /// @dev Token Name.
  string private _name;

  /// @dev Token Symbol.
  string private _symbol;

  /// @dev Token decimal digits.
  uint8 private immutable _DECIMALS;

  /// @dev The number of ERC20 tokens required for one ERC721 token.
  uint256 private immutable _UNIT;

  /// @dev The number of tokens held by each address.
  mapping(address holder => uint256 balance) private _balances;

  /// @dev Identifier for the next token to mint.
  uint256 internal _nextTokenId = _startTokenId();

  /// @dev ERC721 token approvals.
  mapping(uint256 tokenId => address approvedAddress) private _tokenApprovals;

  /// @dev ERC721 operator approvals.
  mapping(address holder => mapping(address operator => bool approval)) private _operatorApprovals;

  /// @dev ERC20 token allowances.
  mapping(address holder => mapping(address operator => uint256 allowance)) private _allowances;  

  /// @dev Exempt addresses from ERC-721 transfers (e.g., pairs, routers) for gas savings.
  mapping(address holder => bool exempt) private _erc721TransferExempt;

  /// @dev Bitmask to extract lower 160 bits from a uint256.
  uint256 private constant _BITMASK_LOWER160BITS = (1 << 160) - 1;

  /// @dev Bitmask to extract upper 96 bits from a uint256.
  uint256 private constant _BITMASK_UPPER96BITS = ((1 << 96) - 1) << 160;

  /// @dev Array of owned ERC-721 token IDs, each position stores a batch of tokens with the initial ID (_BITMASK_LOWER160BITS) and quantity (_BITMASK_UPPER96BITS).
  mapping(address holder => uint256[] batchArray) private _owned;

  /// @dev Mapping storing in each position the owner address (_BITMASK_LOWER160BITS) and index of this batch in _owned (_BITMASK_UPPER96BITS).
  mapping(uint256 tokenId => uint256 addressAndPosition) private _ownedData;

  /// @dev Bitmap storing the head of the batches, indicating where the _ownedData is located.
  BitMaps.BitMap private _batchHead;

  /// @dev Bitmap representing burned tokens.
  BitMaps.BitMap private _burnedTokens;

  /// @dev Amount of burned tokens.
  uint256 private _burnedCount = 0;

  /// @dev Queue of ERC-721 tokens in the stash.
  DoubleEndedQueue.Uint256Deque private _stashQueue;

  /// @dev Transfer(address,address,uint256) hash signature.
  bytes32 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

  /// @dev Approval(address,address,uint256) hash signature.
  bytes32 private constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;

  /// @dev ApprovalForAll(address,address,bool) hash signature.
  bytes32 private constant _APPROVALFORALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;

  /// @dev Stash address for this token.
  address private immutable _STASH_ADDRESS;

  /// @dev EIP-2612 nonces.
  mapping(address => uint256) public nonces;

  /// @dev Initial chain id for EIP-2612 support.
  uint256 internal immutable _INITIAL_CHAIN_ID;

  /// @dev Initial domain separator for EIP-2612 support.
  bytes32 internal immutable _INITIAL_DOMAIN_SEPARATOR;


  /**
   * @dev Initializes the contract with token details and necessary parameters.
   * 
   * @param name_ The name of the token.
   * @param symbol_ The symbol of the token.
   * @param unit_ The equivalence between 1 ERC721 token and ERC20 needed for that token.
   */
  constructor(string memory name_, string memory symbol_, uint256 unit_) {
    _name = name_;
    _symbol = symbol_;

    _DECIMALS = 18;
    _UNIT = unit_ * 10 ** _DECIMALS;
    _STASH_ADDRESS = address(new Stash());

    // EIP-2612 initialization
    _INITIAL_CHAIN_ID = block.chainid;
    _INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator();
  }

  /**
   * @dev Returns the starting token ID.
   * 
   * @return The starting token ID, which is set to 1 by default.
   * To change the starting token ID, please override this function.
   */
  function _startTokenId() internal pure returns (uint256) {
    return 1;
  }

  /**
   * @dev Returns the total number of tokens minted in the contract.
   * 
   * @return The total number of tokens minted.
   */
  function _totalMinted() internal view virtual returns (uint256) {
    return _nextTokenId - _startTokenId();
  }

  /**
   * @dev See {IERC165-supportsInterface}.
   */
  function supportsInterface(bytes4 interfaceId_) public view virtual returns (bool) {
    return interfaceId_ == type(IERC404B).interfaceId ||
           interfaceId_ == type(IERC165).interfaceId ||
           interfaceId_ == type(IERC20).interfaceId ||
           interfaceId_ == type(IERC721).interfaceId ||
           interfaceId_ == type(IERC721Receiver).interfaceId ||
           interfaceId_ == type(IERC721Metadata).interfaceId;
  }

  /// IERC20 + ERC721 Metadata Methods ///

  /**
   * @dev See {IERC404-name}.
   */
  function name() public view virtual override returns (string memory) {
    return _name;
  }

  /**
   * @dev See {IERC404-symbol}.
   */
  function symbol() public view virtual override returns (string memory) {
    return _symbol;
  }

  /**
   * @dev See {IERC404-decimals}.
   */
  function decimals() public view virtual override returns (uint8) {
    return _DECIMALS;
  }

  /**
   * @dev See {IERC404-unit}.
   */
  function unit() public view virtual returns (uint256) {
    return _UNIT;
  }

  /**
   * @dev See {IERC404-tokenURI}.
   */
  function tokenURI(uint256 tokenId_) public view virtual override returns (string memory) {
    if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_);
    string memory baseURI = _baseURI();
    return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId_.toString())) : "";
  }

  /**
   * @dev Base URI for computing the {tokenURI}. If set, the resulting URI for each
   * token will be the concatenation of the `baseURI` and the `tokenId`. 
   * 
   * It is empty by default and can be overridden in child contracts.
   * @return The base URI string.
   */
  function _baseURI() internal view virtual returns (string memory) {
    return "";
  }

  /**
   * @dev Checks whether the specified `tokenId` exists in the contract.
   * Tokens start existing when they are minted using the {_mint} function. Burned tokens are not considered to exist.
   * 
   * @param tokenId_ The ID of the token to check.
   * @return A boolean indicating whether the token exists.
   */
  function _exists(uint256 tokenId_) internal view virtual returns (bool) {
    if (_burnedTokens.get(tokenId_)) {
      return false;
    }
    return tokenId_ < _nextTokenId && _startTokenId() <= tokenId_;
  }

  /**
   * @dev See {IERC404-exists}.
   */
  function exists(uint256 tokenId_) external view virtual returns (bool) {
    return _exists(tokenId_);
  }

  /// ERC721 Methods ///

  /**
   * @dev See {IERC404-ownerOf}.
   */
  function ownerOf(uint256 tokenId_) public view virtual override returns (address owner) {
    if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_);
    uint256 data = _ownedData[_batchHead.scanForward(tokenId_)];
    assembly {
      owner := and(data, _BITMASK_LOWER160BITS)
    }
    if (owner == address(0)) {
      owner = _STASH_ADDRESS;
    }
  }

  /**
   * @dev See {IERC404-safeTransferFrom}.
   */
  function safeTransferFrom(address from_, address to_, uint256 tokenId_) public virtual override {
    safeTransferFrom(from_, to_, tokenId_, "");
  }

  /**
   * @dev See {IERC404-safeTransferFrom}.
   */
  function safeTransferFrom(address from_, address to_, uint256 tokenId_, bytes memory data_) public virtual override {
    if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_);
    if (!_isApprovedOrOwner(msg.sender, tokenId_)) revert ERC721InsufficientApproval(msg.sender, tokenId_);
    _safeTransferERC721(from_, to_, tokenId_, data_);
  }

  /**
   * @dev Safely transfers `tokenId_` token from `from_` to `to_`, ensuring the recipient contract
   * implements the ERC721Receiver interface to prevent tokens from being forever locked.
   *
   * `data_` is additional data without a specified format, included in the call to `to_`.
   *
   * This internal function is equivalent to {safeTransferFrom}, and can be used to implement alternative
   * token transfer mechanisms, such as signature-based ones.
   *
   * Requirements:
   * - `to_` cannot be the zero nor stash address.
   * - `tokenId_` must exist and be owned by `from_`.
   * - If `to_` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}.
   *
   * Emits a {Transfer} event.
   *
   * @param from_ The address sending the token.
   * @param to_ The address receiving the token.
   * @param tokenId_ The ID of the token being transferred.
   * @param data_ Additional data sent during the token transfer.
   */
  function _safeTransferERC721(address from_, address to_, uint256 tokenId_, bytes memory data_) internal virtual {
    if (!_checkOnERC721Received(from_, to_, tokenId_, 1, data_))
      revert ERC721ReceiverNotImplemented(to_, tokenId_, 1, data_);
    if (to_ == address(0) || to_ == _STASH_ADDRESS || to_ == from_) revert ERC721InvalidReceiver(to_);
    _transferERC721(from_, to_, tokenId_);
  }

  /**
   * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
   * 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 startTokenId_ The first ID of the tokens to be transferred.
   * @param quantity_ Amount of tokens to be transferred.
   * @param data_ Optional data to send along with the call.
   * @return r Boolean indicating whether the call returned the expected magic value.
   */
  function _checkOnERC721Received(address from_, address to_, uint256 startTokenId_, uint256 quantity_, bytes memory data_) private returns (bool r) {
    if (to_.code.length > 0) {
      r = true;
      for (uint256 tokenId = startTokenId_; tokenId < startTokenId_ + quantity_; tokenId++) {
        try IERC721Receiver(to_).onERC721Received(msg.sender, from_, tokenId, data_) returns (bytes4 retval) {
          r = r && retval == IERC721Receiver.onERC721Received.selector;
        } catch (bytes memory reason) {
          if (reason.length == 0) {
            revert ERC721ReceiverNotImplemented(to_, startTokenId_, quantity_, data_);
          } else {
            assembly {
              revert(add(32, reason), mload(reason))
            }
          }
        }
      }
      return r;
    } else {
      return true;
    }
  }

  /**
   * @dev Returns whether `spender` is allowed to manage `tokenId`.
   *
   * Requirements:
   * - `tokenId` must exist.
   *
   * @param spender_ The address being checked for approval.
   * @param tokenId_ The ID of the token being checked.
   * @return A boolean indicating whether `spender` is allowed to manage `tokenId`.
   */
  function _isApprovedOrOwner(address spender_, uint256 tokenId_) internal view virtual returns (bool) {
    address owner = ownerOf(tokenId_);
    return (spender_ == owner || getApproved(tokenId_) == spender_ || isApprovedForAll(owner, spender_));
  }

  /**
   * @dev Adds a batch of tokens to the `_owned` mapping for the given owner.
   *
   * @param batchInitialId_ The initial ID of the batch of tokens.
   * @param owner_ The address of the owner.
   * @param quantity_ The quantity of tokens in the batch.
   */
  function _pushOwned(uint256 batchInitialId_, address owner_, uint256 quantity_) internal virtual {
    uint256 data;
    assembly {
      data := add(and(batchInitialId_, _BITMASK_LOWER160BITS), and(shl(160, quantity_), _BITMASK_UPPER96BITS))
    }
    _owned[owner_].push(data);
  }

  /**
   * @dev Sets the data for a specific batch of tokens in the `_owned` mapping for the given owner and index.
   *
   * @param batchInitialId_ The initial ID of the batch of tokens.
   * @param owner_ The address of the owner.
   * @param index_ The index of the batch in the `_owned` array.
   * @param quantity_ The quantity of tokens in the batch.
   */
  function _setOwned(uint256 batchInitialId_, address owner_, uint256 index_, uint256 quantity_) internal virtual {
    uint256 data;
    assembly {
      data := add(and(batchInitialId_, _BITMASK_LOWER160BITS), and(shl(160, quantity_), _BITMASK_UPPER96BITS))
    }
    _owned[owner_][index_] = data;
  }

  /**
   * @dev Retrieves the initial ID and quantity of tokens in a batch owned by a specific address.
   *
   * @param owner_ The address of the token owner.
   * @param index_ The index of the batch in the owner's collection.
   * @return batchInitialId The initial ID of the tokens in the batch.
   * @return batchQuantity The quantity of tokens in the batch.
   */
  function _getOwnedBatchInitialIdAndQuantity(address owner_, uint256 index_) internal view virtual returns (uint256 batchInitialId, uint256 batchQuantity) {
    uint256 data = _owned[owner_][index_];
    assembly {
      batchInitialId := and(data, _BITMASK_LOWER160BITS)
      batchQuantity := shr(160, data)
    }
  }

  /**
   * @dev Sets the data for a batch of owned tokens at a specific index in the _ownedData mapping.
   * This function is used to update the data associated with a batch of tokens owned by an address.
   * It ensures that the index does not exceed the upper limit defined by _BITMASK_UPPER96BITS >> 160.
   *
   * @param batchInitialId_ The initial ID of the tokens in the batch.
   * @param ownerOf_ The address of the owner of the tokens in the batch.
   * @param index_ The index of the batch within the _owned[ownerOf_] mapping.
   */
  function _setOwnedData(uint256 batchInitialId_, address ownerOf_, uint256 index_) internal virtual {
    if (index_ > _BITMASK_UPPER96BITS >> 160) {
      revert ERC404OwnedIndexOverflow(index_);
    }
    uint256 data;
    assembly {
      data := add(and(ownerOf_, _BITMASK_LOWER160BITS), and(shl(160, index_), _BITMASK_UPPER96BITS))
    }
    _ownedData[batchInitialId_] = data;
  }

  /**
   * @dev Retrieves the owner, index within the owner's batch, and token ID at the head of the batch for the given token ID.
   *
   * Requirements:
   * - The token ID must exist.
   *
   * @param tokenId_ The ID of the token for which to retrieve information.
   * @return owner The address of the token's owner.
   * @return index The index of the token within the owner's batch.
   * @return tokenIdBatchHead The token ID at the head of the batch.
   */
  function _getOwnerOwnedIndexAndBatchHeadId(uint256 tokenId_) internal view returns (address owner, uint256 index, uint256 tokenIdBatchHead) {
    tokenIdBatchHead = _batchHead.scanForward(tokenId_);
    uint256 data = _ownedData[tokenIdBatchHead];
    assembly {
      index := shr(160, data)
      owner := and(data, _BITMASK_LOWER160BITS)
    }
  }

  /**
   * @dev Transfers an ERC721 token from one address to another.
   *
   * Requirements:
   * - `from_` must be the owner of the token.
   * - Token ID must exist and be owned by `from_`.
   * - If `to_` is a smart contract, it must implement {IERC721Receiver-onERC721Received}.
   * - If `to_` is exempt from ERC721 transfer, the token is moved to the stash.
   *
   * Emits an {IERC721-Transfer} event.
   * Emits an {IERC20-Transfer} event.
   *
   * @param from_ The address transferring the token.
   * @param to_ The address receiving the token.
   * @param tokenId_ The ID of the token being transferred.
   */
  function _transferERC721(address from_, address to_, uint256 tokenId_) internal virtual {
    (address owner, uint256 index, uint256 tokenIdBatchHead) = _getOwnerOwnedIndexAndBatchHeadId(tokenId_);
    // _beforeTokenTransfers(from_, to_, tokenId_, 1);

    delete _tokenApprovals[tokenId_]; // On transfer, any previous approval is reset.

    uint256 batchQuantity;
    uint256 data = _owned[owner][index];
    assembly {
      batchQuantity := shr(160, data)
    }
    _removeTokenFrom(from_, index, tokenId_, tokenIdBatchHead, batchQuantity);

    if (_erc721TransferExempt[to_]) {
      // Is exempt: move to stash
      _batchHead.set(tokenId_);
      _stashQueue.pushFront(tokenId_);

      address mutableStashAddress = _STASH_ADDRESS;
      assembly {
        // Emit ERC721.Transfer(from_, _STASH_ADDRESS, tokenId_)
        log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(mutableStashAddress, _BITMASK_LOWER160BITS), tokenId_)
      }
    }
    else {
      // Add ownership to "to_"
      assembly {
        data := add(and(tokenId_, _BITMASK_LOWER160BITS), and(shl(160, 1), _BITMASK_UPPER96BITS))
      }
      _owned[to_].push(data);
      uint256 index_ = _owned[to_].length - 1;
      assembly {
        data := add(and(to_, _BITMASK_LOWER160BITS), and(shl(160, index_), _BITMASK_UPPER96BITS))
      }
      _ownedData[tokenId_] = data;

      assembly {
        // emit IERC721.Transfer(from_, to_, tokenId_);
        log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS), tokenId_)
      }
    }

    unchecked {
      // `_balances[from]` cannot overflow for the same reason as described in `_burn`:
      // `from`'s balance is the number of token held, which is at least one before the current
      // transfer.
      // `_balances[to]` could overflow in the conditions described in `_mint`. That would require
      // all 2**256 token ids to be minted, which in practice is impossible.
      _balances[from_] -= _UNIT;
      _balances[to_] += _UNIT;
    }

    data = _UNIT;
    assembly {
      // emit IERC20.Transfer(from_, to_, _UNIT);
      mstore(0x00, data)
      log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS))
    }
    // _afterTokenTransfers(from_, to_, tokenId_, 1);
  }

  /**
   * @dev Removes a token from an address, adjusting the internal data structures accordingly.
   *
   * Requirements:
   * - `from_` must be the owner of the token.
   *
   * @param from_ The address from which the token is being removed.
   * @param index_ The index of the token within the owner's batch.
   * @param tokenId_ The ID of the token being removed.
   * @param batchInitialId_ The initial ID of the batch.
   * @param batchQuantity_ The quantity of tokens in the batch.
   */
  function _removeTokenFrom(address from_, uint256 index_, uint256 tokenId_, uint256 batchInitialId_, uint256 batchQuantity_) internal {
    unchecked {
      // If Is Batch Head == No tokens before in the batch.
      if (batchInitialId_ == tokenId_) {
        if (batchQuantity_ == 1) {
          _removeSingleToken(from_, index_);
        } else {
          _removeBatchHeadToken(from_, index_, tokenId_, batchQuantity_);
        }
      } else {
        // Is not batch head == There is tokens before for the
        _removeNonHeadToken(from_, index_, tokenId_, batchInitialId_, batchQuantity_);
      }
    }
  }

  /**
   * @dev Removes a single token from the owner's collection.
   * 
   * This internal function is used during ERC721 token transfers to remove a single token from the owner's collection.
   * It shifts the token data in the owner's collection to fill the gap left by the removed token, ensuring continuous indexing.
   * If the removed token is not the last token in the collection, it updates the metadata and batch information accordingly.
   *
   * @param from_ The address of the owner from which the token is being removed.
   * @param index_ The index of the token in the owner's collection to be removed.
   */
  function _removeSingleToken(address from_, uint256 index_) internal {
    unchecked {
      uint256[] storage ownedFrom = _owned[from_];
      uint256 fromStackLastIndex = ownedFrom.length - 1;
      if (fromStackLastIndex != index_) {
        uint256 data = ownedFrom[fromStackLastIndex];
        ownedFrom[index_] = data;
        uint256 lastBatchInitialId;
        assembly {
          lastBatchInitialId := and(data, _BITMASK_LOWER160BITS)
          data := add(and(from_, _BITMASK_LOWER160BITS), and(shl(160, index_), _BITMASK_UPPER96BITS))
        }
        _ownedData[lastBatchInitialId] = data;
      }
      ownedFrom.pop();
    }
  }

  /**
   * @dev Removes the batch head token from the owner's collection.
   * 
   * This internal function is used during ERC721 token transfers to remove the batch head token from the owner's collection.
   * It sets the subsequent token ID as the new batch head, updates the batch information, and shifts the remaining tokens accordingly.
   *
   * @param from_ The address of the owner from which the batch head token is being removed.
   * @param index_ The index of the batch head token in the owner's collection to be removed.
   * @param tokenId_ The ID of the batch head token being removed.
   * @param batchQuantity_ The quantity of tokens in the batch (including the batch head).
   */
  function _removeBatchHeadToken(address from_, uint256 index_, uint256 tokenId_, uint256 batchQuantity_) internal {
    unchecked {
      uint256 subsequentTokenId = tokenId_ + 1;
      _batchHead.set(subsequentTokenId);

      uint256 data;
      assembly {
        data := add(and(from_, _BITMASK_LOWER160BITS), and(shl(160, index_), _BITMASK_UPPER96BITS))
      }
      _ownedData[subsequentTokenId] = data;

      assembly {
        data := add(
          and(subsequentTokenId, _BITMASK_LOWER160BITS),
          and(shl(160, sub(batchQuantity_, 1)), _BITMASK_UPPER96BITS)
        )
      }
      _owned[from_][index_] = data;
    }
  }

  /**
   * @dev Removes a non-head token from the owner's collection within a batch.
   * 
   * This internal function is used during ERC721 token transfers to remove a token that is not the batch head from the owner's collection within a batch.
   * It updates the batch information, shifts the remaining tokens accordingly, and creates a new batch if necessary.
   *
   * @param from_ The address of the owner from which the token is being removed.
   * @param index_ The index of the token in the owner's collection to be removed.
   * @param tokenId_ The ID of the token being removed.
   * @param batchInitialId_ The ID of the first token in the batch.
   * @param batchQuantity_ The quantity of tokens in the batch.
   */
  function _removeNonHeadToken(address from_, uint256 index_, uint256 tokenId_, uint256 batchInitialId_, uint256 batchQuantity_) internal {
    unchecked {
      _batchHead.set(tokenId_);
      uint256 batchSizeAndIndex = tokenId_ - batchInitialId_;
      uint256 data;
      assembly {
        data := add(and(batchInitialId_, _BITMASK_LOWER160BITS), and(shl(160, batchSizeAndIndex), _BITMASK_UPPER96BITS))
      }
      _owned[from_][index_] = data;

      if (batchSizeAndIndex < batchQuantity_ - 1) {
        // It means that the batch continues
        uint256 subsequentTokenId = tokenId_ + 1;
        _batchHead.set(subsequentTokenId);

        batchSizeAndIndex = (batchQuantity_ - 1) - (tokenId_ - batchInitialId_);
        assembly {
          data := add(and(subsequentTokenId, _BITMASK_LOWER160BITS), and(shl(160, batchSizeAndIndex), _BITMASK_UPPER96BITS))
        }
        _owned[from_].push(data);

        batchSizeAndIndex = _owned[from_].length - 1;
        assembly {
          data := add(and(from_, _BITMASK_LOWER160BITS), and(shl(160, batchSizeAndIndex), _BITMASK_UPPER96BITS))
        }
        _ownedData[subsequentTokenId] = data;
      }
    }
  }

  /**
   * @dev See {IERC404-getApproved}.
   */
  function getApproved(uint256 tokenId_) public view virtual override returns (address) {
    if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_);
    return _tokenApprovals[tokenId_];
  }

  /**
   * @dev See {IERC404-setApprovalForAll}.
   */
  function setApprovalForAll(address operator_, bool approved_) public virtual override {
    address owner = msg.sender;
    if(operator_ == owner) revert ERC721InvalidOperator(operator_);
    _operatorApprovals[owner][operator_] = approved_;
    assembly {
      // emit IERC721.ApprovalForAll(owner, operator, approved);
      mstore(0x00, approved_)
      log3(0x00, 0x20, _APPROVALFORALL_EVENT_SIGNATURE, and(owner, _BITMASK_LOWER160BITS), and(operator_, _BITMASK_LOWER160BITS))
    }
  }

  /**
   * @dev See {IERC404-isApprovedForAll}.
   */
  function isApprovedForAll(address owner_, address operator_) public view virtual override returns (bool) {
    return _operatorApprovals[owner_][operator_];
  }

  /**
   * @dev Safely mints a specified quantity of ERC721 tokens and assigns them to the specified address.
   *
   * This internal function is equivalent to calling `_safeMint(to, quantity, "")`, providing an empty data parameter.
   * It ensures that the minted tokens are safely transferred to the recipient by calling the ERC721 safe transfer function.
   *
   * @param to_ The address to which the minted tokens will be assigned.
   * @param quantity_ The number of tokens to mint.
   */
  function _safeMint(address to_, uint256 quantity_) internal virtual {
    _safeMint(to_, quantity_, "");
  }

  /**
   * @dev Safely mints a specified quantity of ERC721 tokens and assigns them to the specified address.
   *
   * This internal function is equivalent to calling `_mint(to_, quantity_)` followed by a check to ensure that the recipient contract implements ERC721Receiver.
   * It requires the recipient contract to implement the ERC721Receiver interface's `onERC721Received` function to receive the tokens safely.
   *
   * @param to_ The address to which the minted tokens will be assigned.
   * @param quantity_ The number of tokens to mint.
   * @param data_ Additional data sent along with the token transfer, if any.
   */
  function _safeMint(address to_, uint256 quantity_, bytes memory data_) internal virtual {
    if (!_checkOnERC721Received(address(0), to_, _nextTokenId, quantity_, data_)) {
      revert ERC721ReceiverNotImplemented(to_, _nextTokenId, quantity_, data_);
    }
    _mint(to_, quantity_);
  }


  /**
   * @dev Mints a specified quantity of ERC721 tokens and assigns them to the specified address.
   *
   * This internal function performs the minting of ERC721 tokens and updates the balances accordingly. 
   * It also emits one ERC20 Transfer event and a ERC721 Transfer event for each minted token.
   * If the recipient address is exempt from ERC721 transfer fees, the method sets the batch head accordingly; 
   * otherwise, it adds the minted tokens to the recipient's ownership.
   *
   * Requirements:
   * - `quantity_` must be greater than 0.
   * - `to_` address must not be the zero nor stash address.
   *
   * Emits an IERC20 {Transfer} event.
   * Emits an IERC721 {Transfer} event for each minted token.
   *
   * @param to_ The address to which the minted tokens will be assigned.
   * @param quantity_ The number of tokens to mint.
   */
  function _mint(address to_, uint256 quantity_) internal virtual {
    if (quantity_ == 0) revert ERC721InvalidMintQuantity();
    if (to_ == address(0) || to_ == _STASH_ADDRESS) revert ERC20InvalidReceiver(to_);
    // _beforeTokenTransfers(address(0), to_, _nextTokenId, quantity_);

    uint256 value;
    uint256 toMasked;
    uint256 end;
    uint256 batchTokenId = _nextTokenId;
    unchecked {
      value = quantity_ * _UNIT;
      _balances[to_] += value; // May overflow in big quantities if total balance not controlled. 
      end = batchTokenId + quantity_;
    }

    assembly {
      // emit IERC20.Transfer(0x00, to_, _UNIT);
      toMasked := and(to_, _BITMASK_LOWER160BITS)
      mstore(0x00, value)
      log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, 0x00, toMasked)
    }

    if (_erc721TransferExempt[to_]) {
      _batchHead.setBatch(batchTokenId, quantity_);
    } else {
      _batchHead.set(batchTokenId);
      _pushOwned(batchTokenId, to_, quantity_);
      _setOwnedData(batchTokenId, to_, _owned[to_].length - 1);

      // Use assembly to loop and emit the `Transfer` event for gas savings.
      // The duplicated `log4` removes an extra check and reduces stack juggling.
      assembly {
        // emit IERC721.Transfer(0x00, to_, batchTokenId);
        log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, 0x00, toMasked, batchTokenId)

        // The `iszero(eq(,))` check ensures that large values of `quantity`
        // that overflows uint256 will make the loop run out of gas.
        // The compiler will optimize the `iszero` away for performance.
        for {
          let tokenId := add(batchTokenId, 1)
        } iszero(eq(tokenId, end)) {
          tokenId := add(tokenId, 1)
        } {
          // emit IERC721.Transfer(0x00, to_, tokenId);
          log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, 0x00, toMasked, tokenId)
        }
      }
    }

    // _afterTokenTransfers(address(0), to_, _nextTokenId, quantity_);
    unchecked {
      _nextTokenId += quantity_;
    }
  }

  /// ERC20 Methods ///

  /**
   * @dev See {IERC404-totalSupply}.
   */
  function totalSupply() public view virtual override returns (uint256) {
    return _totalTokens() * _UNIT;
  }

  /**
   * @dev Calculates the total number of tokens that have been minted and not burned.
   *
   * This internal function returns the difference between the total minted tokens and the burned tokens, representing the total number of existing tokens in circulation.
   *
   * @return The total number of existing tokens in circulation.
   */
  function _totalTokens() internal view virtual returns (uint256) {
    return _totalMinted() - _burned();
  }

  /**
   * @dev Retrieves the total number of tokens that have been burned.
   *
   * This internal function returns the count of tokens that have been burned within the contract.
   *
   * @return The total number of tokens that have been burned.
   */
  function _burned() internal view virtual returns (uint256) {
    return _burnedCount;
  }

  /**
   * @dev See {IERC404-transfer}.
   */
  function transfer(address to_, uint256 valueOrId_) public virtual override returns (bool) {
    address owner = msg.sender;
    transferFrom(owner, to_, valueOrId_); 
    return true;
  }

  /**
   * @dev See {IERC404-allowance}.
   */
  function allowance(address owner_, address spender_) public view virtual override returns (uint256) {
    return _allowances[owner_][spender_];
  }

  /// ERC404 Combined (Methods with similar interfaces and behavior in ERC20 & ERC721) ///

  /**
   * @dev See {IERC404-balanceOf}.
   */
  function balanceOf(address account_) public view virtual override returns (uint256) {
    return _balances[account_];
  }

  /**
   * @dev See {IERC404-transferFrom}.
   */
  function transferFrom(address from_, address to_, uint256 valueOrId_) public virtual returns (bool) {
    if (_exists(valueOrId_)) {
      safeTransferFrom(from_, to_, valueOrId_, "");
    } else {
      return _transferFromERC20(from_, to_, valueOrId_);
    }
    return true;
  }

  /**
   * @dev Transfers ERC20 tokens from one address to another, handling ERC721 exemptions internally.
   *
   * This function is used to transfer ERC20 tokens directly between addresses, handling exemptions for ERC721 transfers
   * internally. It checks for valid recipients, allowances, and handles ERC721 exemptions if the recipient address is
   * exempt from ERC721 transfers.
   *
   * Requirements:
   * - `to_` cannot be the zero address or the stash address.
   *
   * @param from_ The address sending the ERC20 tokens.
   * @param to_ The address receiving the ERC20 tokens.
   * @param value_ The amount of ERC20 tokens to transfer.
   * @return A boolean indicating whether the transfer was successful.
   */
  function _transferFromERC20(address from_, address to_, uint256 value_) public virtual returns (bool) {
    if (to_ == address(0) || to_ == _STASH_ADDRESS || to_ == from_) revert ERC20InvalidReceiver(to_);

    if (from_ != msg.sender) {
      uint256 allowed = _allowances[from_][msg.sender];

      // Check that the operator has sufficient allowance.
      if (allowed != type(uint256).max) {
        if(value_ > allowed) revert ERC20InsufficientAllowance(from_, allowed, value_);
        _allowances[from_][msg.sender] = allowed - value_;
      }
    }

    // Transferring ERC-20s directly requires the _transferERC20WithERC721 function.
    return _transferERC20WithERC721(from_, to_, value_);
  }

  /**
   * @dev This function handles the transfer of ERC-20 tokens and optionally adjusts the ERC-721 token balances based on the transfer exemptions.
   * 
   * Requirements:
   * - The sender (`from_`) must have a balance of at least `value_`.
   * 
   * Emits:
   * - {IERC20.Transfer} event for ERC-20 and possibly a {IERC721.Transfer} for each ERC-721 Token.
   * 
   * @param from_ Address sending the tokens.
   * @param to_ Address receiving the tokens.
   * @param value_ Amount of ERC-20 tokens to transfer.
   * @return bool True if the transfer is successful.
   */
  function _transferERC20WithERC721(address from_, address to_, uint256 value_) internal virtual returns (bool) {
    uint256 erc20BalanceOfSenderBefore = _balances[from_];
    uint256 erc20BalanceOfReceiverBefore = _balances[to_];

    if (erc20BalanceOfSenderBefore < value_) revert ERC20InsufficientBalance(from_, erc20BalanceOfSenderBefore, value_);

    unchecked {
      _balances[from_] -= value_;
      _balances[to_] += value_;
    }

    assembly {
      // emit IERC20.Transfer(from_, to_, value_);
      mstore(0x00, value_)
      log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS))
    }

    // Skip ERC-721 transfer to exempt addresses to save gas
    bool isFromERC721TransferExempt = _erc721TransferExempt[from_];
    bool isToERC721TransferExempt = _erc721TransferExempt[to_];
    if (isFromERC721TransferExempt && isToERC721TransferExempt) {
      // Case 1) Both sender and recipient are ERC-721 transfer exempt. No ERC-721s need to be transferred.
    } else if (isFromERC721TransferExempt) {
      // Case 2) The sender is ERC-721 transfer exempt, but the recipient is not. 
      unchecked {
        uint256 tokensToRetrieveFromStash = (_balances[to_] / _UNIT) - (erc20BalanceOfReceiverBefore / _UNIT);
        _retrieveFromStash(to_, tokensToRetrieveFromStash);
      }
    } else if (isToERC721TransferExempt) {
      // Case 3) The sender is not ERC-721 transfer exempt, but the recipient is. 
      unchecked {
        uint256 tokensToStash = (erc20BalanceOfSenderBefore / _UNIT) - (_balances[from_] / _UNIT);
        _stash(from_, tokensToStash);
      }
    } else {
      // Case 4) Neither the sender nor the recipient are ERC-721 transfer exempt.
      _batchTransferERC721WithBalanceAdjustment(from_, to_, erc20BalanceOfSenderBefore, erc20BalanceOfReceiverBefore, value_);
    }
    return true;
  }

  /**
   * @dev Internal function to batch transfer ERC721 tokens with balance adjustment.
   * 
   * Emits a {IERC721.Transfer} event for each token transferred, including the initial token ID and all subsequent IDs in the batch.
   *
   * @param from_ The address from which to transfer tokens.
   * @param to_ The address to which to transfer tokens.
   * @param fromPreviousBalance_ The previous balance of tokens for the sender.
   * @param toPreviousBalance_ The previous balance of tokens for the recipient.
   * @param transferedValue_ The value of tokens to be transferred.
   */
  function _batchTransferERC721WithBalanceAdjustment(address from_, address to_, uint256 fromPreviousBalance_, uint256 toPreviousBalance_, uint256 transferedValue_) internal {
    uint256 tokenId;
    uint256 end;
    uint256 nftsToTransfer = transferedValue_ / _UNIT;
    for (uint256 i = 0; i < nftsToTransfer; ) {
      // Transfers the whole batch
      uint256 lastOwnedIndex = _owned[from_].length - 1;
      (uint256 batchInitialId_, uint256 batchQuantity_) = _getOwnedBatchInitialIdAndQuantity(from_, lastOwnedIndex);

      if (batchQuantity_ + i <= nftsToTransfer) {
        // Transfer whole batch
        _owned[to_].push(_owned[from_][lastOwnedIndex]);
        _owned[from_].pop();

        uint256 lastToIndex = _owned[to_].length - 1;
        _setOwnedData(batchInitialId_, to_, lastToIndex);

        unchecked {
          tokenId = batchInitialId_;
          end = batchInitialId_ + batchQuantity_;
          i += batchQuantity_;
        }
      } else {
        // Transfers part of the batch
        unchecked {
          uint256 tokensToTransfer = nftsToTransfer - i;
          uint256 tokensInPreviousBatch = batchQuantity_ - tokensToTransfer;
          _setOwned(batchInitialId_, from_, lastOwnedIndex, tokensInPreviousBatch);

          uint256 newBatchInitialId = batchInitialId_ + tokensInPreviousBatch;
          _batchHead.set(newBatchInitialId);
          _pushOwned(newBatchInitialId, to_, tokensToTransfer);
          _setOwnedData(newBatchInitialId, to_, _owned[to_].length - 1);

          tokenId = newBatchInitialId;
          end = newBatchInitialId + tokensToTransfer;
          i = nftsToTransfer;
        }
      }
      unchecked {
        for (uint256 j = tokenId; j < end; ++j) {
          delete _tokenApprovals[j]; // On transfer, any previous approval is reset.

          assembly {
            // emit IERC721.Transfer(from_, to_, emitInitialId);
            log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS), j)
          }
        }
      }
    }

    // If the transfer changes either the sender or the recipient's holdings from a fractional to a non-fractional
    // amount (or vice versa), adjust ERC-721s.
    unchecked {
      // First check if the send causes the sender to lose a whole token that was represented by an ERC-721
      // due to a fractional part being transferred.
      if (fromPreviousBalance_ / _UNIT - _balances[from_] / _UNIT > nftsToTransfer) {
        _stash(from_, 1);
      }

      // Then, check if the transfer causes the receiver to gain a whole new token which requires gaining
      // an additional ERC-721.
      if (_balances[to_] / _UNIT - toPreviousBalance_ / _UNIT > nftsToTransfer) {
        _retrieveFromStash(to_);
      }
    }
  }

  /**
   * @dev Internal virtual function to stash ERC721 tokens.
   * 
   * Emits a {IERC721.Transfer} event for each token stashed.
   *
   * @param from_ The address from which to stash tokens.
   * @param quantity_ The quantity of tokens to be stashed.
   */
  function _stash(address from_, uint256 quantity_) internal virtual {
    unchecked {
      uint256 batchInitialId_;
      uint256 batchQuantity_;
      uint256 data;
      // Stash loop variables
      uint256 begin;
      uint256 end;

      for (uint256 stashed = 0; stashed < quantity_; ) {
        data = _owned[from_][_owned[from_].length - 1];
        assembly {
          batchInitialId_ := and(data, _BITMASK_LOWER160BITS)
          batchQuantity_ := shr(160, data)
        }
        if (stashed + batchQuantity_ <= quantity_) {
          // Transfer the whole batch
          delete _ownedData[batchInitialId_];
          _batchHead.setBatch(batchInitialId_, batchQuantity_); // Set batchead in a massive way to all tokens.
          _owned[from_].pop(); // Remove batch from owned ids
          stashed += batchQuantity_; // Increment the stashed items
          begin = batchInitialId_; 
          end = begin + batchQuantity_;
        } else {
          // Only transfer the amount needed, maintain the batch
          uint256 tokensToStash = quantity_ - stashed;
          uint256 nonStashedBatchSize = batchQuantity_ - tokensToStash;
          begin = batchInitialId_ + nonStashedBatchSize;
          end = begin + tokensToStash;
          _batchHead.setBatch(begin, tokensToStash); // Set batchead in a massive way to all tokens to be stashed
          _setOwned(batchInitialId_, from_, _owned[from_].length - 1, nonStashedBatchSize); // Update the batch size
          stashed = quantity_; // Update the stashed items
        }
        address mutableStashAddress = _STASH_ADDRESS;
        for (uint256 i=begin; i<end; ++i) {
          _stashQueue.pushFront(i);
          delete _tokenApprovals[i]; // On stash of a token, any previous approval is reset.
          assembly {
            // emit IERC721.Transfer(from_, _STASH_ADDRESS, tokenId);
            log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(mutableStashAddress, _BITMASK_LOWER160BITS), i)
          }
        }
      }
    }
  }

  /**
   * @dev Internal virtual function to retrieve ERC721 tokens from the stash.
   * 
   * Emits a {IERC721.Transfer} event for each token retrieved.
   *
   * @param to_ The address to which retrieved tokens will be transferred.
   */
  function _retrieveFromStash(address to_) internal virtual {
    uint256 id = _stashQueue.popBack();
    _pushOwned(id, to_, 1);
    unchecked {
      _setOwnedData(id, to_, _owned[to_].length - 1);
    }

    address mutableStashAddress = _STASH_ADDRESS;
    assembly {
      // emit IERC721.Transfer(_STASH_ADDRESS, to_, tokenId);
      log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(mutableStashAddress, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS), id)
    }
  }

  /**
   * @dev Internal function to retrieve multiple ERC721 tokens from the stash and transfer them to a recipient.
   * 
   * Emits a {IERC721.Transfer} event for each token retrieved, including the token ID transferred to the recipient.
   * 
   * @param to_ The address to which retrieved tokens will be transferred.
   * @param amount_ The number of tokens to retrieve from the stash.
   */
  function _retrieveFromStash(address to_, uint256 amount_) internal {
    for (uint256 i = 0; i < amount_; ) {
      _retrieveFromStash(to_);
      unchecked {
        ++i;
      }
    }
  }

  /**
   * @dev See {IERC404-approve}.
   */
  function approve(address spender_, uint256 valueOrId_) public virtual returns (bool) {
    if (_exists(valueOrId_)) {
      _erc721Approve(spender_, valueOrId_);
    } else {
      return _erc20Approve(spender_, valueOrId_);
    }
    return true;
  }

  /**
   * @dev Approves a specific address to transfer the specified ERC-721 token.
   * 
   * Requirements:
   * - The caller must be the owner of the ERC-721 token or have been approved by the owner.
   * 
   * Emits:
   * - {IERC721.Approval} event for ERC-721 Tokens.
   * 
   * @param spender_ Address to be approved for the specified ERC-721 token.
   * @param id_ ID of the ERC-721 token to be approved.
   */
  function _erc721Approve(address spender_, uint256 id_) public virtual {
    address erc721Owner = ownerOf(id_);
    if (msg.sender != erc721Owner && !isApprovedForAll(erc721Owner, msg.sender)) {
      revert ERC721InvalidApprover(msg.sender);
    }
    _tokenApprovals[id_] = spender_;

    assembly {
      // emit IERC721.Approval(erc721Owner, spender_, id_);
      log4(0x00, 0x00, _APPROVAL_EVENT_SIGNATURE, and(erc721Owner, _BITMASK_LOWER160BITS), and(spender_, _BITMASK_LOWER160BITS), id_)
    }
  }

  /**
   * @dev Approves a specific address to spend a specified amount of ERC-20 tokens on behalf of the caller.
   * 
   * Requirements:
   * - The spender address must not be the zero address.
   * 
   * Emits:
   * - {IERC20.Approval} event for ERC-20 Tokens.
   * 
   * @param spender_ Address to be approved for spending the specified ERC-20 tokens.
   * @param value_ Amount of ERC-20 tokens to be approved for spending.
   * @return bool True if the approval is successful.
   */
  function _erc20Approve(address spender_, uint256 value_) public virtual returns (bool) {
    address owner = msg.sender;
    if (spender_ == address(0) || spender_ == _STASH_ADDRESS) {
      revert ERC20InvalidSpender(spender_);
    }
    _allowances[owner][spender_] = value_;

    assembly {
      // emit IERC20.Approval(msg.sender, spender_, value_);
      let ownerMasked := and(owner, _BITMASK_LOWER160BITS)
      let approvedMasked := and(spender_, _BITMASK_LOWER160BITS)
      mstore(0x00, value_)
      log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, ownerMasked, approvedMasked)
    }
    return true;
  }

  /**
   * @dev See {IERC20Permit-permit}. 
   */
  function permit(address owner_, address spender_, uint256 value_, uint256 deadline_, uint8 v_, bytes32 r_, bytes32 s_) public virtual {
    if (deadline_ < block.timestamp) {
      revert EIP2612PermitDeadlineExpired(owner_, spender_, value_, deadline_, v_, r_, s_);
    }

    // permit cannot be used for ERC-721 token approvals, so ensure
    // the value does not fall within the valid range of ERC-721 token ids.
    if (_exists(value_)) {
      revert ERC404InvalidTransferValue(value_);
    }

    if (spender_ == address(0) || spender_ == _STASH_ADDRESS) {
      revert ERC20InvalidSpender(spender_);
    }

    unchecked {
      address recoveredAddress = ecrecover(
        keccak256(
          abi.encodePacked(
            "\x19\x01",
            DOMAIN_SEPARATOR(),
            keccak256(
              abi.encode(
                keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"),
                owner_,
                spender_,
                value_,
                nonces[owner_]++,
                deadline_
              )
            )
          )
        ),
        v_,
        r_,
        s_
      );

      if (recoveredAddress == address(0) || recoveredAddress != owner_) {
        revert EIP2612InvalidSigner(recoveredAddress, owner_, spender_, value_, deadline_, v_, r_, s_);
      }

      _allowances[recoveredAddress][spender_] = value_;
    }

    assembly {
      // emit IERC20.Approval(owner_, spender_, value_);
      let ownerMasked := and(owner_, _BITMASK_LOWER160BITS)
      let approvedMasked := and(spender_, _BITMASK_LOWER160BITS)
      mstore(0x00, value_)
      log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, ownerMasked, approvedMasked)
    }
  }

  /**
   * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. 
   */
  function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
    return block.chainid == _INITIAL_CHAIN_ID ? _INITIAL_DOMAIN_SEPARATOR : _computeDomainSeparator();
  }

  /**
   * @notice Internal function to compute the domain separator for EIP-2612 permits.
   * @dev This function computes the domain separator based on the contract's name, version, chain ID, and address.
   * 
   * @return bytes32 The computed domain separator value.
   */
  function _computeDomainSeparator() internal view virtual returns (bytes32) {
    return
      keccak256(
        abi.encode(
          keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
          keccak256(bytes(_name)),
          keccak256("1"),
          block.chainid,
          address(this)
        )
      );
  }

  /**
   * @dev See {IERC404-isERC721TransferExempt}. 
   */
  function isERC721TransferExempt(address target_) external view override returns (bool isExempt) {
    isExempt = _erc721TransferExempt[target_];
  }

  /**
   * @dev See {IERC404-setERC721TransferExempt}. 
   */
  function setERC721TransferExempt(bool state_) external override {
    _setERC721TransferExempt(msg.sender, state_);
  }

  /**
   * @dev Internal function to set the exemption status for ERC-721 transfers.
   * 
   * Requirements:
   * - `target_` address cannot be the zero address or the stash address.
   * 
   * @param target_ The address for which to set the exemption status.
   * @param state_ The new exemption state to set (true for exempt, false for non-exempt).
   */
  function _setERC721TransferExempt(address target_, bool state_) internal virtual {
    if (target_ == address(0) || target_ == _STASH_ADDRESS) {
      revert ERC404InvalidERC721Exemption(target_);
    }

    // Adjust the ERC721 balances of the target to respect exemption rules.
    if (state_) {
      _stashAll(target_);
    } else {
      _retrieveAllFromStash(target_);
    }

    _erc721TransferExempt[target_] = state_;
  }

  /**
   * @dev Internal function to stash all ERC-721 tokens owned by the target address.
   * 
   * Emits:
   * - {IERC721.Transfer} event for ERC-721 tokens being transferred to the stash.
   * 
   * @param target_ The address whose tokens are to be stashed.
   */
  function _stashAll(address target_) private {
    uint256[] memory ownedTarget = _owned[target_];
    for (uint256 i = 0; i < ownedTarget.length; ) {
      (uint256 batchInitialId_, uint256 batchQuantity_) = _getOwnedBatchInitialIdAndQuantity(target_, i);
      delete _ownedData[batchInitialId_]; // Resets _ownedData
      _batchHead.setBatch(batchInitialId_, batchQuantity_); // Set batchead in a massive way to all tokens.

      // add all tokens to the stash
      unchecked {
        uint256 end = batchInitialId_ + batchQuantity_;
        address mutableStashAddress = _STASH_ADDRESS;

        for (uint256 b = batchInitialId_; b < end; ++b) {
          delete _tokenApprovals[b]; // On stash of a token, any previous approval is reset.
          _stashQueue.pushFront(b);
          assembly {
            // emit IERC721.Transfer(target_, _STASH_ADDRESS, batchInitialId_);
            log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(target_, _BITMASK_LOWER160BITS), and(mutableStashAddress, _BITMASK_LOWER160BITS), b)
          }
        }
        ++i;
      }
    }
    delete _owned[target_];
  }

  /**
   * @dev Internal function to retrieve all ERC-721 tokens from the stash for the target address.
   * 
   * Emits:
   * - {IERC721.Transfer} event for ERC-721 tokens being transferred from the stash.
   * 
   * @param target_ The address to retrieve ERC-721 tokens for.
   */
  function _retrieveAllFromStash(address target_) private {
    uint256 expectedERC721Balance = _balances[target_] / _UNIT;
    uint256 actualERC721Balance = 0;
    uint256[] memory ownedTarget = _owned[target_];
    for (uint256 i = 0; i < ownedTarget.length; ) {
      uint256 data = ownedTarget[i];
      assembly {
        actualERC721Balance := add(actualERC721Balance, shr(160, data))
        i := add(i, 1) // Avoiding an unchecked block after this one
      }
    }

    unchecked {
      expectedERC721Balance -= actualERC721Balance;
      for (uint256 i = 0; i < expectedERC721Balance; ++i) {
        // Transfer ERC721 balance in from pool
        _retrieveFromStash(target_);
      }
    }
  }

  /**
   * @dev See {IERC404-owned}. 
   */
  function owned(address owner_) public view virtual returns (uint256[] memory ownedCreatureIds) {
    if (owner_ == _STASH_ADDRESS) return tokensInStash();
    uint256 size = 0;
    uint256 data;
    uint256[] memory ownedOwner = _owned[owner_];
    for (uint256 i = 0; i < ownedOwner.length; ) {
      data = ownedOwner[i];
      assembly {
        size := add(size, shr(160, data))
        i := add(i, 1)
      }
    }
    ownedCreatureIds = new uint256[](size);

    unchecked {
      uint256 ix = 0;
      uint256 batchInitialId_;
      uint256 batchQuantity_;
      for (uint256 i = 0; i < ownedOwner.length; ++i) {
        data = ownedOwner[i];
        assembly {
          batchInitialId_ := and(data, _BITMASK_LOWER160BITS)
          batchQuantity_ := shr(160, data)
        }

        for (uint256 j = 0; j < batchQuantity_; ++j) {
          ownedCreatureIds[ix] = batchInitialId_ + j;
          ++ix;
        }
      }
    }
  }

  /**
   * @dev Internal function to burn (destroy) an ERC-721 token.
   * 
   * Emits:
   * - {IERC721.Transfer} event from `from` to `address(0)` (burning the token).
   * - {IERC20.Transfer} event from `from` to `address(0)` with `_UNIT` value (The ERC-20 side of the token).
   * 
   * @param tokenId_ ID of the ERC-721 token to be burned.
   */
  function _burn(uint256 tokenId_) internal virtual {
    if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_);
    (address from, uint256 index, uint256 tokenIdBatchHead) = _getOwnerOwnedIndexAndBatchHeadId(tokenId_);
    // _beforeTokenTransfers(from, to, tokenId, 1);

    delete _tokenApprovals[tokenId_]; // On transfer, any previous approval is reset.

    uint256 batchQuantity_;
    uint256 data = _owned[from][index];
    assembly {
      batchQuantity_ := shr(160, data)
    }

    _removeTokenFrom(from, index, tokenId_, tokenIdBatchHead, batchQuantity_);
    delete _ownedData[tokenId_];
    _batchHead.set(tokenId_);
    _burnedTokens.set(tokenId_);

    unchecked {
      // Cannot overflow, as that would require more tokens to be burned/transferred
      // out than the owner initially received through minting and transferring in.
      _balances[from] -= _UNIT;
      ++_burnedCount;
    }

    data = _UNIT;
    assembly {
      let fromMasked := and(from, _BITMASK_LOWER160BITS)
      // emit IERC20.Transfer(from_, to_, _UNIT);
      mstore(0x00, data)
      log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, fromMasked, 0x00)

      // emit IERC721.Transfer(from, address(0), tokenId_);
      log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, fromMasked, 0x00, tokenId_)
    }
    // _afterTokenTransfers(from, address(0), tokenId, 1);
  }

  /**
   * @dev See {IERC404-stashAddress}. 
   */
  function stashAddress() public view returns (address) {
    return _STASH_ADDRESS;
  }

  /**
   * @dev See {IERC404-stashLength}. 
   */
  function stashLength() public view returns (uint256) {
    return _stashQueue.length();
  }

  /**
   * @dev See {IERC404-tokensInStash}. 
   */
  function tokensInStash() public view returns (uint256[] memory) {
    return _stashQueue.retriveQueueItems();
  }

  /**
   * @dev See {IERC404-exchangeWithStash}. 
   */
  function exchangeWithStash(uint256 tokenId_, uint128 index_) public {
    uint256 stashTokenId = _stashQueue.at(index_);
    if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_);
    if (!_isApprovedOrOwner(msg.sender, tokenId_)) revert ERC721InsufficientApproval(msg.sender, tokenId_);
    (address owner, uint256 index, uint256 tokenIdBatchHead) = _getOwnerOwnedIndexAndBatchHeadId(tokenId_);
    // _beforeTokenTransfers(msg.sender, _STASH_ADDRESS, tokenId_, 1);
    // _beforeTokenTransfers(_STASH_ADDRESS, msg.sender, stashTokenId, 1);

    delete _tokenApprovals[tokenId_]; // On transfer, any previous approval is reset.

    uint256 batchQuantity_;
    uint256 data = _owned[owner][index];
    assembly {
      batchQuantity_ := shr(160, data)
    }
    _removeTokenFrom(owner, index, tokenId_, tokenIdBatchHead, batchQuantity_);
    delete _ownedData[tokenId_];
    _batchHead.set(tokenId_);
    _stashQueue.setIndexValue(index_, tokenId_); // Sets the token to exchange into the stash

    // Now, sets the Stash token to the tokenId owner
    assembly {
      data := add(and(stashTokenId, _BITMASK_LOWER160BITS), and(shl(160, 1), _BITMASK_UPPER96BITS))
    }
    _owned[owner].push(data);
    unchecked {
      uint256 ownedIndex = _owned[owner].length - 1;
      assembly {
        data := add(and(owner, _BITMASK_LOWER160BITS), and(shl(160, ownedIndex), _BITMASK_UPPER96BITS))
      }
    }
    _ownedData[stashTokenId] = data;

    address stashMasked = _STASH_ADDRESS;
    assembly {
      stashMasked := and(stashMasked, _BITMASK_LOWER160BITS)
      let ownerMasked := and(owner, _BITMASK_LOWER160BITS)

      // emit IERC721.Transfer(_STASH_ADDRESS, owner, stashTokenId);
      log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, stashMasked, ownerMasked, stashTokenId)
      // emit IERC721.Transfer(owner, _STASH_ADDRESS, tokenId_);
      log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, ownerMasked, stashMasked, tokenId_)
    }
    // _afterTokenTransfers(msg.sender, _STASH_ADDRESS, tokenId_, 1);
    // _afterTokenTransfers(_STASH_ADDRESS, msg.sender, stashTokenId, 1);
  }
}
合同源代码
文件 17 的 34:IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)

pragma solidity ^0.8.20;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

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

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

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

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

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

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

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}
合同源代码
文件 18 的 34:IBECDnaStrategy.sol
// contracts/strategies/IBECDnaStrategy.sol
// SPDX-License-Identifier: MIT

/**

    /3333333     /33333333     /333333    
   | 33__  33   | 33_____/    /33__  33   
   | 33  \ 33   | 33         | 33  \__/   
   | 3333333    | 33333      | 33         
   | 33__  33   | 33__/      | 33         
   | 33  \ 33   | 33         | 33    33   
   | 3333333/   | 33333333   |  333333/   
   |_______/    |________/    \______/    

 # https://blackeyedcreatures.com

 */

pragma solidity ^0.8.25;

/**
 * @title Black Eyed Creatures DNA Strategy
 * @notice The strategies are the contracts that mints and generates the metada for the BECs. 
 *         This interface helps with the information the genesis engine needs for each creature type.
 * @dev The genesis engine (through different strategies) creates DNA based in different logis, 
 *      but always creating DNA that are compliant with the following order (8b each):
 * 00: body_family
 * 01: body_variation
 * 02: head_family
 * 03: head_variation
 * 04: ears_family
 * 05: ears_variation
 * 06: face_family
 * 07: face_variation
 * 08: hair_family
 * 09: hair_variation
 * 10: eyes_family
 * 11: eyes_variation
 * 12: bg_color_family
 * 13: bg_color_variation
 * 14: skin_color_family
 * 15: skin_color_variation
 * 16: secondary_color_family
 * 17: secondary_color_variation
 * 18-30: unused
 * 31: type: normal|golden|ghost|others
 *
 * @author https://42i.co
 */
interface IBECDnaStrategy {
  /**
   * @notice Retrieves the DNA of a creature based on its id.
   * @param _creatureId The id of the creature.
   * @return uint256 The DNA of the specified creature.
   */
  function getDna(uint256 _creatureId) external view returns (uint256);

  /**
   * @notice Gets the metadata tokenURI for this creature.
   * @param _creatureId The id of the creature.
   * @return string memory The token uri.
   */
  function tokenURI(uint256 _creatureId) external view returns (string memory);

  /**
   * @notice Identifies the strategy ID.
   * @return uint256 The ID of the strategy.
   */
  function getStrategyId() external view returns (uint256);

  /**
   * @notice Identifies the distribution ID associated with this strategy.
   * @return uint256 The distribution ID.
   */
  function getDistributionId() external view returns (uint256);
}
合同源代码
文件 19 的 34:IBECErrors.sol
// contracts/IBECErrors.sol
// SPDX-License-Identifier: MIT

/**

    /3333333     /33333333     /333333    
   | 33__  33   | 33_____/    /33__  33   
   | 33  \ 33   | 33         | 33  \__/   
   | 3333333    | 33333      | 33         
   | 33__  33   | 33__/      | 33         
   | 33  \ 33   | 33         | 33    33   
   | 3333333/   | 33333333   |  333333/   
   |_______/    |________/    \______/    

 # https://blackeyedcreatures.com

 */
pragma solidity ^0.8.25;

/**
 * @title IBECErrors
 * @dev Interface for Black Eyed Creatures (BEC) custom errors.
 * @author https://42i.co
 */
interface IBECErrors {

    /**
     * @dev Indicates that a minting operation attempted to mint zero creatures.
     */
    error BECZeroQuantityMinting();

    /**
     * @dev Indicates that a minting operation has exceeded the cap limit for creatures.
     */
    error BECCapLimitReached();

    /**
     * @dev Indicates that invalid ambassadors were provided.
     * @param alpha ID of the first ambassador.
     * @param beta ID of the second ambassador.
     * @param gamma ID of the third ambassador.
     */
    error BECInvalidAmbassadors(uint256 alpha, uint256 beta, uint256 gamma);

    /**
     * @dev Indicates that an incorrect number of ambassadors was provided.
     * @param length The number of ambassadors provided.
     */
    error BECInvalidAmbassadorsLength(uint256 length);

    /**
     * @dev Indicates that a creature is already set as a variation ambassador.
     * @param creatureId The ID of the creature.
     */
    error BECAlreadyVariationAmbassador(uint256 creatureId);

    /**
     * @dev Indicates that a creature is already set as a family ambassador.
     * @param creatureId The ID of the creature.
     */
    error BECAlreadyFamilyAmbassador(uint256 creatureId);

    /**
     * @dev Indicates that a creature is not a variation ambassador when required.
     * @param creatureId The ID of the creature.
     */
    error BECNotVariationAmbassador(uint256 creatureId);

    /**
     * @dev Indicates that an invalid phenotype was provided.
     * @param phenotype The invalid phenotype identifier.
     */
    error BECInvalidPhenotype(uint256 phenotype);

    /**
     * @dev Indicates that an invalid family was provided for a creature.
     * @param creatureId The ID of the creature.
     */
    error BECInvalidFamily(uint256 creatureId);

    /**
     * @dev Indicates that an invalid variation was provided for a creature.
     * @param creatureId The ID of the creature.
     */
    error BECInvalidVariation(uint256 creatureId);

    /**
     * @dev Indicates that an invalid name was provided, either empty or too long.
     * @param name The invalid name submitted.
     */
    error BECInvalidName(string name);

    /**
     * @dev Indicates that a duplicated name was provided.
     * @param name The duplicate name submitted.
     */
    error BECDuplicatedName(string name);

    /**
     * @dev Indicates that a variation name has already been set for a given phenotype, family, and variation.
     * @param phenotype The phenotype identifier.
     * @param family The family identifier.
     * @param variation The variation identifier.
     */
    error BECVariationNameAlreadySet(uint256 phenotype, uint256 family, uint256 variation);

    /**
     * @dev Indicates that a family name has already been set for a given phenotype and family.
     * @param phenotype The phenotype identifier.
     * @param family The family identifier.
     */
    error BECFamilyNameAlreadySet(uint256 phenotype, uint256 family);

    /**
     * @dev Indicates that not all variations have been set for a given phenotype and family.
     * @param phenotype The phenotype identifier.
     * @param family The family identifier.
     * @param variation The variation identifier that is missing.
     */
    error BECNotAllVariationsSet(uint256 phenotype, uint256 family, uint256 variation);

    /**
     * @dev Indicates that not all required variations were present.
     */
    error BECNotAllVariationsPresent();

    /**
     * @dev Indicates that a hunt has already finished.
     */
    error BECHuntFinished();

    /**
     * @dev Indicates that the ritual price was not fully paid.
     * @param price The expected price.
     * @param paid The amount that was actually paid.
     */
    error BECRitualPriceNotPaid(uint256 price, uint256 paid);

    /**
     * @dev Indicates that the maximum number of hunts allowed was exceeded.
     * @param allowed The allowed number of hunts.
     * @param required The required number of hunts attempted.
     */
    error BECMaxHuntsAllowed(uint256 allowed, uint256 required);

    /**
     * @dev Indicates that the maximum number of reproductions allowed was exceeded.
     * @param allowed The allowed number of reproductions.
     * @param required The required number of reproductions attempted.
     */
    error BECMaxReproductionsAllowed(uint256 allowed, uint256 required);

    /**
     * @dev Indicates that the maximum number of reproductions for a specific creature was exceeded.
     * @param creatureId The ID of the creature.
     * @param allowed The allowed number of reproductions for this creature.
     * @param required The required number of reproductions attempted.
     */
    error BECMaxCreatureReproductionsAllowed(uint256 creatureId, uint256 allowed, uint256 required);

    /**
     * @dev Indicates that the creature is not of type 0, which is required for the operation.
     * @param creatureId The ID of the creature.
     */
    error BECNotType0Creature(uint256 creatureId);

    /**
     * @dev Indicates that the creature is fruitless, meaning it cannot reproduce.
     * @param creatureId The ID of the creature.
     */
    error BECFruitlessCreature(uint256 creatureId);

    /**
     * @dev Indicates that a parent creature was attempted to be used as payment, which is not allowed.
     * @param creatureId The ID of the creature.
     */
    error BECParentCreatureAsPayment(uint256 creatureId);

    /**
     * @dev Indicates that an invalid owner was provided for a token.
     * @param operator The address of the operator trying to act on the token.
     * @param tokenId The token ID being acted upon.
     */
    error BECInvalidOwner(address operator, uint256 tokenId);

    /**
     * @dev Indicates that there are insufficient funds for the requested operation.
     * @param requested The amount of funds requested.
     * @param available The amount of funds available.
     */
    error BECInsufficientFunds(uint256 requested, uint256 available);

    /**
     * @dev Indicates that an invalid owner was provided for a Black Sphere.
     * @param owner The incorrect owner address.
     * @param blacksphere The Black Sphere ID involved.
     */
    error BlackSphereInvalidOwner(address owner, uint256 blacksphere);

    /**
     * @dev Indicates that the function or feature called is not currently enabled.
     */
    error BECNotEnabled();

    /**
     * @dev Indicates that the genesis store for a creature has already been set.
     * @param creatureId The ID of the creature.
     */
    error BECGenesisStoreAlreadySet(uint256 creatureId);

    /**
     * @dev Indicates that the distribution for a creature has already been set.
     * @param distribution The distribution ID.
     */
    error BECDistributionAlreadySet(uint256 distribution);

    /**
     * @dev Indicates that the wrong distribution ID was provided.
     * @param distributionId The incorrect distribution ID provided.
     */
    error BECWrongDistributionId(uint256 distributionId);

    /**
     * @dev Indicates that the domain for a creature has already been set.
     * @param domain The domain ID.
     */
    error BECDomainAlreadySet(uint256 domain);

    /**
     * @dev Indicates that an empty array was provided for golden data.
     */
    error BECEmptyGoldenDataArray();

    /**
     * @dev Indicates that a non-empty golden deltas array was provided when expected to be empty.
     */
    error BECNotEmptyGoldenDeltasArray();

    /**
     * @dev Indicates that more creatures were provided than there are phenotypes available.
     */
    error BECMoreCreaturesThanPhenotypes();

    /**
     * @dev Indicates that an awakening operation has already been performed.
     */
    error BECAlreadyAwaken();

    /**
     * @dev Indicates that IDs were not provided in order.
     */
    error BECIdsNotInOrder();

    /**
     * @dev Indicates that an invalid address was provided.
     * @param target The target address.
     */
    error BECInvalidAddress(address target);

    /**
     * @dev Indicates that an invalid protocol bit was used.
     */
    error BECInvalidProtocolBit();

    /**
     * @dev Indicates that an index was out of bounds.
     */
    error BECIndexOutOfBounds();
}
合同源代码
文件 20 的 34:IBECMetaExtension.sol
// contracts/meta-extensions/IBECMetaExtension.sol
// SPDX-License-Identifier: MIT

/**

    /3333333     /33333333     /333333    
   | 33__  33   | 33_____/    /33__  33   
   | 33  \ 33   | 33         | 33  \__/   
   | 3333333    | 33333      | 33         
   | 33__  33   | 33__/      | 33         
   | 33  \ 33   | 33         | 33    33   
   | 3333333/   | 33333333   |  333333/   
   |_______/    |________/    \______/    

 # https://blackeyedcreatures.com

 */

pragma solidity ^0.8.25;

/**
 * @title Black Eyed Creatures Meta Extension Interface
 * @dev Defines the interface for meta extensions within the Black Eyed Creatures ecosystem. 
 *      Meta extensions are modular contracts that provide additional token metadata for creatures, enhancing their attributes, 
 *      appearance, or interactions within the ecosystem.
 * @notice Implementations of this interface should ensure that extensions are applied in a manner that is consistent with 
 *         the ecosystem's rules and enhances the user experience.
 * @author https://42i.co
 */
interface IBECMetaExtension {

  /**
   * @notice Applies the meta extension to a creature and returns the additional metadata.
   * @dev When implemented, this function should handle the logic for appending the creature's metadata based on the extension's purpose. 
   * @param _creatureId The unique identifier of the creature to which the extension is applied.
   * @return string A string representing the modified or additional metadata for the creature.
   */
  function applyExtension(uint256 _creatureId) external view returns (string memory);
}
合同源代码
文件 21 的 34:IERC165.sol
// 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);
}
合同源代码
文件 22 的 34:IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
合同源代码
文件 23 的 34:IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
合同源代码
文件 24 的 34:IERC404B.sol
// contracts/erc404/IERC404B.sol
// SPDX-License-Identifier: MIT

/**

    /3333333     /33333333     /333333    
   | 33__  33   | 33_____/    /33__  33   
   | 33  \ 33   | 33         | 33  \__/   
   | 3333333    | 33333      | 33         
   | 33__  33   | 33__/      | 33         
   | 33  \ 33   | 33         | 33    33   
   | 3333333/   | 33333333   |  333333/   
   |_______/    |________/    \______/    

 # https://blackeyedcreatures.com

 */
pragma solidity ^0.8.25;

import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";

/**
 * @title IERC404B Interface
 * @dev Interface for a hybrid token contract combining ERC20 and ERC721 functionalities with a unique "stash" feature.
 * The stash is a holding area for tokens that are currently unowned but not burned, allowing for controlled management and re-distribution.
 * Supports ERC165 for interface detection and ERC20Permit for token allowance via signatures.
 */
interface IERC404B is IERC165, IERC20Permit {
 
  /// IERC20 + ERC721 Metadata Methods ///

  /**
   * @dev Returns the name of the token.
   */
  function name() external view returns (string memory);

  /**
   * @dev Returns the symbol of the token.
   */
  function symbol() external view returns (string memory);

  /**
   * @dev Returns the number of decimals used to get its user representation.
   * For example, if `decimals` equals `2`, a balance of `505` tokens should
   * be displayed to a user as `5.05` (`505 / 10 ** 2`).
   *
   * Tokens usually opt for a value of 18, imitating the relationship between
   * Ether and Wei. This is the default value returned by this function, unless
   * it's overridden.
   *
   * NOTE: This information is only used for _display_ purposes: it in
   * no way affects any of the arithmetic of the contract, including
   * {IERC20-balanceOf} and {IERC20-transfer}.
   */
  function decimals() external view returns (uint8);

  /**
   * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
   */
  function tokenURI(uint256 tokenId) external view returns (string memory);


  /// ERC721 Methods ///

  /**
   * @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 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 caller.
   *
   * 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);

  /// ERC20 Methods ///

  /**
   * @dev Returns the amount of ERC20 tokens in existence.
   */
  function totalSupply() external view returns (uint256);

  /**
   * @dev Moves `amountOrId` tokens from the caller's account to `to`.
   *
   * Returns a boolean value indicating whether the operation succeeded.
   *
   * Emits {Transfer} events.
   */
  function transfer(address to, uint256 amountOrId) external returns (bool);

  /**
   * @dev Returns the remaining number of tokens that `spender` will be
   * allowed to spend on behalf of `owner` through {transferFrom}. This is
   * zero by default.
   *
   * This value changes when {approve} or {transferFrom} are called.
   */
  function allowance(address owner, address spender) external view returns (uint256);

  /// ERC404 Combined (Methods with similar interfaces and behavior in ERC20 & ERC721) ///

  /**
   * @dev Returns the amount of tokens owned by `account`.
   */
  function balanceOf(address account) external view returns (uint256 balance);

  /**
   * @dev Moves `amountOrId` tokens from `from` to `to` using the
   * allowance mechanism. `amountOrId` is then deducted from the caller's
   * allowance.
   *
   * Returns a boolean value indicating whether the operation succeeded.
   *
   * WARNING: In case of Id, 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.
   * - `amountOrId` amount should be less or equal than balance OR tokenId 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 {Transfer} events.
   */
  function transferFrom(address from, address to, uint256 amountOrId) external returns (bool);

  /**
   * @dev Sets `amountOrId` as the allowance of `spender` over the caller's tokens.
   *
   * Returns a boolean value indicating whether the operation succeeded.
   *
   * IMPORTANT: Beware that changing an allowance with this method brings the risk
   * that someone may use both the old and the new allowance by unfortunate
   * transaction ordering. One possible solution to mitigate this race
   * condition is to first reduce the spender's allowance to 0 and set the
   * desired value afterwards:
   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
   *
   * Emits an {Approval} event.
   */
  function approve(address spender, uint256 amountOrId) external returns (bool);


  /// ERC404 Specific ///

 /**
   * @notice Retrieves the equivalence between 1 ERC721 token and ERC20 needed for that token.
   * @dev This function returns the unit value used in conversions between ERC721 and ERC20 tokens.
   * @return The unit value representing the equivalence between 1 ERC721 token and ERC20.
   */
  function unit() external view returns (uint256);

    /**
   * @notice Checks if the specified token exists.
   *
   * A token is considered to exist if it has been minted using {_mint} and is not in the set of burned tokens.
   *
   * @param tokenId_ The ID of the token to check.
   * @return True if the token exists, false otherwise.
   */
  function exists(uint256 tokenId_) external view returns (bool);

  /**
   * @dev Checks if the specified address is exempt from ERC-721 transfers.
   * This function retrieves the exemption status for ERC-721 transfers for the given address.
   * 
   * @param target_ The address to check for ERC-721 transfer exemption.
   * @return isExempt True if the address is exempt from ERC-721 transfers, false otherwise.
   */
  function isERC721TransferExempt(address target_) external view returns (bool isExempt);

  /**
   * @dev Sets the exemption status for ERC-721 transfers for the caller.
   * 
   * Emits:
   * - {Transfer} event for each target_ ERC721 token from/to the stash.
   * 
   * @param state_ The new exemption state to set (true for exempt, false for non-exempt).
   */
  function setERC721TransferExempt(bool state_) external;

  /**
   * @dev Retrieves the IDs of ERC-721 tokens owned by a specific address.
   * 
   * @param owner_ The address for which ERC-721 token IDs are being retrieved.
   * @return ownedCreatureIds An array of uint256 representing the ERC-721 token IDs owned by the specified address.
   */
  function owned(address owner_) external view returns (uint256[] memory);

  /**
   * @dev External function to get the current stash address.
   * 
   * @return address Current stash address.
   */
  function stashAddress() external view returns (address);

  /**
   * @dev External function to get the current length of the stash queue.
   * 
   * @return uint256 Current length of the stash queue.
   */
  function stashLength() external view returns (uint256);

  /**
   * @dev External function to retrieve all tokens currently in the stash queue.
   * 
   * @return uint256[] An array containing all tokens currently in the stash queue.
   */
  function tokensInStash() external view returns (uint256[] memory);

  /**
   * @dev Public function to exchange an ERC-721 token with a token in the stash.
   * 
   * Requirements:
   * - The caller must be the owner or have approval to transfer the tokenId_.
   * - The stashTokenId_ must belong to the stash.
   * 
   * Emits:
   * - {Transfer} event for the token exchanged from the stash to the caller.
   * - {Transfer} event for the token exchanged from the caller to the stash.
   * 
   * @param tokenId_ The ID of the ERC-721 token to exchange.
   * @param index_ The index of the token at the stash to exchange with.
   */
  function exchangeWithStash(uint256 tokenId_, uint128 index_) external;
}
合同源代码
文件 25 的 34:IERC404BErrors.sol
// contracts/erc404/IERC404BErrors.sol
// SPDX-License-Identifier: MIT

/**

    /3333333     /33333333     /333333    
   | 33__  33   | 33_____/    /33__  33   
   | 33  \ 33   | 33         | 33  \__/   
   | 3333333    | 33333      | 33         
   | 33__  33   | 33__/      | 33         
   | 33  \ 33   | 33         | 33    33   
   | 3333333/   | 33333333   |  333333/   
   |_______/    |________/    \______/    

 # https://blackeyedcreatures.com

 */
pragma solidity ^0.8.25;

/**
 * @dev ERC404B3Errors interface defines custom error messages for the ERC404B3 contract.
 */
interface IERC404BErrors {

  /**
   * @dev Indicates that the specified token is not found in the stash.
   * @param stashTokenId The ID of the token in the stash.
   */
  error ERC404TokenNotInStash(uint256 stashTokenId);

  /**
   * @dev Indicates that the index value provided is not valid in the stash queue.
   * @param indexInQueue The index value in the queue.
   * @param stashTokenId The ID of the token in the stash.
   */
  error ERC404NotValidIndexValueInStash(uint128 indexInQueue, uint256 stashTokenId);

  /**
   * @dev Indicates that the transfer value is invalid.
   * @param value The invalid transfer value.
   */
  error ERC404InvalidTransferValue(uint256 value);

  /**
   * @dev Indicates that the target address is not eligible for ERC721 exemption.
   * @param target The address that is not eligible for exemption.
   */
  error ERC404InvalidERC721Exemption(address target);

  /**
   * @dev Indicates an overflow in the owned index.
   * @param index The index value causing the overflow.
   */
  error ERC404OwnedIndexOverflow(uint256 index);

  /**
   * @dev Indicates an invalid mint quantity for ERC721.
   */
  error ERC721InvalidMintQuantity();

  /**
   * @dev Indicates that the recipient address has not implemented ERC721Receiver.
   * @param to The recipient address.
   * @param tokenId The ID of the token being transferred.
   * @param quantity The quantity of tokens being transferred.
   * @param data Additional data for the transfer.
   */
  error ERC721ReceiverNotImplemented(address to, uint256 tokenId, uint256 quantity, bytes data);

  /**
   * @dev Indicates that the permit deadline has expired for EIP-2612 permit.
   * @param owner The owner of the tokens.
   * @param spender The spender of the tokens.
   * @param value The token value.
   * @param deadline The expired deadline.
   * @param v Signature parameter v.
   * @param r Signature parameter r.
   * @param s Signature parameter s.
   */
  error EIP2612PermitDeadlineExpired(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s);

  /**
   * @dev Indicates that the signer of the permit is invalid for EIP-2612 permit.
   * @param recoveredAddress The recovered signer address.
   * @param owner The owner of the tokens.
   * @param spender The spender of the tokens.
   * @param value The token value.
   * @param deadline The permit deadline.
   * @param v Signature parameter v.
   * @param r Signature parameter r.
   * @param s Signature parameter s.
   */
  error EIP2612InvalidSigner(address recoveredAddress, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s);
}
合同源代码
文件 26 的 34:IERC721.sol
// 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);
}
合同源代码
文件 27 的 34:IERC721Metadata.sol
// 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);
}
合同源代码
文件 28 的 34:IERC721Receiver.sol
// 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);
}
合同源代码
文件 29 的 34:Math.sol
// 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;
    }
}
合同源代码
文件 30 的 34:Ownable.sol
// 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);
    }
}
合同源代码
文件 31 的 34:Popcount.sol
// SPDX-License-Identifier: MIT
/**
   _____       ___     ___ __           ____  _ __      
  / ___/____  / (_)___/ (_) /___  __   / __ )(_) /______
  \__ \/ __ \/ / / __  / / __/ / / /  / __  / / __/ ___/
 ___/ / /_/ / / / /_/ / / /_/ /_/ /  / /_/ / / /_(__  ) 
/____/\____/_/_/\__,_/_/\__/\__, /  /_____/_/\__/____/  
                           /____/                        

- npm: https://www.npmjs.com/package/solidity-bits
- github: https://github.com/estarriolvetch/solidity-bits

 */

pragma solidity ^0.8.0;

library Popcount {
    uint256 private constant m1 = 0x5555555555555555555555555555555555555555555555555555555555555555;
    uint256 private constant m2 = 0x3333333333333333333333333333333333333333333333333333333333333333;
    uint256 private constant m4 = 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;
    uint256 private constant h01 = 0x0101010101010101010101010101010101010101010101010101010101010101;

    function popcount256A(uint256 x) internal pure returns (uint256 count) {
        unchecked{
            for (count=0; x!=0; count++)
                x &= x - 1;
        }
    }

    function popcount256B(uint256 x) internal pure returns (uint256) {
        if (x == type(uint256).max) {
            return 256;
        }
        unchecked {
            x -= (x >> 1) & m1;             //put count of each 2 bits into those 2 bits
            x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits 
            x = (x + (x >> 4)) & m4;        //put count of each 8 bits into those 8 bits 
            x = (x * h01) >> 248;  //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ... 
        }
        return x;
    }
}
合同源代码
文件 32 的 34:SignedMath.sol
// 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);
        }
    }
}
合同源代码
文件 33 的 34:Strings.sol
// 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));
    }
}
合同源代码
文件 34 的 34:draft-IERC6093.sol
// 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);
}
设置
{
  "compilationTarget": {
    "contracts/BECCore.sol": "BECCore"
  },
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "details": {
      "constantOptimizer": true,
      "cse": true,
      "deduplicate": true,
      "inliner": true,
      "jumpdestRemover": true,
      "orderLiterals": true,
      "peephole": true,
      "simpleCounterForLoopUncheckedIncrement": true,
      "yul": true,
      "yulDetails": {
        "optimizerSteps": "u:fDnTOcmu",
        "stackAllocation": true
      }
    },
    "runs": 200
  },
  "remappings": [],
  "viaIR": true
}
ABI
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"BECAlreadyAwaken","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECAlreadyFamilyAmbassador","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECAlreadyVariationAmbassador","type":"error"},{"inputs":[],"name":"BECCapLimitReached","type":"error"},{"inputs":[{"internalType":"uint256","name":"distribution","type":"uint256"}],"name":"BECDistributionAlreadySet","type":"error"},{"inputs":[{"internalType":"uint256","name":"domain","type":"uint256"}],"name":"BECDomainAlreadySet","type":"error"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"BECDuplicatedName","type":"error"},{"inputs":[],"name":"BECEmptyGoldenDataArray","type":"error"},{"inputs":[{"internalType":"uint256","name":"phenotype","type":"uint256"},{"internalType":"uint256","name":"family","type":"uint256"}],"name":"BECFamilyNameAlreadySet","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECFruitlessCreature","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECGenesisStoreAlreadySet","type":"error"},{"inputs":[],"name":"BECHuntFinished","type":"error"},{"inputs":[],"name":"BECIdsNotInOrder","type":"error"},{"inputs":[],"name":"BECIndexOutOfBounds","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"name":"BECInsufficientFunds","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"BECInvalidAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"alpha","type":"uint256"},{"internalType":"uint256","name":"beta","type":"uint256"},{"internalType":"uint256","name":"gamma","type":"uint256"}],"name":"BECInvalidAmbassadors","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"BECInvalidAmbassadorsLength","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECInvalidFamily","type":"error"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"BECInvalidName","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"BECInvalidOwner","type":"error"},{"inputs":[{"internalType":"uint256","name":"phenotype","type":"uint256"}],"name":"BECInvalidPhenotype","type":"error"},{"inputs":[],"name":"BECInvalidProtocolBit","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECInvalidVariation","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"},{"internalType":"uint256","name":"allowed","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"BECMaxCreatureReproductionsAllowed","type":"error"},{"inputs":[{"internalType":"uint256","name":"allowed","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"BECMaxHuntsAllowed","type":"error"},{"inputs":[{"internalType":"uint256","name":"allowed","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"BECMaxReproductionsAllowed","type":"error"},{"inputs":[],"name":"BECMoreCreaturesThanPhenotypes","type":"error"},{"inputs":[],"name":"BECNotAllVariationsPresent","type":"error"},{"inputs":[{"internalType":"uint256","name":"phenotype","type":"uint256"},{"internalType":"uint256","name":"family","type":"uint256"},{"internalType":"uint256","name":"variation","type":"uint256"}],"name":"BECNotAllVariationsSet","type":"error"},{"inputs":[],"name":"BECNotEmptyGoldenDeltasArray","type":"error"},{"inputs":[],"name":"BECNotEnabled","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECNotType0Creature","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECNotVariationAmbassador","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECParentCreatureAsPayment","type":"error"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"paid","type":"uint256"}],"name":"BECRitualPriceNotPaid","type":"error"},{"inputs":[{"internalType":"uint256","name":"phenotype","type":"uint256"},{"internalType":"uint256","name":"family","type":"uint256"},{"internalType":"uint256","name":"variation","type":"uint256"}],"name":"BECVariationNameAlreadySet","type":"error"},{"inputs":[{"internalType":"uint256","name":"distributionId","type":"uint256"}],"name":"BECWrongDistributionId","type":"error"},{"inputs":[],"name":"BECZeroQuantityMinting","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"blacksphere","type":"uint256"}],"name":"BlackSphereInvalidOwner","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[{"internalType":"address","name":"recoveredAddress","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"EIP2612InvalidSigner","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"EIP2612PermitDeadlineExpired","type":"error"},{"inputs":[],"name":"EIP712BECSigningKeyNotSet","type":"error"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"EIP712InvalidSignature","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"ERC404InvalidERC721Exemption","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"ERC404InvalidTransferValue","type":"error"},{"inputs":[{"internalType":"uint128","name":"indexInQueue","type":"uint128"},{"internalType":"uint256","name":"stashTokenId","type":"uint256"}],"name":"ERC404NotValidIndexValueInStash","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"ERC404OwnedIndexOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"stashTokenId","type":"uint256"}],"name":"ERC404TokenNotInStash","type":"error"},{"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":[],"name":"ERC721InvalidMintQuantity","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":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"ERC721ReceiverNotImplemented","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":[],"name":"QueueEmpty","type":"error"},{"inputs":[],"name":"QueueFull","type":"error"},{"inputs":[],"name":"QueueOutOfBounds","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":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Received","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"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GENETICIST","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IPFS_URI_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"_erc20Approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"_erc721Approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"_transferFromERC20","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender_","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"valueOrId_","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_creatureId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"burned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint128","name":"index_","type":"uint128"}],"name":"exchangeWithStash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"bool","name":"_state","type":"bool"}],"name":"forceERC721TransferExempt","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":"uint256","name":"_creatureId","type":"uint256"}],"name":"getImageURI","outputs":[{"internalType":"string","name":"uri","type":"string"}],"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":"uint256","name":"_creatureId","type":"uint256"}],"name":"getSeed","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_creatureIds","type":"uint256[]"}],"name":"getSeeds","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSiteBaseURI","outputs":[{"internalType":"string","name":"uri","type":"string"}],"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":"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":"uint256","name":"tokenId","type":"uint256"}],"name":"ipfsUris","outputs":[{"internalType":"string","name":"ipfsUri","type":"string"}],"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":[{"internalType":"address","name":"target_","type":"address"}],"name":"isERC721TransferExempt","outputs":[{"internalType":"bool","name":"isExempt","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_creatureOwner","type":"address"},{"internalType":"bytes32","name":"_seed","type":"bytes32"},{"internalType":"uint256","name":"_quantity","type":"uint256"}],"name":"mintWithSeed","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"owned","outputs":[{"internalType":"uint256[]","name":"ownedCreatureIds","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":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","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":"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":"_signingKey","type":"address"}],"name":"setAllowlistSigningAddress","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":"string","name":"_uri","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state_","type":"bool"}],"name":"setERC721TransferExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_genesisEngineContractAddress","type":"address"}],"name":"setGenesisEngineContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_creatureId","type":"uint256"},{"internalType":"string","name":"_uri","type":"string"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"setIPFSTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_uri","type":"string"}],"name":"setSiteBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stashAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stashLength","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":"_creatureId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokensInStash","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"valueOrId_","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"valueOrId_","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address payable","name":"_address","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address payable","name":"_address","type":"address"}],"name":"withdrawERC20Token","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"address","name":"_address","type":"address"}],"name":"withdrawERC721Token","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]