creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts/access/AccessControl.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"./IAccessControl.sol\";\nimport {Context} from \"../utils/Context.sol\";\nimport {ERC165} from \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n *     require(hasRole(MY_ROLE, msg.sender));\n *     ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n    struct RoleData {\n        mapping(address account => bool) hasRole;\n        bytes32 adminRole;\n    }\n\n    mapping(bytes32 role => RoleData) private _roles;\n\n    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n    /**\n     * @dev Modifier that checks that an account has a specific role. Reverts\n     * with an {AccessControlUnauthorizedAccount} error including the required role.\n     */\n    modifier onlyRole(bytes32 role) {\n        _checkRole(role);\n        _;\n    }\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n        return _roles[role].hasRole[account];\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n     */\n    function _checkRole(bytes32 role) internal view virtual {\n        _checkRole(role, _msgSender());\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n     * is missing `role`.\n     */\n    function _checkRole(bytes32 role, address account) internal view virtual {\n        if (!hasRole(role, account)) {\n            revert AccessControlUnauthorizedAccount(account, role);\n        }\n    }\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n        return _roles[role].adminRole;\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been revoked `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `callerConfirmation`.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n        if (callerConfirmation != _msgSender()) {\n            revert AccessControlBadConfirmation();\n        }\n\n        _revokeRole(role, callerConfirmation);\n    }\n\n    /**\n     * @dev Sets `adminRole` as ``role``'s admin role.\n     *\n     * Emits a {RoleAdminChanged} event.\n     */\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n        bytes32 previousAdminRole = getRoleAdmin(role);\n        _roles[role].adminRole = adminRole;\n        emit RoleAdminChanged(role, previousAdminRole, adminRole);\n    }\n\n    /**\n     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n        if (!hasRole(role, account)) {\n            _roles[role].hasRole[account] = true;\n            emit RoleGranted(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n        if (hasRole(role, account)) {\n            _roles[role].hasRole[account] = false;\n            emit RoleRevoked(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/access/IAccessControl.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n    /**\n     * @dev The `account` is missing a role.\n     */\n    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n    /**\n     * @dev The caller of a function is not the expected one.\n     *\n     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n     */\n    error AccessControlBadConfirmation();\n\n    /**\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n     *\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n     * {RoleAdminChanged} not being emitted signaling this.\n     */\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n    /**\n     * @dev Emitted when `account` is granted `role`.\n     *\n     * `sender` is the account that originated the contract call, an admin role\n     * bearer except when using {AccessControl-_setupRole}.\n     */\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Emitted when `account` is revoked `role`.\n     *\n     * `sender` is the account that originated the contract call:\n     *   - if using `revokeRole`, it is the admin role bearer\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n     */\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) external view returns (bool);\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `callerConfirmation`.\n     */\n    function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"
      },
      "@openzeppelin/contracts/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    /**\n     * @dev The caller account is not authorized to perform an operation.\n     */\n    error OwnableUnauthorizedAccount(address account);\n\n    /**\n     * @dev The owner is not a valid owner account. (eg. `address(0)`)\n     */\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n     */\n    constructor(address initialOwner) {\n        if (initialOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(initialOwner);\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        if (owner() != _msgSender()) {\n            revert OwnableUnauthorizedAccount(_msgSender());\n        }\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
      },
      "@openzeppelin/contracts/interfaces/draft-IERC6093.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)\npragma solidity ^0.8.20;\n\n/**\n * @dev Standard ERC20 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.\n */\ninterface IERC20Errors {\n    /**\n     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     * @param balance Current balance for the interacting account.\n     * @param needed Minimum amount required to perform a transfer.\n     */\n    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);\n\n    /**\n     * @dev Indicates a failure with the token `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     */\n    error ERC20InvalidSender(address sender);\n\n    /**\n     * @dev Indicates a failure with the token `receiver`. Used in transfers.\n     * @param receiver Address to which tokens are being transferred.\n     */\n    error ERC20InvalidReceiver(address receiver);\n\n    /**\n     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.\n     * @param spender Address that may be allowed to operate on tokens without being their owner.\n     * @param allowance Amount of tokens a `spender` is allowed to operate with.\n     * @param needed Minimum amount required to perform a transfer.\n     */\n    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);\n\n    /**\n     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n     * @param approver Address initiating an approval operation.\n     */\n    error ERC20InvalidApprover(address approver);\n\n    /**\n     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.\n     * @param spender Address that may be allowed to operate on tokens without being their owner.\n     */\n    error ERC20InvalidSpender(address spender);\n}\n\n/**\n * @dev Standard ERC721 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.\n */\ninterface IERC721Errors {\n    /**\n     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.\n     * Used in balance queries.\n     * @param owner Address of the current owner of a token.\n     */\n    error ERC721InvalidOwner(address owner);\n\n    /**\n     * @dev Indicates a `tokenId` whose `owner` is the zero address.\n     * @param tokenId Identifier number of a token.\n     */\n    error ERC721NonexistentToken(uint256 tokenId);\n\n    /**\n     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     * @param tokenId Identifier number of a token.\n     * @param owner Address of the current owner of a token.\n     */\n    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);\n\n    /**\n     * @dev Indicates a failure with the token `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     */\n    error ERC721InvalidSender(address sender);\n\n    /**\n     * @dev Indicates a failure with the token `receiver`. Used in transfers.\n     * @param receiver Address to which tokens are being transferred.\n     */\n    error ERC721InvalidReceiver(address receiver);\n\n    /**\n     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     * @param tokenId Identifier number of a token.\n     */\n    error ERC721InsufficientApproval(address operator, uint256 tokenId);\n\n    /**\n     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n     * @param approver Address initiating an approval operation.\n     */\n    error ERC721InvalidApprover(address approver);\n\n    /**\n     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     */\n    error ERC721InvalidOperator(address operator);\n}\n\n/**\n * @dev Standard ERC1155 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.\n */\ninterface IERC1155Errors {\n    /**\n     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     * @param balance Current balance for the interacting account.\n     * @param needed Minimum amount required to perform a transfer.\n     * @param tokenId Identifier number of a token.\n     */\n    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);\n\n    /**\n     * @dev Indicates a failure with the token `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     */\n    error ERC1155InvalidSender(address sender);\n\n    /**\n     * @dev Indicates a failure with the token `receiver`. Used in transfers.\n     * @param receiver Address to which tokens are being transferred.\n     */\n    error ERC1155InvalidReceiver(address receiver);\n\n    /**\n     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     * @param owner Address of the current owner of a token.\n     */\n    error ERC1155MissingApprovalForAll(address operator, address owner);\n\n    /**\n     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n     * @param approver Address initiating an approval operation.\n     */\n    error ERC1155InvalidApprover(address approver);\n\n    /**\n     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     */\n    error ERC1155InvalidOperator(address operator);\n\n    /**\n     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.\n     * Used in batch transfers.\n     * @param idsLength Length of the array of token identifiers\n     * @param valuesLength Length of the array of token amounts\n     */\n    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);\n}\n"
      },
      "@openzeppelin/contracts/interfaces/IERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"
      },
      "@openzeppelin/contracts/interfaces/IERC4626.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"../token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @dev Interface of the ERC4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n */\ninterface IERC4626 is IERC20, IERC20Metadata {\n    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n    event Withdraw(\n        address indexed sender,\n        address indexed receiver,\n        address indexed owner,\n        uint256 assets,\n        uint256 shares\n    );\n\n    /**\n     * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n     *\n     * - MUST be an ERC-20 token contract.\n     * - MUST NOT revert.\n     */\n    function asset() external view returns (address assetTokenAddress);\n\n    /**\n     * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n     *\n     * - SHOULD include any compounding that occurs from yield.\n     * - MUST be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT revert.\n     */\n    function totalAssets() external view returns (uint256 totalManagedAssets);\n\n    /**\n     * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n     * scenario where all the conditions are met.\n     *\n     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n     * - MUST NOT revert.\n     *\n     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n     * from.\n     */\n    function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n     * scenario where all the conditions are met.\n     *\n     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n     * - MUST NOT revert.\n     *\n     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n     * from.\n     */\n    function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n     * through a deposit call.\n     *\n     * - MUST return a limited value if receiver is subject to some deposit limit.\n     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n     * - MUST NOT revert.\n     */\n    function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n     * current on-chain conditions.\n     *\n     * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n     *   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n     *   in the same transaction.\n     * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n     *   deposit would be accepted, regardless if the user has enough tokens approved, etc.\n     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n     */\n    function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n     *\n     * - MUST emit the Deposit event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   deposit execution, and are accounted for during deposit.\n     * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n     *   approving enough underlying tokens to the Vault contract, etc).\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n     */\n    function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n    /**\n     * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n     * - MUST return a limited value if receiver is subject to some mint limit.\n     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n     * - MUST NOT revert.\n     */\n    function maxMint(address receiver) external view returns (uint256 maxShares);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n     * current on-chain conditions.\n     *\n     * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n     *   in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n     *   same transaction.\n     * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n     *   would be accepted, regardless if the user has enough tokens approved, etc.\n     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by minting.\n     */\n    function previewMint(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n     *\n     * - MUST emit the Deposit event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n     *   execution, and are accounted for during mint.\n     * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n     *   approving enough underlying tokens to the Vault contract, etc).\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n     */\n    function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n    /**\n     * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n     * Vault, through a withdraw call.\n     *\n     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n     * - MUST NOT revert.\n     */\n    function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n     * given current on-chain conditions.\n     *\n     * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n     *   call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n     *   called\n     *   in the same transaction.\n     * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n     *   the withdrawal would be accepted, regardless if the user has enough shares, etc.\n     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n     */\n    function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n     *\n     * - MUST emit the Withdraw event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   withdraw execution, and are accounted for during withdraw.\n     * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n     *   not having enough shares, etc).\n     *\n     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n     * Those methods should be performed separately.\n     */\n    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n    /**\n     * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n     * through a redeem call.\n     *\n     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n     * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n     * - MUST NOT revert.\n     */\n    function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n     * given current on-chain conditions.\n     *\n     * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n     *   in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n     *   same transaction.\n     * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n     *   redemption would be accepted, regardless if the user has enough shares, etc.\n     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n     */\n    function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n     *\n     * - MUST emit the Withdraw event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   redeem execution, and are accounted for during redeem.\n     * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n     *   not having enough shares, etc).\n     *\n     * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n     * Those methods should be performed separately.\n     */\n    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/ERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC20Metadata} from \"./extensions/IERC20Metadata.sol\";\nimport {Context} from \"../../utils/Context.sol\";\nimport {IERC20Errors} from \"../../interfaces/draft-IERC6093.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n */\nabstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {\n    mapping(address account => uint256) private _balances;\n\n    mapping(address account => mapping(address spender => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the default value returned by this function, unless\n     * it's overridden.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `value`.\n     */\n    function transfer(address to, uint256 value) public virtual returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, value);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 value) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, value);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `value`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `value`.\n     */\n    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, value);\n        _transfer(from, to, value);\n        return true;\n    }\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * NOTE: This function is not virtual, {_update} should be overridden instead.\n     */\n    function _transfer(address from, address to, uint256 value) internal {\n        if (from == address(0)) {\n            revert ERC20InvalidSender(address(0));\n        }\n        if (to == address(0)) {\n            revert ERC20InvalidReceiver(address(0));\n        }\n        _update(from, to, value);\n    }\n\n    /**\n     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`\n     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding\n     * this function.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _update(address from, address to, uint256 value) internal virtual {\n        if (from == address(0)) {\n            // Overflow check required: The rest of the code assumes that totalSupply never overflows\n            _totalSupply += value;\n        } else {\n            uint256 fromBalance = _balances[from];\n            if (fromBalance < value) {\n                revert ERC20InsufficientBalance(from, fromBalance, value);\n            }\n            unchecked {\n                // Overflow not possible: value <= fromBalance <= totalSupply.\n                _balances[from] = fromBalance - value;\n            }\n        }\n\n        if (to == address(0)) {\n            unchecked {\n                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.\n                _totalSupply -= value;\n            }\n        } else {\n            unchecked {\n                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.\n                _balances[to] += value;\n            }\n        }\n\n        emit Transfer(from, to, value);\n    }\n\n    /**\n     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).\n     * Relies on the `_update` mechanism\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * NOTE: This function is not virtual, {_update} should be overridden instead.\n     */\n    function _mint(address account, uint256 value) internal {\n        if (account == address(0)) {\n            revert ERC20InvalidReceiver(address(0));\n        }\n        _update(address(0), account, value);\n    }\n\n    /**\n     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.\n     * Relies on the `_update` mechanism.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * NOTE: This function is not virtual, {_update} should be overridden instead\n     */\n    function _burn(address account, uint256 value) internal {\n        if (account == address(0)) {\n            revert ERC20InvalidSender(address(0));\n        }\n        _update(account, address(0), value);\n    }\n\n    /**\n     * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     *\n     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.\n     */\n    function _approve(address owner, address spender, uint256 value) internal {\n        _approve(owner, spender, value, true);\n    }\n\n    /**\n     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.\n     *\n     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by\n     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any\n     * `Approval` event during `transferFrom` operations.\n     *\n     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to\n     * true using the following override:\n     * ```\n     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {\n     *     super._approve(owner, spender, value, true);\n     * }\n     * ```\n     *\n     * Requirements are the same as {_approve}.\n     */\n    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {\n        if (owner == address(0)) {\n            revert ERC20InvalidApprover(address(0));\n        }\n        if (spender == address(0)) {\n            revert ERC20InvalidSpender(address(0));\n        }\n        _allowances[owner][spender] = value;\n        if (emitEvent) {\n            emit Approval(owner, spender, value);\n        }\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `value`.\n     *\n     * Does not update the allowance value in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Does not emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            if (currentAllowance < value) {\n                revert ERC20InsufficientAllowance(spender, currentAllowance, value);\n            }\n            unchecked {\n                _approve(owner, spender, currentAllowance - value, false);\n            }\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC4626.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20, IERC20Metadata, ERC20} from \"../ERC20.sol\";\nimport {SafeERC20} from \"../utils/SafeERC20.sol\";\nimport {IERC4626} from \"../../../interfaces/IERC4626.sol\";\nimport {Math} from \"../../../utils/math/Math.sol\";\n\n/**\n * @dev Implementation of the ERC4626 \"Tokenized Vault Standard\" as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[EIP-4626].\n *\n * This extension allows the minting and burning of \"shares\" (represented using the ERC20 inheritance) in exchange for\n * underlying \"assets\" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends\n * the ERC20 standard. Any additional extensions included along it would affect the \"shares\" token represented by this\n * contract and not the \"assets\" token which is an independent contract.\n *\n * [CAUTION]\n * ====\n * In empty (or nearly empty) ERC-4626 vaults, deposits are at high risk of being stolen through frontrunning\n * with a \"donation\" to the vault that inflates the price of a share. This is variously known as a donation or inflation\n * attack and is essentially a problem of slippage. Vault deployers can protect against this attack by making an initial\n * deposit of a non-trivial amount of the asset, such that price manipulation becomes infeasible. Withdrawals may\n * similarly be affected by slippage. Users can protect against this attack as well as unexpected slippage in general by\n * verifying the amount received is as expected, using a wrapper that performs these checks such as\n * https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router].\n *\n * Since v4.9, this implementation uses virtual assets and shares to mitigate that risk. The `_decimalsOffset()`\n * corresponds to an offset in the decimal representation between the underlying asset's decimals and the vault\n * decimals. This offset also determines the rate of virtual shares to virtual assets in the vault, which itself\n * determines the initial exchange rate. While not fully preventing the attack, analysis shows that the default offset\n * (0) makes it non-profitable, as a result of the value being captured by the virtual shares (out of the attacker's\n * donation) matching the attacker's expected gains. With a larger offset, the attack becomes orders of magnitude more\n * expensive than it is profitable. More details about the underlying math can be found\n * xref:erc4626.adoc#inflation-attack[here].\n *\n * The drawback of this approach is that the virtual shares do capture (a very small) part of the value being accrued\n * to the vault. Also, if the vault experiences losses, the users try to exit the vault, the virtual shares and assets\n * will cause the first user to exit to experience reduced losses in detriment to the last users that will experience\n * bigger losses. Developers willing to revert back to the pre-v4.9 behavior just need to override the\n * `_convertToShares` and `_convertToAssets` functions.\n *\n * To learn more, check out our xref:ROOT:erc4626.adoc[ERC-4626 guide].\n * ====\n */\nabstract contract ERC4626 is ERC20, IERC4626 {\n    using Math for uint256;\n\n    IERC20 private immutable _asset;\n    uint8 private immutable _underlyingDecimals;\n\n    /**\n     * @dev Attempted to deposit more assets than the max amount for `receiver`.\n     */\n    error ERC4626ExceededMaxDeposit(address receiver, uint256 assets, uint256 max);\n\n    /**\n     * @dev Attempted to mint more shares than the max amount for `receiver`.\n     */\n    error ERC4626ExceededMaxMint(address receiver, uint256 shares, uint256 max);\n\n    /**\n     * @dev Attempted to withdraw more assets than the max amount for `receiver`.\n     */\n    error ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max);\n\n    /**\n     * @dev Attempted to redeem more shares than the max amount for `receiver`.\n     */\n    error ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max);\n\n    /**\n     * @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777).\n     */\n    constructor(IERC20 asset_) {\n        (bool success, uint8 assetDecimals) = _tryGetAssetDecimals(asset_);\n        _underlyingDecimals = success ? assetDecimals : 18;\n        _asset = asset_;\n    }\n\n    /**\n     * @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way.\n     */\n    function _tryGetAssetDecimals(IERC20 asset_) private view returns (bool, uint8) {\n        (bool success, bytes memory encodedDecimals) = address(asset_).staticcall(\n            abi.encodeCall(IERC20Metadata.decimals, ())\n        );\n        if (success && encodedDecimals.length >= 32) {\n            uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256));\n            if (returnedDecimals <= type(uint8).max) {\n                return (true, uint8(returnedDecimals));\n            }\n        }\n        return (false, 0);\n    }\n\n    /**\n     * @dev Decimals are computed by adding the decimal offset on top of the underlying asset's decimals. This\n     * \"original\" value is cached during construction of the vault contract. If this read operation fails (e.g., the\n     * asset has not been created yet), a default of 18 is used to represent the underlying asset's decimals.\n     *\n     * See {IERC20Metadata-decimals}.\n     */\n    function decimals() public view virtual override(IERC20Metadata, ERC20) returns (uint8) {\n        return _underlyingDecimals + _decimalsOffset();\n    }\n\n    /** @dev See {IERC4626-asset}. */\n    function asset() public view virtual returns (address) {\n        return address(_asset);\n    }\n\n    /** @dev See {IERC4626-totalAssets}. */\n    function totalAssets() public view virtual returns (uint256) {\n        return _asset.balanceOf(address(this));\n    }\n\n    /** @dev See {IERC4626-convertToShares}. */\n    function convertToShares(uint256 assets) public view virtual returns (uint256) {\n        return _convertToShares(assets, Math.Rounding.Floor);\n    }\n\n    /** @dev See {IERC4626-convertToAssets}. */\n    function convertToAssets(uint256 shares) public view virtual returns (uint256) {\n        return _convertToAssets(shares, Math.Rounding.Floor);\n    }\n\n    /** @dev See {IERC4626-maxDeposit}. */\n    function maxDeposit(address) public view virtual returns (uint256) {\n        return type(uint256).max;\n    }\n\n    /** @dev See {IERC4626-maxMint}. */\n    function maxMint(address) public view virtual returns (uint256) {\n        return type(uint256).max;\n    }\n\n    /** @dev See {IERC4626-maxWithdraw}. */\n    function maxWithdraw(address owner) public view virtual returns (uint256) {\n        return _convertToAssets(balanceOf(owner), Math.Rounding.Floor);\n    }\n\n    /** @dev See {IERC4626-maxRedeem}. */\n    function maxRedeem(address owner) public view virtual returns (uint256) {\n        return balanceOf(owner);\n    }\n\n    /** @dev See {IERC4626-previewDeposit}. */\n    function previewDeposit(uint256 assets) public view virtual returns (uint256) {\n        return _convertToShares(assets, Math.Rounding.Floor);\n    }\n\n    /** @dev See {IERC4626-previewMint}. */\n    function previewMint(uint256 shares) public view virtual returns (uint256) {\n        return _convertToAssets(shares, Math.Rounding.Ceil);\n    }\n\n    /** @dev See {IERC4626-previewWithdraw}. */\n    function previewWithdraw(uint256 assets) public view virtual returns (uint256) {\n        return _convertToShares(assets, Math.Rounding.Ceil);\n    }\n\n    /** @dev See {IERC4626-previewRedeem}. */\n    function previewRedeem(uint256 shares) public view virtual returns (uint256) {\n        return _convertToAssets(shares, Math.Rounding.Floor);\n    }\n\n    /** @dev See {IERC4626-deposit}. */\n    function deposit(uint256 assets, address receiver) public virtual returns (uint256) {\n        uint256 maxAssets = maxDeposit(receiver);\n        if (assets > maxAssets) {\n            revert ERC4626ExceededMaxDeposit(receiver, assets, maxAssets);\n        }\n\n        uint256 shares = previewDeposit(assets);\n        _deposit(_msgSender(), receiver, assets, shares);\n\n        return shares;\n    }\n\n    /** @dev See {IERC4626-mint}.\n     *\n     * As opposed to {deposit}, minting is allowed even if the vault is in a state where the price of a share is zero.\n     * In this case, the shares will be minted without requiring any assets to be deposited.\n     */\n    function mint(uint256 shares, address receiver) public virtual returns (uint256) {\n        uint256 maxShares = maxMint(receiver);\n        if (shares > maxShares) {\n            revert ERC4626ExceededMaxMint(receiver, shares, maxShares);\n        }\n\n        uint256 assets = previewMint(shares);\n        _deposit(_msgSender(), receiver, assets, shares);\n\n        return assets;\n    }\n\n    /** @dev See {IERC4626-withdraw}. */\n    function withdraw(uint256 assets, address receiver, address owner) public virtual returns (uint256) {\n        uint256 maxAssets = maxWithdraw(owner);\n        if (assets > maxAssets) {\n            revert ERC4626ExceededMaxWithdraw(owner, assets, maxAssets);\n        }\n\n        uint256 shares = previewWithdraw(assets);\n        _withdraw(_msgSender(), receiver, owner, assets, shares);\n\n        return shares;\n    }\n\n    /** @dev See {IERC4626-redeem}. */\n    function redeem(uint256 shares, address receiver, address owner) public virtual returns (uint256) {\n        uint256 maxShares = maxRedeem(owner);\n        if (shares > maxShares) {\n            revert ERC4626ExceededMaxRedeem(owner, shares, maxShares);\n        }\n\n        uint256 assets = previewRedeem(shares);\n        _withdraw(_msgSender(), receiver, owner, assets, shares);\n\n        return assets;\n    }\n\n    /**\n     * @dev Internal conversion function (from assets to shares) with support for rounding direction.\n     */\n    function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256) {\n        return assets.mulDiv(totalSupply() + 10 ** _decimalsOffset(), totalAssets() + 1, rounding);\n    }\n\n    /**\n     * @dev Internal conversion function (from shares to assets) with support for rounding direction.\n     */\n    function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view virtual returns (uint256) {\n        return shares.mulDiv(totalAssets() + 1, totalSupply() + 10 ** _decimalsOffset(), rounding);\n    }\n\n    /**\n     * @dev Deposit/mint common workflow.\n     */\n    function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual {\n        // If _asset is ERC777, `transferFrom` can trigger a reentrancy BEFORE the transfer happens through the\n        // `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer,\n        // calls the vault, which is assumed not malicious.\n        //\n        // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the\n        // assets are transferred and before the shares are minted, which is a valid state.\n        // slither-disable-next-line reentrancy-no-eth\n        SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n        _mint(receiver, shares);\n\n        emit Deposit(caller, receiver, assets, shares);\n    }\n\n    /**\n     * @dev Withdraw/redeem common workflow.\n     */\n    function _withdraw(\n        address caller,\n        address receiver,\n        address owner,\n        uint256 assets,\n        uint256 shares\n    ) internal virtual {\n        if (caller != owner) {\n            _spendAllowance(owner, caller, shares);\n        }\n\n        // If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the\n        // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer,\n        // calls the vault, which is assumed not malicious.\n        //\n        // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the\n        // shares are burned and after the assets are transferred, which is a valid state.\n        _burn(owner, shares);\n        SafeERC20.safeTransfer(_asset, receiver, assets);\n\n        emit Withdraw(caller, receiver, owner, assets, shares);\n    }\n\n    function _decimalsOffset() internal view virtual returns (uint8) {\n        return 0;\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     *\n     * CAUTION: See Security Considerations above.\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC20Permit} from \"../extensions/IERC20Permit.sol\";\nimport {Address} from \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    /**\n     * @dev An operation with an ERC20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Indicates a failed `decreaseAllowance` request.\n     */\n    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        forceApprove(token, spender, oldAllowance + value);\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n     * value, non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n        unchecked {\n            uint256 currentAllowance = token.allowance(address(this), spender);\n            if (currentAllowance < requestedDecrease) {\n                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n            }\n            forceApprove(token, spender, currentAllowance - requestedDecrease);\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data);\n        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC721} from \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n    /**\n     * @dev Returns the token collection name.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the token collection symbol.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n     */\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC721/IERC721.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in ``owner``'s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\n     *   a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or\n     *   {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\n     *   a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\n     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n     * understand this adds an external call which potentially creates a reentrancy vulnerability.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external;\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the address zero.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool approved) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n    /**\n     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n     * by `operator` from `from`, this function is called.\n     *\n     * It must return its Solidity selector to confirm the token transfer.\n     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be\n     * reverted.\n     *\n     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n     */\n    function onERC721Received(\n        address operator,\n        address from,\n        uint256 tokenId,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n"
      },
      "@openzeppelin/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev The ETH balance of the account is not enough to perform the operation.\n     */\n    error AddressInsufficientBalance(address account);\n\n    /**\n     * @dev There's no code at `target` (it is not a contract).\n     */\n    error AddressEmptyCode(address target);\n\n    /**\n     * @dev A call to an address target failed. The target may have reverted.\n     */\n    error FailedInnerCall();\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        if (address(this).balance < amount) {\n            revert AddressInsufficientBalance(address(this));\n        }\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        if (!success) {\n            revert FailedInnerCall();\n        }\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason or custom error, it is bubbled\n     * up by this function (like regular Solidity function calls). However, if\n     * the call reverted with no returned reason, this function reverts with a\n     * {FailedInnerCall} error.\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        if (address(this).balance < value) {\n            revert AddressInsufficientBalance(address(this));\n        }\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n     * unsuccessful call.\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata\n    ) internal view returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            // only check if target is a contract if the call was successful and the return data is empty\n            // otherwise we already know that it was a contract\n            if (returndata.length == 0 && target.code.length == 0) {\n                revert AddressEmptyCode(target);\n            }\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n     * revert reason or with a default {FailedInnerCall} error.\n     */\n    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n     */\n    function _revert(bytes memory returndata) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert FailedInnerCall();\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Base64.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.2) (utils/Base64.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides a set of functions to operate with Base64 strings.\n */\nlibrary Base64 {\n    /**\n     * @dev Base64 Encoding/Decoding Table\n     */\n    string internal constant _TABLE = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\n    /**\n     * @dev Converts a `bytes` to its Bytes64 `string` representation.\n     */\n    function encode(bytes memory data) internal pure returns (string memory) {\n        /**\n         * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence\n         * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol\n         */\n        if (data.length == 0) return \"\";\n\n        // Loads the table into memory\n        string memory table = _TABLE;\n\n        // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter\n        // and split into 4 numbers of 6 bits.\n        // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up\n        // - `data.length + 2`  -> Round up\n        // - `/ 3`              -> Number of 3-bytes chunks\n        // - `4 *`              -> 4 characters for each chunk\n        string memory result = new string(4 * ((data.length + 2) / 3));\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Prepare the lookup table (skip the first \"length\" byte)\n            let tablePtr := add(table, 1)\n\n            // Prepare result pointer, jump over length\n            let resultPtr := add(result, 0x20)\n            let dataPtr := data\n            let endPtr := add(data, mload(data))\n\n            // In some cases, the last iteration will read bytes after the end of the data. We cache the value, and\n            // set it to zero to make sure no dirty bytes are read in that section.\n            let afterPtr := add(endPtr, 0x20)\n            let afterCache := mload(afterPtr)\n            mstore(afterPtr, 0x00)\n\n            // Run over the input, 3 bytes at a time\n            for {\n\n            } lt(dataPtr, endPtr) {\n\n            } {\n                // Advance 3 bytes\n                dataPtr := add(dataPtr, 3)\n                let input := mload(dataPtr)\n\n                // To write each character, shift the 3 byte (24 bits) chunk\n                // 4 times in blocks of 6 bits for each character (18, 12, 6, 0)\n                // and apply logical AND with 0x3F to bitmask the least significant 6 bits.\n                // Use this as an index into the lookup table, mload an entire word\n                // so the desired character is in the least significant byte, and\n                // mstore8 this least significant byte into the result and continue.\n\n                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))\n                resultPtr := add(resultPtr, 1) // Advance\n\n                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))\n                resultPtr := add(resultPtr, 1) // Advance\n\n                mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))\n                resultPtr := add(resultPtr, 1) // Advance\n\n                mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))\n                resultPtr := add(resultPtr, 1) // Advance\n            }\n\n            // Reset the value that was cached\n            mstore(afterPtr, afterCache)\n\n            // When data `bytes` is not exactly 3 bytes long\n            // it is padded with `=` characters at the end\n            switch mod(mload(data), 3)\n            case 1 {\n                mstore8(sub(resultPtr, 1), 0x3d)\n                mstore8(sub(resultPtr, 2), 0x3d)\n            }\n            case 2 {\n                mstore8(sub(resultPtr, 1), 0x3d)\n            }\n        }\n\n        return result;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS\n    }\n\n    /**\n     * @dev The signature derives the `address(0)`.\n     */\n    error ECDSAInvalidSignature();\n\n    /**\n     * @dev The signature has an invalid length.\n     */\n    error ECDSAInvalidSignatureLength(uint256 length);\n\n    /**\n     * @dev The signature has an S value that is in the upper half order.\n     */\n    error ECDSAInvalidSignatureS(bytes32 s);\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not\n     * return address(0) without also returning an error description. Errors are documented using an enum (error type)\n     * and a bytes32 providing additional information about the error.\n     *\n     * If no error is returned, then the address can be used for verification purposes.\n     *\n     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     */\n    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {\n        unchecked {\n            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n            // We do not check for an overflow here since the shift operation results in 0 or 1.\n            uint8 v = uint8((uint256(vs) >> 255) + 27);\n            return tryRecover(hash, v, r, s);\n        }\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     */\n    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError, bytes32) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS, s);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature, bytes32(0));\n        }\n\n        return (signer, RecoverError.NoError, bytes32(0));\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.\n     */\n    function _throwError(RecoverError error, bytes32 errorArg) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert ECDSAInvalidSignature();\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert ECDSAInvalidSignatureLength(uint256(errorArg));\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert ECDSAInvalidSignatureS(errorArg);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/introspection/ERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/utils/math/Math.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    /**\n     * @dev Muldiv operation overflow.\n     */\n    error MathOverflowedMulDiv();\n\n    enum Rounding {\n        Floor, // Toward negative infinity\n        Ceil, // Toward positive infinity\n        Trunc, // Toward zero\n        Expand // Away from zero\n    }\n\n    /**\n     * @dev Returns the addition of two unsigned integers, with an overflow flag.\n     */\n    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            uint256 c = a + b;\n            if (c < a) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n     */\n    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b > a) return (false, 0);\n            return (true, a - b);\n        }\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n     */\n    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n            // benefit is lost if 'b' is also tested.\n            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n            if (a == 0) return (true, 0);\n            uint256 c = a * b;\n            if (c / a != b) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the division of two unsigned integers, with a division by zero flag.\n     */\n    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a / b);\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n     */\n    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a % b);\n        }\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds towards infinity instead\n     * of rounding towards zero.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (b == 0) {\n            // Guarantee the same behavior as in a regular Solidity division.\n            return a / b;\n        }\n\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n     * denominator == 0.\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n     * Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0 = x * y; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            if (denominator <= prod1) {\n                revert MathOverflowedMulDiv();\n            }\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n            uint256 twos = denominator & (0 - denominator);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n            // works in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n     * towards zero.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n     */\n    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n        return uint8(rounding) % 2 == 1;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/math/SignedMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n    /**\n     * @dev Returns the largest of two signed numbers.\n     */\n    function max(int256 a, int256 b) internal pure returns (int256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two signed numbers.\n     */\n    function min(int256 a, int256 b) internal pure returns (int256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two signed numbers without overflow.\n     * The result is rounded towards zero.\n     */\n    function average(int256 a, int256 b) internal pure returns (int256) {\n        // Formula from the book \"Hacker's Delight\"\n        int256 x = (a & b) + ((a ^ b) >> 1);\n        return x + (int256(uint256(x) >> 255) & (a ^ b));\n    }\n\n    /**\n     * @dev Returns the absolute unsigned value of a signed value.\n     */\n    function abs(int256 n) internal pure returns (uint256) {\n        unchecked {\n            // must be unchecked in order to support `n = type(int256).min`\n            return uint256(n >= 0 ? n : -n);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Strings.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)\n\npragma solidity ^0.8.20;\n\nimport {Math} from \"./math/Math.sol\";\nimport {SignedMath} from \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant HEX_DIGITS = \"0123456789abcdef\";\n    uint8 private constant ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev The `value` string doesn't fit in the specified `length`.\n     */\n    error StringsInsufficientHexLength(uint256 value, uint256 length);\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            uint256 length = Math.log10(value) + 1;\n            string memory buffer = new string(length);\n            uint256 ptr;\n            /// @solidity memory-safe-assembly\n            assembly {\n                ptr := add(buffer, add(32, length))\n            }\n            while (true) {\n                ptr--;\n                /// @solidity memory-safe-assembly\n                assembly {\n                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))\n                }\n                value /= 10;\n                if (value == 0) break;\n            }\n            return buffer;\n        }\n    }\n\n    /**\n     * @dev Converts a `int256` to its ASCII `string` decimal representation.\n     */\n    function toStringSigned(int256 value) internal pure returns (string memory) {\n        return string.concat(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value)));\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            return toHexString(value, Math.log256(value) + 1);\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        uint256 localValue = value;\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = HEX_DIGITS[localValue & 0xf];\n            localValue >>= 4;\n        }\n        if (localValue != 0) {\n            revert StringsInsufficientHexLength(value, length);\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal\n     * representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);\n    }\n\n    /**\n     * @dev Returns true if the two strings are equal.\n     */\n    function equal(string memory a, string memory b) internal pure returns (bool) {\n        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));\n    }\n}\n"
      },
      "contracts/BECAccessControl.sol": {
        "content": "// contracts/BECAccessControl.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n    /3333333     /33333333     /333333    \n   | 33__  33   | 33_____/    /33__  33   \n   | 33  \\ 33   | 33         | 33  \\__/   \n   | 3333333    | 33333      | 33         \n   | 33__  33   | 33__/      | 33         \n   | 33  \\ 33   | 33         | 33    33   \n   | 3333333/   | 33333333   |  333333/   \n   |_______/    |________/    \\______/    \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {AccessControl} from \"@openzeppelin/contracts/access/AccessControl.sol\";\n\n/**\n * @title Black Eyed Creatures Access Control\n * @author https://42i.co\n */\nabstract contract BECAccessControl is AccessControl {\n\n  /// @dev Role identifier for the GENETICIST role.\n  bytes32 public constant GENETICIST = keccak256(\"GENETICIST\");\n\n  /// @dev Constructor grants the GENETICIST role to the address deploying the contract.\n  constructor() {\n    _setRoleAdmin(GENETICIST, GENETICIST);\n    _grantRole(GENETICIST, msg.sender);\n  }\n}\n"
      },
      "contracts/BECCore.sol": {
        "content": "// contracts/BECCore.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n    /3333333     /33333333     /333333    \n   | 33__  33   | 33_____/    /33__  33   \n   | 33  \\ 33   | 33         | 33  \\__/   \n   | 3333333    | 33333      | 33         \n   | 33__  33   | 33__/      | 33         \n   | 33  \\ 33   | 33         | 33    33   \n   | 3333333/   | 33333333   |  333333/   \n   |_______/    |________/    \\______/    \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {ERC404B} from \"./erc404/ERC404B.sol\";\nimport {BECURIStorage} from \"./BECURIStorage.sol\";\n\n/**\n * @title Black Eyed Creatures Core Contract\n * @dev This is the base contract for Black Eyed Creatures (BEC).\n * @author https://42i.co\n */\ncontract BECCore is BECURIStorage {\n  /// @dev Role constants for managing access to specific methods.\n  bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n\n  /// @dev Mapping between creature ID and the seed that generates its DNA.\n  /// 0: Type (8, 3bit), Strategy (32, 5bit), Generation (4, 2bit), Seed (212bit)\n  mapping(uint256 creatureId => bytes32 seed) internal creatureSeed;\n\n  /// @dev Constructor initializes the ERC404 token with name \"Black Eyed Creatures\" and symbol \"BEC\".\n  constructor() ERC404B(\"Black Eyed Creatures\", \"BEC\", 333) {\n    _setRoleAdmin(MINTER_ROLE, GENETICIST);\n  }\n\n  /**\n   * @notice Mints new creatures with given DNA seeds for a specified address.\n   * @dev Only addresses with MINTER_ROLE can call this function.\n   * @param _creatureOwner Address of the new owner of the minted creatures.\n   * @param _seed A seed value used to generate creature DNAs.\n   * @param _quantity Quantity of minted creatures.\n   * @return creatureIds Array of IDs for the newly minted creatures.\n   */\n  function mintWithSeed(\n    address _creatureOwner,\n    bytes32 _seed,\n    uint256 _quantity\n  ) public payable onlyRole(MINTER_ROLE) returns (uint256[] memory) {\n    if (_quantity == 0) revert BECZeroQuantityMinting();\n    uint256 baseCreatureId = nextTokenId();\n    if (baseCreatureId + _quantity > 133333) revert BECCapLimitReached();\n    uint256[] memory mintedCreatureIds = new uint256[](_quantity);\n\n    _mint(_creatureOwner, _quantity);\n    creatureSeed[baseCreatureId] = _seed;\n\n    for (uint256 i = 0; i < _quantity; i++) {\n      mintedCreatureIds[i] = baseCreatureId + i;\n    }\n    return mintedCreatureIds;\n  }\n\n  /**\n   * @notice Retrieves the next available token ID for minting new creatures.\n   * @dev This function returns the token ID that will be assigned to the next minted creature.\n   * @return uint256 Next available token ID.\n   */\n  function nextTokenId() public view virtual returns (uint256) {\n    return _nextTokenId;\n  }\n\n  /**\n   * @notice Retrieves the seed of a creature by ID.\n   * @param _creatureId ID of the creature.\n   * @return bytes32 Seed of the creatures.\n   */\n  function getSeed(uint256 _creatureId) public view returns (bytes32) {\n    bytes32 seed = 0;\n    for (uint256 i = 0; seed == 0; i++) {\n      seed = creatureSeed[_creatureId - i];\n    }\n    return seed;\n  }\n\n  /**\n   * @notice Retrieves the seeds of a set creatures by ID.\n   * @param _creatureIds ID of the creatures.\n   * @return bytes32[] Seeds of the creatures.\n   */\n  function getSeeds(uint256[] calldata _creatureIds) public view returns (bytes32[] memory) {\n    bytes32[] memory seeds = new bytes32[](_creatureIds.length);\n    for (uint256 j = 0; j < _creatureIds.length; j++) {\n      seeds[j] = getSeed(_creatureIds[j]);\n    }\n    return seeds;\n  }\n\n  /**\n   * @notice Retrieves the total number of tokens currently in circulation.\n   * @dev This function returns the total count of tokens that have been minted and are currently in existence.\n   * @return uint256 Total number of tokens in circulation.\n   */\n  function totalTokens() public view returns (uint256) {\n    return _totalTokens();\n  }\n\n  /**\n   * @notice Burns a creature by ID.\n   * @dev Only owner or approved senders can call this function.\n   * @param _creatureId ID of the creature to be burned.\n   */\n  function burn(uint256 _creatureId) public {\n    if (!_isApprovedOrOwner(msg.sender, _creatureId)) revert ERC721InsufficientApproval(msg.sender, _creatureId);\n    _burn(_creatureId);\n  }\n\n  /**\n   * @notice Retrieves the number of creatures that have been burned.\n   * @return uint256 Number of burned creatures.\n   */\n  function burned() public view returns (uint256) {\n    return _burned();\n  }\n\n  /**\n   * @dev Forces the exemption status for ERC-721 transfers for the caller.\n   *      This function can only be called by the owner, and is created for setting as exempt DEXs & LPs.\n   *      An address that is not a contract, cannot be forced.\n   * \n   * Emits:\n   * - {Transfer} event for each target_ ERC721 token from/to the stash.\n   * \n   * @param _target The address to be setted as exempt.\n   * @param _state The new exemption state to set (true for exempt, false for non-exempt).\n   */\n  function forceERC721TransferExempt(address _target, bool _state) external onlyOwner {\n    if (_target.code.length == 0) revert BECInvalidAddress(_target);\n    _setERC721TransferExempt(_target, _state);\n  }\n}\n"
      },
      "contracts/BECEnabler.sol": {
        "content": "// contracts/BECEnabler.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n   /3333333    /33333333    /333333 \n  | 33__  33  | 33_____/   /33__  33\n  | 33  \\ 33  | 33        | 33  \\__/\n  | 3333333   | 33333     | 33      \n  | 33__  33  | 33__/     | 33      \n  | 33  \\ 33  | 33        | 33    33\n  | 3333333/  | 33333333  |  333333/\n  |_______/   |________/   \\______/ \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {BECWithdrawable} from \"./BECWithdrawable.sol\";\n\n/**\n * @title Black Eyed Creatures Enabler\n * @author https://42i.co\n */\ncontract BECEnabler is BECWithdrawable {\n\n  event BECEnabled(address contractAddress);\n\n  /// @dev Internal state variable to track whether the BEC ecosystem is enabled.\n  bool internal enabled = false;\n\n  /**\n   * @notice Checks whether the contract enabled.\n   * @return bool True if the contract is enabled, false otherwise.\n   */\n  function isEnabled() external view returns (bool) {\n    return enabled;\n  }\n\n  /**\n   * @notice Enables the BEC ecosystem functionalities.\n   * @dev Sets the internal `enabled` state variable to true, activating the functionalities of the BEC ecosystem that depend on this state. \n   *      This action can typically control the operational state of various contract features, such as minting or token transfers.\n   */\n  function enable() external onlyOwner {\n    enabled = true;\n    emit BECEnabled(address(this));\n  }\n}\n"
      },
      "contracts/BECGenesisEngine.sol": {
        "content": "// contracts/BECGenesisEngine.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n   /3333333    /33333333    /333333 \n  | 33__  33  | 33_____/   /33__  33\n  | 33  \\ 33  | 33        | 33  \\__/\n  | 3333333   | 33333     | 33      \n  | 33__  33  | 33__/     | 33      \n  | 33  \\ 33  | 33        | 33    33\n  | 3333333/  | 33333333  |  333333/\n  |_______/   |________/   \\______/ \n\n # http://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {BECCore} from \"./BECCore.sol\";\nimport {BECLab} from \"./BECLab.sol\";\nimport {BECWithdrawable} from \"./BECWithdrawable.sol\";\nimport {BECAccessControl} from \"./BECAccessControl.sol\";\nimport {IBECDnaStrategy} from \"./strategies/IBECDnaStrategy.sol\";\nimport {IBECMetaExtension} from \"./meta-extensions/IBECMetaExtension.sol\";\nimport {IERC721Errors} from \"@openzeppelin/contracts/interfaces/draft-IERC6093.sol\";\n\n/**\n * @title Black Eyed Creatures Genesis Engine Contract\n * @notice Orchestrates the unveiling of creature DNA within the Black Eyed Creatures universe.\n * @dev Manages the revelation of creature DNA based on different logics.\n * @author https://42i.co\n */\ncontract BECGenesisEngine is BECWithdrawable, BECAccessControl, IERC721Errors {\n\n  /// @dev A constant identifier for the role that is permitted to update the genesis storage.\n  bytes32 public constant GENESIS_STORAGE_UPDATER = keccak256(\"GENESIS_STORAGE_UPDATER\");\n\n  /// @dev Core contract address.\n  address private immutable coreContractAddress;\n\n  /// @dev Nested mapping structure to store the probability information of each variation for each phenotype and family, represented bitwise.\n  /// The outermost mapping categorizes by [distribution].\n  /// The intermediate mapping categorizes by [phenotype].\n  /// The innermost mapping categorizes by [family].\n  /// The uint256 value associated with each [distribution][phenotype][family] contains:\n  ///   - familyTickets (32b): Represents the quantity of tickets allocated to this specific family, influencing the probability of selection.\n  ///   - variationsCount (8b): Indicates the total number of variations available within the family.\n  ///   - 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.\n  mapping(uint256 distribution => mapping(uint256 phenotype => mapping(uint256 family => uint256 tickets))) public tickets;\n\n  /// @dev A mapping storing uint256s, each containing 32-bit segments representing the total tickets for each phenotype in a specific distribution.\n  mapping(uint256 distribution => uint256 tickets) public phenotypeTickets;\n\n  /// @dev A mapping to store specific data associated with each creature, indexed by the creature's ID.\n  mapping(uint256 creatureId => uint256 value) public genesisStorage;\n\n  /// @dev A mapping that associates each dna strategy with a strategy contract address, indexed by the strategy ID.\n  mapping(uint256 strategyId => address contractAddress) public dnaStrategies;\n\n  /// @dev An array of metadata extensions.\n  IBECMetaExtension[] public extensions;\n\n  /**\n   * @notice Initializes the Genesis Engine.\n   * @dev Sets the coreContractAddress to the provided BEC core contract address.\n   * @param _becCore The address of the BEC core contract.\n   */\n  constructor(address _becCore) {\n    coreContractAddress = _becCore;\n    _setRoleAdmin(GENESIS_STORAGE_UPDATER, GENETICIST);\n  }\n\n  /**\n   * @notice Sets the genesis storage value for a specific creature.\n   * @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.\n   * @param _creatureId The ID of the creature for which the storage value is to be set.\n   * @param _value The value to be stored.\n   */\n  function setGenesisStorage(uint256 _creatureId, uint256 _value) public onlyRole(GENESIS_STORAGE_UPDATER) {\n    if (genesisStorage[_creatureId] != 0) revert BECGenesisStoreAlreadySet(_creatureId);\n    genesisStorage[_creatureId] = _value;\n  }\n\n  /**\n   * @notice Retrieves the DNA of a specific creature.\n   * @dev The function fetches the seed associated with the creature from the core contract, \n   *      determines the strategy using the seed, and then retrieves the DNA using the strategy. \n   *      It requires that the creature with the given ID exists.\n   * @param _creatureId The ID of the creature whose DNA is to be retrieved.\n   * @return uint256 The DNA of the specified creature.\n   */\n  function getDna(uint256 _creatureId) public view returns (uint256) {\n    BECCore coreContract = BECCore(payable(coreContractAddress));\n    if (!coreContract.exists(_creatureId)) revert ERC721NonexistentToken(_creatureId);\n    bytes32 seed = coreContract.getSeed(_creatureId);\n    IBECDnaStrategy strategy = IBECDnaStrategy(dnaStrategies[uint256(uint8(seed[0]) >> 3) & 0x1F]);\n    return strategy.getDna(_creatureId);\n  }\n\n  /**\n   * @notice Retrieves the token URI of a specific creature.\n   * @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.\n   * @param _creatureId The ID of the creature whose token URI is to be retrieved.\n   * @return string The token URI of the specified creature.\n   */\n  function tokenURI(uint256 _creatureId) public view returns (string memory) {\n    BECCore coreContract = BECCore(payable(coreContractAddress));\n    bytes32 seed = coreContract.getSeed(_creatureId);\n    IBECDnaStrategy strategy = IBECDnaStrategy(dnaStrategies[uint256(uint8(seed[0]) >> 3) & 0x1F]);\n    return strategy.tokenURI(_creatureId);\n  }\n\n  /**\n   * @notice Retrieves the genesis storage value for a specific creature.\n   * @dev Returns the stored value associated with the given creature ID from the genesisStorage mapping.\n   * @param _creatureId The ID of the creature whose genesis storage value is to be retrieved.\n   * @return uint256 The genesis storage value of the specified creature.\n   */\n  function getGenesisStorage(uint256 _creatureId) public view returns (uint256) {\n    return genesisStorage[_creatureId];\n  }\n\n  /**\n   * @notice Retrieves the amount of tickets of a family for a specific phenotype within a given distribution ID.\n   * @dev Accesses the tickets mapping with the provided _distribution, _phenotype, and _family to return the associated family ticket information.\n   * @param _distribution The distribution identifier.\n   * @param _phenotype The phenotype identifier.\n   * @param _family The family identifier within the phenotype.\n   * @return uint256 The family ticket information of the specified phenotype and family.\n   */\n  function getFamilyTickets(uint256 _distribution, uint256 _phenotype, uint256 _family) public view returns (uint256) {\n    return tickets[_distribution][_phenotype][_family] & 0xFFFFFFFF;\n  }\n\n  /**\n   * @notice Retrieves the amount of tickets of a variation for a specific phenotype and family within a given distribution ID.\n   * @dev Calculates the variation ticket information based on the stored ticket information and the provided _variation.\n   * @param _distribution The distribution identifier.\n   * @param _phenotype The phenotype identifier.\n   * @param _family The family identifier within the phenotype.\n   * @param _variation The variation identifier within the family.\n   * @return uint256 The variation ticket information of the specified phenotype, family, and variation.\n   */\n  function getVariationTickets(uint256 _distribution, uint256 _phenotype, uint256 _family, uint256 _variation) public view returns (uint256) {\n    return 1 << ((tickets[_distribution][_phenotype][_family] >> (40 + (_variation * 3))) & 0x7);\n  }\n\n  /**\n   * @notice Retrieves the count of variations for a specific phenotype and family within a given distribution ID.\n   * @dev Calculates the variations count based on the stored ticket information.\n   * @param _distribution The distribution identifier.\n   * @param _phenotype The phenotype identifier.\n   * @param _family The family identifier within the phenotype.\n   * @return uint256 The count of variations for the specified phenotype and family.\n   */\n  function getVariationsCount(uint256 _distribution, uint256 _phenotype, uint256 _family) public view returns (uint256) {\n    return (tickets[_distribution][_phenotype][_family] >> 32) & 0xFF;\n  }\n\n  /**\n   * @notice Retrieves the total number of tickets for each phenotype within a given distribution.\n   * @dev Accesses the ticketsPerPhenotype mapping with the provided _distribution ID to return the associated ticket count.\n   * @param _distribution The ID of the distribution.\n   * @return uint256 The total number of tickets for each phenotype in the specified distribution.\n   */\n  function getPhenotypeTickets(uint256 _distribution) public view returns (uint256) {\n    return phenotypeTickets[_distribution];\n  }\n\n  /**\n   * @notice Adds ticket information for a specific distribution.\n   * @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.\n   * @param _distribution The ID of the distribution to which the tickets are to be added.\n   * @param _phenotypeTickets The total number of tickets for each phenotype within the distribution.\n   * @param _tickets A two-dimensional array representing the ticket information to be added for each phenotype and family.\n   */\n  function addTickets(uint256 _distribution, uint256 _phenotypeTickets, uint256[][] memory _tickets) public onlyRole(GENETICIST) {\n    if (phenotypeTickets[_distribution] != 0) revert BECDistributionAlreadySet(_distribution);\n    phenotypeTickets[_distribution] = _phenotypeTickets;\n    for (uint256 i = 0; i < _tickets.length; i++) {\n      for (uint256 j = 0; j < _tickets[i].length; j++) {\n        tickets[_distribution][i][j] = _tickets[i][j];\n      }\n    }\n  }\n\n  /**\n   * @notice Registers a DNA strategy for a distribution.\n   * @dev Can only be called by an address with the GENETICIST role.\n   * @param _dnaStrategy The address of the DNA strategy contract to be registered.\n   */\n  function registerStrategy(address _dnaStrategy) public onlyRole(GENETICIST) {\n    IBECDnaStrategy dnaStrategy = IBECDnaStrategy(_dnaStrategy);\n    uint256 distributionId = dnaStrategy.getDistributionId();\n    if (tickets[distributionId][0][0] == 0) revert BECWrongDistributionId(distributionId);\n\n    uint256 strategyId = dnaStrategy.getStrategyId();\n    dnaStrategies[strategyId] = _dnaStrategy;\n  }\n\n  /**\n   * @notice Adds a new metadata extension to the Genesis Engine.\n   * @dev Appends a new extension contract address to the `extensions` array. \n   *      This function can only be invoked by an address with the GENETICIST role. \n   *      Each extension should implement the IBECMetaExtension interface.\n   * @param _extensionAddress The address of the metadata extension contract to add.\n   */\n  function addExtension(address _extensionAddress) public onlyRole(GENETICIST) {\n    IBECMetaExtension extension = IBECMetaExtension(_extensionAddress);\n    extensions.push(extension);\n  }\n\n  /**\n   * @notice Clears all registered metadata extensions from the Genesis Engine.\n   * @dev Deletes the `extensions` array, effectively removing all metadata extension contracts. \n   *      This action cannot be undone. This function can only be invoked by an address with the GENETICIST role.\n   */\n  function clearExtensions() public onlyRole(GENETICIST) {\n    delete extensions;\n  }\n\n  /**\n   * @notice Retrieves the addresses of all registered metadata extensions.\n   * @dev Returns an array of addresses for each metadata extension contract currently registered in the `extensions` array.\n   * @return An array of IBECMetaExtension contract addresses currently registered.\n   */\n  function getExtensions() external view returns (IBECMetaExtension[] memory) {\n    return extensions;\n  }\n}\n"
      },
      "contracts/BECLab.sol": {
        "content": "// contracts/BECLab.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n   /3333333    /33333333    /333333 \n  | 33__  33  | 33_____/   /33__  33\n  | 33  \\ 33  | 33        | 33  \\__/\n  | 3333333   | 33333     | 33      \n  | 33__  33  | 33__/     | 33      \n  | 33  \\ 33  | 33        | 33    33\n  | 3333333/  | 33333333  |  333333/\n  |_______/   |________/   \\______/ \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {BECCore} from \"./BECCore.sol\";\nimport {BECEnabler} from \"./BECEnabler.sol\";\nimport {BECAccessControl} from \"./BECAccessControl.sol\";\nimport {BECGenesisEngine} from \"./BECGenesisEngine.sol\";\nimport {EIP712} from \"./eip712/EIP712.sol\";\nimport {Strings} from \"@openzeppelin/contracts/utils/Strings.sol\";\nimport {ECDSA} from \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport {IERC721Errors} from \"@openzeppelin/contracts/interfaces/draft-IERC6093.sol\";\n\n/**\n * @title Black Eyed Creatures Lab Contract\n * @author https://42i.co\n */\ncontract BECLab is BECEnabler, BECAccessControl, EIP712, IERC721Errors {\n  using ECDSA for bytes32;\n\n  event FamilyNameSet(uint256 indexed phenotype, uint256 indexed family, uint256[] ambassadors, string name);\n  event VariationNameSet(uint256 indexed phenotype, uint256 indexed family, uint256 indexed variation, uint256[] ambassadors, string name);\n  event CreatureNameSet(uint256 indexed creatureId, string name);\n\n  /// @dev Core contract address.\n  address private immutable coreContractAddress;\n\n  /// @dev Genesis engine contract address.\n  address private immutable genesisEngineAddress;\n\n  /// @dev Blcksphr contract address.\n  address private immutable blcksphrsAddress;\n\n  /// @dev Mapping of the lab registry\n  /// Structure:\n  /// [bucket] each bucket stores 8 creature registries, of 4 bytes each\n  /// - isVariationAmbassador (1bit)\n  /// - isFamilyAmbassador (1bit)\n  /// - ambassadorPhenotype (3bit)\n  /// - ambassadorFamily (5bit)\n  /// - ambassadorVariation (6bit)\n  /// - omegas (16bit)\n  mapping(uint256 bucket => uint256 registries) internal labRegistry;\n\n  /// @dev Mapping that keeps track of each family name.\n  mapping(uint256 phenotype => mapping(uint256 family => string name)) public familyNames;\n\n  /// @dev Mapping that keeps track of each variation name.\n  mapping(uint256 phenotype => mapping(uint256 family => mapping(uint256 variation => string name))) public variationNames;\n\n  /// @dev Names of the creatures.\n  mapping(uint256 creatureId => string name) public names;\n\n  /// @dev Hash of names, and if they are used or not (default not).\n  mapping(bytes32 nameHash => bool isUsed) internal nameUsed;\n\n  /// @dev Mapping storing the amount of families and variations set by the address.\n  mapping(address caller => uint256 count) public familyVariationAndNamesSet;\n\n  /// @dev A constant identifier for the role that is permitted to update the lab register.\n  bytes32 public constant LAB_REGISTER_UPDATER = keccak256(\"LAB_REGISTER_UPDATER\");\n\n  /// @dev The typehash for the data type specified in the family structured data.\n  /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-typehash\n  bytes32 public constant VERIFY_FAMILY_TYPEHASH = keccak256(\"VerifyFamilyName(uint256 phenotype,uint256 family,uint256[] ambassadors,string name,address wallet)\");\n\n  /// @dev The typehash for the data type specified in the variation structured data.\n  /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-typehash\n  bytes32 public constant VERIFY_VARIATION_TYPEHASH = keccak256(\"VerifyVariationName(uint256 phenotype,uint256 family,uint256 variation,uint256[] ambassadors,string name,address wallet)\");\n\n  /**\n   * @dev Constructor for the Lab contract.\n   * @param _becCore The core contract address.\n   * @param _becGenesisEngine The genesis engine contract address.\n   * @param _blcksphrsAddress The blcksphr contract address.\n   */\n  constructor(address _becCore, address _becGenesisEngine, address _blcksphrsAddress) {\n    coreContractAddress = _becCore;\n    genesisEngineAddress = _becGenesisEngine;\n    blcksphrsAddress = _blcksphrsAddress;\n    _setRoleAdmin(LAB_REGISTER_UPDATER, GENETICIST);\n  }\n\n  /**\n   * @notice Checks if a variation name proposal meets the necessary criteria for a given phenotype, family, and variation.\n   * @dev This function examines the validity of a name proposal for a variation by assessing the criteria regarding\n   *      the phenotype, family, variation, and the three proposed ambassador creatures.\n   *      A successful execution of this function indicates the name proposal meets all established conditions.\n   * @param _phenotype The phenotype within which the family resides.\n   * @param _family The family within which the variation exists.\n   * @param _variation The specific variation for which the name validity is being verified.\n   * @param _ambassadorIds The 3 ambassador ids.\n   * @param _name The proposed name for the variation.\n   *\n   * Requirements:\n   * - Phenotype number must be less than 6.\n   * - Name length should be up to 8 characters.\n   * - Name must be alphanumeric.\n   * - The proposed ambassador creatures must be distinct.\n   * - The creatures cannot already be variation ambassadors.\n   * - Each proposed ambassador must be associated with the specified phenotype, family, and variation.\n   */\n  function verifyVariationName(\n    uint256 _phenotype,\n    uint256 _family,\n    uint256 _variation,\n    uint256[] memory _ambassadorIds,\n    string memory _name\n  ) public view {\n    // Verify basics\n    if (_phenotype > 5) revert BECInvalidPhenotype(_phenotype);\n    if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name);\n    if (!isAZ(bytes(_name))) revert BECInvalidName(_name);\n    if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name);\n    if (_ambassadorIds.length != 3) revert BECInvalidAmbassadorsLength(_ambassadorIds.length);\n    if (bytes(variationNames[_phenotype][_family][_variation]).length != 0)\n      revert BECVariationNameAlreadySet(_phenotype, _family, _variation);\n\n    // Verify creatures\n    if (\n      _ambassadorIds[0] == _ambassadorIds[1] ||\n      _ambassadorIds[0] == _ambassadorIds[2] ||\n      _ambassadorIds[1] == _ambassadorIds[2]\n    ) revert BECInvalidAmbassadors(_ambassadorIds[0], _ambassadorIds[1], _ambassadorIds[2]);\n\n    // Verifying ambassadors and family & variation for each creature\n    for (uint256 i = 0; i < 3; i++) {\n      uint256 registry = (labRegistry[_ambassadorIds[i] / 8] >> ((_ambassadorIds[i] % 8) * 32)) & 0xFFFFFFFF;\n      if (registry & 0x1 != 0) revert BECAlreadyVariationAmbassador(_ambassadorIds[i]);\n      verifyFamilyAndVariation(_phenotype, _family, _variation, _ambassadorIds[i]);\n    }\n  }\n\n  /**\n   * @notice Verifies if a creature's family and variation match the provided family and variation within a specified phenotype.\n   * @dev Extracts the creature's DNA related to the provided phenotype. It then verifies if the extracted DNA matches the provided family and variation.\n   *      A successful execution indicates that the creature has the expected family and variation within the specified phenotype.\n   * @param _phenotype The phenotype within which the family and variation reside.\n   * @param _family The expected family of the creature within the given phenotype.\n   * @param _variation The expected variation of the creature within the provided family.\n   * @param _creatureId The ID of the creature (creature) to be verified.\n   *\n   * Requirements:\n   * - The creature's family and variation, as determined from its DNA for the given phenotype, must match `_family` and `_variation` respectively.\n   */\n  function verifyFamilyAndVariation(\n    uint256 _phenotype,\n    uint256 _family,\n    uint256 _variation,\n    uint256 _creatureId\n  ) internal view {\n    unchecked {\n      uint256 phenotypeTraits = BECGenesisEngine(payable(genesisEngineAddress)).getDna(_creatureId) >> ((_phenotype * 16));\n      uint256 dnaVariation = (phenotypeTraits >> 8) & 0xFF;\n      uint256 dnaFamily = (phenotypeTraits) & 0xFF;\n\n      if (dnaFamily != _family) revert BECInvalidFamily(_creatureId);\n      if (dnaVariation != _variation) revert BECInvalidVariation(_creatureId);\n    }\n  }\n\n  /**\n   * @notice Allows a user to propose a name for a variation by specifying the phenotype, family, variation, ambassador creatures,\n   *         and the name itself.\n   * @dev This function allows users to suggest a name for a specific variation by proposing three creatures as ambassadors.\n   *      Before calling this function, users should call verifyVariationNameProposal() with the same parameters\n   *      to ensure that the proposal is valid.\n   *      The proposal will be checked by a validator backend after submission.\n   *      The proposal is validated through a signature. If the proposal meets all criteria, the name is set for the variation.\n   * @param _phenotype The phenotype within which the family resides.\n   * @param _family The family within which the variation exists.\n   * @param _variation The specific variation for which a name is being proposed.\n   * @param _ambassadorIds An array of ambassador creature IDs proposed for the naming.\n   * @param _name The proposed name for the variation.\n   *\n   * Requirements:\n   * - Phenotype number must be less than 6.\n   * - Name length should be up to 8 characters.\n   * - Name must be alphanumeric.\n   * - The proposal price must be met.\n   * - The caller must own all three proposed ambassador creatures.\n   * - The proposed ambassador creatures must be distinct.\n   * - The creatures cannot already be variation ambassadors.\n   * - There shouldn't be a pre-existing name or proposal for the specified variation.\n   */\n  function setVariationName(\n    uint256 _phenotype,\n    uint256 _family,\n    uint256 _variation,\n    uint256[] memory _ambassadorIds,\n    string memory _name,\n    bytes calldata _signature\n  ) public {\n    if (!enabled) revert BECNotEnabled();\n    // Verify basics\n    if (!validateVariationSignature(_phenotype, _family, _variation, _ambassadorIds, _name, _signature)) revert EIP712InvalidSignature(_signature);\n    if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name);\n    if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name);\n    if (bytes(variationNames[_phenotype][_family][_variation]).length != 0)\n      revert BECVariationNameAlreadySet(_phenotype, _family, _variation);\n\n    BECCore coreContract = BECCore(payable(coreContractAddress));\n    for (uint256 i = 0; i < 3; i++) {\n      // Verify ownership\n      if (msg.sender != coreContract.ownerOf(_ambassadorIds[i])) revert BECInvalidOwner(msg.sender, _ambassadorIds[i]);\n\n      // Verifying creature was not used for being ambassador\n      uint256 registry = (labRegistry[_ambassadorIds[i] / 8] >> ((_ambassadorIds[i] % 8) * 32)) & 0xFFFFFFFF;\n      if (registry & 0x1 != 0) revert BECAlreadyVariationAmbassador(_ambassadorIds[i]);\n\n      // Setting creature as ambassador in the registry\n      setVariationAmbassadorToRegistry(_ambassadorIds[i], _phenotype, _family, _variation);\n    }\n\n    // Set variation name\n    variationNames[_phenotype][_family][_variation] = _name;\n    nameUsed[keccak256(abi.encodePacked(_name))] = true;\n    familyVariationAndNamesSet[msg.sender] += 1;\n\n    emit VariationNameSet(_phenotype, _family, _variation, _ambassadorIds, _name);\n  }\n\n  /**\n   * @notice Validates the signature for a variation name proposal.\n   * @dev Checks if the provided signature is valid for the given variation name proposal details.\n   * @param _phenotype The phenotype ID involved in the proposal.\n   * @param _family The family ID involved in the proposal.\n   * @param _variation The variation ID for which the name is proposed.\n   * @param _ambassadorIds The IDs of the ambassador creatures proposed.\n   * @param _name The proposed name for the variation.\n   * @param _signature The signature to validate.\n   * @return bool Returns true if the signature is valid, false otherwise.\n   */\n  function validateVariationSignature(\n    uint256 _phenotype,\n    uint256 _family,\n    uint256 _variation,\n    uint256[] memory _ambassadorIds,\n    string memory _name,\n    bytes calldata _signature\n  ) internal view returns (bool) {\n    if (allowlistSigningKey == address(0)) revert EIP712BECSigningKeyNotSet();\n\n    bytes32 digest = keccak256(\n      abi.encodePacked(\n        \"\\x19\\x01\",\n        EIP712_DOMAIN_SEPARATOR,\n        keccak256(\n          abi.encode(\n            VERIFY_VARIATION_TYPEHASH,\n            _phenotype,\n            _family,\n            _variation,\n            keccak256(abi.encodePacked(_ambassadorIds)),\n            keccak256(bytes(_name)),\n            msg.sender\n          )\n        )\n      )\n    );\n\n    address recoveredAddress = digest.recover(_signature);\n    return recoveredAddress == allowlistSigningKey;\n  }\n\n  /**\n   * @notice Updates the registry entry to set the creature as a variation ambassador.\n   * @dev This function performs bitwise operations on the provided registry entry to indicate\n   *      that the creature is now an ambassador for a specified variation. It updates and returns\n   *      the modified registry entry by setting the appropriate bits based on the phenotype, family,\n   *      and variation passed as arguments.\n   * @param _creatureId The creature Id.\n   * @param _variationAmbassadorPhenotype The phenotype associated with the variation ambassador.\n   * @param _variationAmbassadorFamily The family associated with the variation ambassador.\n   * @param _variationAmbassadorVariation The specific variation the creature is an ambassador for.\n   */\n  function setVariationAmbassadorToRegistry(\n    uint256 _creatureId,\n    uint256 _variationAmbassadorPhenotype,\n    uint256 _variationAmbassadorFamily,\n    uint256 _variationAmbassadorVariation\n  ) private {\n    unchecked {\n      labRegistry[_creatureId / 8] |=\n        (1 |\n          (_variationAmbassadorPhenotype << 2) |\n          (_variationAmbassadorFamily << 5) |\n          (_variationAmbassadorVariation << 10)) <<\n        ((_creatureId % 8) * 32);\n    }\n  }\n\n  /**\n   * @notice Retrieves the name of a specified variation. If the variation hasn't been approved by ambassadors,\n   *         it returns a default name based on the family and variation numbers.\n   * @dev Checks the approval status of the variation using the variationAmbassadorsProposal mapping. If approved,\n   *      it fetches the name from the variationNames mapping. Otherwise, it constructs a default name.\n   * @param _phenotype The phenotype of the variation.\n   * @param _family The family of the variation.\n   * @param _variation The specific variation number.\n   * @return variationName The name of the variation or a default name if not approved.\n   */\n  function getVariationName(\n    uint256 _phenotype,\n    uint256 _family,\n    uint256 _variation\n  ) public view returns (string memory) {\n    if (bytes(variationNames[_phenotype][_family][_variation]).length != 0) {\n      return capitalized(variationNames[_phenotype][_family][_variation]);\n    }\n    return string(abi.encodePacked(\"#(\", Strings.toString(_family), \", \", Strings.toString(_variation), \")\"));\n  }\n\n  /**\n   * @notice Checks if a family name proposal meets the necessary criteria for a given phenotype and family.\n   * @dev This function examines the validity of a name proposal for a family by assessing the criteria regarding\n   *      the phenotype, family, and the three proposed ambassador creatures.\n   *      A successful execution of this function indicates the name proposal meets all established conditions.\n   *      The checks include validations for phenotype number, name length, name format,\n   *      ambassador uniqueness, and ambassador association with the specific phenotype and family.\n   *      It also ensures all variations within the family have been named before a family name is proposed.\n   * @param _phenotype The phenotype within which the family resides.\n   * @param _family The family for which the name validity is being verified.\n   * @param _ambassadorIds An array of ambassador creature IDs proposed for the naming.\n   * @param _name The proposed name for the family.\n   *\n   * Requirements:\n   * - Phenotype number must be less than 6.\n   * - Name length should be up to 8 characters.\n   * - Name must be alphanumeric.\n   * - The proposed ambassador creatures must be distinct.\n   * - Each proposed ambassador must be associated with the specified phenotype and family.\n   * - All variations within the family must have been named.\n   *\n   * @return Returns `true` if the name proposal is valid; reverts otherwise.\n   */\n  function verifyFamilyName(\n    uint256 _phenotype,\n    uint256 _family,\n    uint256[] memory _ambassadorIds,\n    string memory _name\n  ) public view returns (bool) {\n    unchecked {\n      // Verify basics\n      if (_phenotype > 5) revert BECInvalidPhenotype(_phenotype);\n      if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name);\n      if (!isAZ(bytes(_name))) revert BECInvalidName(_name);\n      if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name);\n      if (_ambassadorIds.length != 3) revert BECInvalidAmbassadorsLength(_ambassadorIds.length);\n      if (bytes(familyNames[_phenotype][_family]).length != 0) revert BECFamilyNameAlreadySet(_phenotype, _family);\n\n      BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineAddress));\n\n      // Verify all variations of the family set up\n      uint256 variationsCount = genesisEngineContract.getVariationsCount(0, _phenotype, _family);\n      for (uint256 v = 0; v < variationsCount; v++) {\n        if (bytes(variationNames[_phenotype][_family][v]).length == 0) revert BECNotAllVariationsSet(_phenotype, _family, v);\n      }\n\n      // Verify creatures are different\n      if (\n        _ambassadorIds[0] == _ambassadorIds[1] ||\n        _ambassadorIds[0] == _ambassadorIds[2] ||\n        _ambassadorIds[1] == _ambassadorIds[2]\n      ) revert BECInvalidAmbassadors(_ambassadorIds[0], _ambassadorIds[1], _ambassadorIds[2]);\n\n      // Verifying ambassadors and family & variation for each creature\n      for (uint256 i = 0; i < 3; i++) {\n        uint256 registry = (labRegistry[_ambassadorIds[i] / 8] >> ((_ambassadorIds[i] % 8) * 32)) & 0xFFFFFFFF;\n        verifyFamilyAmbassador(_ambassadorIds[i], registry);\n        verifyFamily(_phenotype, _family, _ambassadorIds[i]);\n      }\n\n      return true;\n    }\n  }\n\n  /**\n   * @notice Validates if a creature can be designated as a family ambassador.\n   * @dev Evaluates the provided creature's registry to determine if the creature can be designated as a family ambassador.\n   *      A successful execution indicates that the creature meets the criteria to become a family ambassador,\n   *      i.e., it is not already a family ambassador and it is a variation ambassador.\n   * @param _creatureId The creatureId to be verified.\n   * @param _registry The registry entry of the creature (creature) to be verified.\n   *\n   * Requirements:\n   * - The creature should not already be a family ambassador.\n   * - The creature must be a variation ambassador.\n   */\n  function verifyFamilyAmbassador(uint256 _creatureId, uint256 _registry) internal pure {\n    unchecked {\n      if ((_registry & 2) != 0) revert BECAlreadyFamilyAmbassador(_creatureId); // Checks that the second bit (isFamilyAmbassador) is 0\n      if ((_registry & 1) == 0) revert BECNotVariationAmbassador(_creatureId); // Checks that the first bit (isVariationAmbassador) is 1\n    }\n  }\n\n  /**\n   * @notice Verifies if the family of a creature corresponds to the specified family within a given phenotype.\n   * @dev Extracts the creature's DNA related to the given phenotype and checks if its family matches the provided `_family`.\n   *      A successful execution indicates the creature belongs to the expected family within the specified phenotype.\n   * @param _phenotype The phenotype within which the family resides.\n   * @param _family The expected family of the creature within the given phenotype.\n   * @param _creatureId The ID of the creature (creature) to be verified.\n   *\n   * Requirements:\n   * - The creature's family, as determined from its DNA for the given phenotype, must match `_family`.\n   */\n  function verifyFamily(uint256 _phenotype, uint256 _family, uint256 _creatureId) internal view {\n    unchecked {\n      uint256 phenotypeTraits = BECGenesisEngine(payable(genesisEngineAddress)).getDna(_creatureId) >>\n        ((_phenotype * 16));\n      uint256 dnaFamily = (phenotypeTraits) & 0xFF;\n      if (dnaFamily != _family) revert BECInvalidFamily(_creatureId);\n    }\n  }\n\n  /**\n   * @notice Proposes a name for a family within a specific phenotype.\n   * @dev This function allows users to suggest a name for a specific family by proposing three creatures as ambassadors.\n   *      The proposal will be checked by a validator backend after submission. If valid, the name will be approved.\n   *      The function includes basic validation for phenotype number, name length, name format, proposal price, \n   *      creature ownership, ambassador uniqueness, and previous proposals for the same family.\n   * @param _phenotype The phenotype within which the family resides.\n   * @param _family The family for which a name is being proposed.\n   * @param _ambassadorIds An array of ambassador creature IDs proposed for the naming.\n   * @param _name The proposed name for the family.\n   *\n   * Requirements:\n   * - Phenotype number must be less than 6.\n   * - Name length should be up to 8 characters.\n   * - Name must be alphanumeric.\n   * - The proposal price must be met.\n   * - The caller must own all three proposed ambassador creatures.\n   * - The proposed ambassador creatures must be distinct.\n   * - All family variations should have their names set.\n   * - The creatures cannot already be family ambassadors.\n   * - There shouldn't be a pre-existing name or proposal for the specified family.\n   */\n  function setFamilyName(\n    uint256 _phenotype,\n    uint256 _family,\n    uint256[] memory _ambassadorIds,\n    string memory _name,\n    bytes calldata _signature\n  ) public {\n    if (!enabled) revert BECNotEnabled();\n    // Verify not already set\n    if (!validateFamilySignature(_phenotype, _family, _ambassadorIds, _name, _signature)) revert EIP712InvalidSignature(_signature);\n    if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name);\n    if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name);\n    if (bytes(familyNames[_phenotype][_family]).length != 0) revert BECFamilyNameAlreadySet(_phenotype, _family);\n\n    BECCore coreContract = BECCore(payable(coreContractAddress));\n    for (uint256 i = 0; i < 3; i++) {\n      if (msg.sender != coreContract.ownerOf(_ambassadorIds[i])) revert BECInvalidOwner(msg.sender, _ambassadorIds[i]);\n      uint256 registry = (labRegistry[_ambassadorIds[i] / 8] >> ((_ambassadorIds[i] % 8) * 32)) & 0xFFFFFFFF;\n      verifyFamilyAmbassador(_ambassadorIds[i], registry);\n      setFamilyAmbassadorToRegistry(_ambassadorIds[i], _phenotype, _family);\n    }\n\n    familyNames[_phenotype][_family] = _name;\n    nameUsed[keccak256(abi.encodePacked(_name))] = true;\n    familyVariationAndNamesSet[msg.sender] += 1 << 64;\n\n    emit FamilyNameSet(_phenotype, _family, _ambassadorIds, _name);\n  }\n\n  /**\n   * @notice Validates the signature for a family name proposal.\n   * @dev Checks if the provided signature is valid for the given family name proposal details.\n   * @param _phenotype The phenotype ID involved in the proposal.\n   * @param _family The family ID for which the name is proposed.\n   * @param _ambassadorIds The IDs of the ambassador creatures proposed.\n   * @param _name The proposed name for the family.\n   * @param _signature The signature to validate.\n   * @return bool Returns true if the signature is valid, false otherwise.\n   */\n  function validateFamilySignature(\n    uint256 _phenotype,\n    uint256 _family,\n    uint256[] memory _ambassadorIds,\n    string memory _name,\n    bytes calldata _signature\n  ) internal view returns (bool) {\n    if (allowlistSigningKey == address(0)) revert EIP712BECSigningKeyNotSet();\n\n    bytes32 digest = keccak256(\n      abi.encodePacked(\n        \"\\x19\\x01\",\n        EIP712_DOMAIN_SEPARATOR,\n        keccak256(\n          abi.encode(\n            VERIFY_FAMILY_TYPEHASH,\n            _phenotype,\n            _family,\n            keccak256(abi.encodePacked(_ambassadorIds)),\n            keccak256(bytes(_name)),\n            msg.sender\n          )\n        )\n      )\n    );\n\n    address recoveredAddress = digest.recover(_signature);\n    return recoveredAddress == allowlistSigningKey;\n  }\n\n  /**\n   * @notice Retrieves the name of a family within a specific phenotype.\n   * @dev This function returns the name of a family based on the given phenotype and family parameters.\n   *      If the ambassador proposal for the family name has been approved, it returns the assigned family name.\n   *      Otherwise, it returns a default placeholder name constructed with the family number.\n   * @param _phenotype The phenotype within which the family resides.\n   * @param _family The specific family for which the name is being queried.\n   * @return A string representing either the assigned name of the family (if the name proposal was approved)\n   *         or a default placeholder name indicating the family number.\n   */\n  function getFamilyName(uint256 _phenotype, uint256 _family) public view returns (string memory) {\n    if (bytes(familyNames[_phenotype][_family]).length != 0) {\n      return capitalized(familyNames[_phenotype][_family]);\n    }\n    return string(abi.encodePacked(\"#(\", Strings.toString(_family), \")\"));\n  }\n\n  /**\n   * @notice Updates the registry entry to set the creature as a family ambassador.\n   * @dev This function performs bitwise operations on the provided registry entry to indicate\n   *      that the creature is now an ambassador for a specified family. It updates and returns\n   *      the modified registry entry by setting the appropriate bits based on the laphenotypeyer and family\n   *      passed as arguments.\n   * @param _creatureId The creature Id.\n   * @param _phenotype The phenotype associated with the family ambassador.\n   * @param _family The specific family the creature is an ambassador for.\n   */\n  function setFamilyAmbassadorToRegistry(uint256 _creatureId, uint256 _phenotype, uint256 _family) private {\n    unchecked {\n      labRegistry[_creatureId / 8] |= (2 | (_phenotype << 2) | (_family << 5)) << ((_creatureId % 8) * 32);\n    }\n  }\n\n  /**\n   * @notice Determines whether the provided string consists only of A-Z characters.\n   * @dev The function checks each character of the input string to ensure it's a letter (A-Z).\n   *      Non-alphabetic characters will result in a return value of false.\n   *      ^[A-Z]{0,6}$\n   * @param _string The input string, given as a byte array, to be verified.\n   * @return bool Returns true if all characters in the string are A-Z, otherwise returns false.\n   */\n  function isAZ(bytes memory _string) internal pure returns (bool) {\n    unchecked {\n      if (_string.length < 3 || _string.length > 7) {\n        return false;\n      }\n      for (uint256 i = 0; i < _string.length; i++) {\n        bytes1 char = _string[i];\n        if (char < 0x41 || char > 0x5A) { // not A-Z\n          return false;\n        }\n      }\n      return true;\n    }\n  }\n\n  /**\n   * @notice Removes the capitalization of all characters besides the first one.\n   * @dev This function iterates over all the elements of the string array and transforms it to lowercase.\n   * @param _caps the string all in caps.\n   * @return A string capitalized. (First leter in uppercase, the rest in lowercase).\n   */\n  function capitalized(string memory _caps) internal pure returns (string memory) {\n    bytes memory b = bytes(_caps);\n    for (uint i = 1; i < b.length; i++) {\n      if (uint8(b[i]) >= 65 && uint8(b[i]) <= 90) {\n        b[i] = bytes1(uint8(b[i]) + 32);\n      }\n    }\n    return string(b);\n  }\n\n  /**\n   * @notice Sets the allowlist signing key for validating signatures.\n   * @dev Updates the allowlist signing key used for signature validation in name proposals.\n   * @param newSigningKey The new signing key to be used for validation.\n   */\n  function setAllowlistSigningAddress(address newSigningKey) public onlyRole(GENETICIST) {\n    _setAllowlistSigningAddress(newSigningKey);\n  }\n\n  /**\n   * @notice Retrieves the lab registry record for a specific creature.\n   * @dev Fetches the registry record for a creature based on its ID.\n   *      The record contains information about the creature's ambassador status and other traits.\n   * @param _creatureId The ID of the creature.\n   * @return uint256 The registry record of the specified creature.\n   */\n  function getLabRegistryRecord(uint256 _creatureId) external view returns (uint256) {\n    return (labRegistry[_creatureId / 8] >> ((_creatureId % 8) * 32)) & 0xFFFFFFFF;\n  }\n\n  /**\n   * @notice Retrieves the number of Omegas for a specific creature.\n   * @dev Fetches the Omega count for a creature from the lab registry based on its ID.\n   * @param _creatureId The ID of the creature.\n   * @return uint256 The number of Omegas associated with the creature.\n   */\n  function getOmegas(uint256 _creatureId) external view returns (uint256) {\n    return (labRegistry[_creatureId / 8] >> ((((_creatureId % 8) * 32)) + 16)) & 0xFFFF;\n  }\n\n  /**\n   * @notice Increments the Omega count for a specific creature.\n   * @dev Adds a specified quantity to the Omega count of a creature in the lab registry.\n   * @param _creatureId The ID of the creature.\n   * @param _quantity The quantity to add to the creature's Omega count.\n   */\n  function incrementOmegas(uint256 _creatureId, uint256 _quantity) external onlyRole(LAB_REGISTER_UPDATER) {\n    labRegistry[_creatureId / 8] += _quantity << (16 + ((_creatureId % 8) * 32));\n  }\n\n  /**\n   * @notice Grants the LAB_REGISTER_UPDATER role to a specified address.\n   * @dev Assigns the role responsible for updating lab registry entries to a given address.\n   * @param _address The address to be granted the LAB_REGISTER_UPDATER role.\n   */\n  function grantLabRegisterUpdaterRole(address _address) external onlyRole(GENETICIST) {\n    grantRole(LAB_REGISTER_UPDATER, _address);\n  }\n\n  /**\n   * @notice Sets a name for a specific creature.\n   * @dev Assigns a name to a creature based on its ID. The caller must be the owner of the creature.\n   * @param _creatureId The ID of the creature.\n   * @param _name The name to assign to the creature.\n   */\n  function setCreatureName(uint256 _creatureId, string memory _name) public {\n    BECCore coreContract = BECCore(payable(coreContractAddress));\n    if (msg.sender != coreContract.ownerOf(_creatureId)) revert BECInvalidOwner(msg.sender, _creatureId);\n    if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name);\n    if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name);\n    if (!isAZ(bytes(_name))) revert BECInvalidName(_name);\n\n    names[_creatureId] = _name;\n    nameUsed[keccak256(abi.encodePacked(_name))] = true;\n    familyVariationAndNamesSet[msg.sender] += 1 << 128;\n\n    emit CreatureNameSet(_creatureId, _name);\n  }\n\n  /**\n   * @notice Retrieves the name of a specific creature.\n   * @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.\n   * @param _creatureId The ID of the creature.\n   * @return string The name of the creature or a default name if no custom name is set.\n   */\n  function getCreatureName(uint256 _creatureId) external view virtual returns (string memory) {\n    if (bytes(names[_creatureId]).length > 0) {\n      return capitalized(names[_creatureId]);\n    }\n    return string(abi.encodePacked(\"BEC #\", Strings.toString(_creatureId)));\n  }\n}\n"
      },
      "contracts/BECRewardsMinter.sol": {
        "content": "// contracts/BECRewardsMinter.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n   /3333333    /33333333    /333333 \n  | 33__  33  | 33_____/   /33__  33\n  | 33  \\ 33  | 33        | 33  \\__/\n  | 3333333   | 33333     | 33      \n  | 33__  33  | 33__/     | 33      \n  | 33  \\ 33  | 33        | 33    33\n  | 3333333/  | 33333333  |  333333/\n  |_______/   |________/   \\______/ \n\n # http://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {BECCore} from \"./BECCore.sol\";\nimport {BECWithdrawable} from \"./BECWithdrawable.sol\";\nimport {IERC721Errors} from \"@openzeppelin/contracts/interfaces/draft-IERC6093.sol\";\nimport \"hardhat/console.sol\";\n\n/**\n * @title TODO\n * @author https://42i.co\n */\ncontract BECRewardsMinter is BECWithdrawable, IERC721Errors {\n  /// @dev Core contract address.\n  address private immutable coreContractAddress;\n\n  address private immutable receiver;\n\n  /// @dev Strategy Logs.\n  uint256 private strategyLogs;\n\n  uint256 mintedRewards;\n\n  /**\n   * @notice Initializes the Rewards Minter.\n   * @dev Sets the coreContractAddress to the provided BEC core contract address. Mint 3000 creatures to the caller.\n   * @param _coreContractAddress The address of the BEC core contract.\n   * TODO: documant\n   */\n  constructor(address _coreContractAddress, address _receiver, uint256 _strategyId, uint256 _distributionId, uint256 _typeId) {\n    unchecked {\n      strategyLogs = _typeId | (_strategyId << 3) | (_distributionId << 8);\n      coreContractAddress = _coreContractAddress;\n      receiver = _receiver;\n      mintedRewards = 0;\n    }\n  }\n\n  \n\n  // TODO: document\n  function mintRewards() external onlyOwner {\n    unchecked {\n      BECCore coreContract = BECCore(payable(coreContractAddress));\n      uint256 batchSize = 128;\n      if (mintedRewards <= 3000) {\n        uint256 lastCreatureId = coreContract.nextTokenId() - 1;\n        bytes32 seedValue = keccak256(abi.encodePacked(address(this), block.number, lastCreatureId));\n\n        // Clear the first 10 bits of seedValue, Set type, strategy and generation of the new creature.\n        seedValue &= bytes32(~(uint256(0x3FF) << 246)); // 246 = 256-10\n        seedValue |= bytes32(uint256(strategyLogs & 0xFF) << 248);\n\n        uint256 quantity = batchSize;\n        if (mintedRewards + batchSize > 3000) {\n          quantity = 3000 - (mintedRewards + batchSize);\n        }\n\n        coreContract.mintWithSeed(receiver, seedValue, quantity);\n        mintedRewards += quantity;\n      }\n    }\n  }\n}\n"
      },
      "contracts/BECURIStorage.sol": {
        "content": "// contracts/BECURIStorage.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n   /3333333    /33333333    /333333 \n  | 33__  33  | 33_____/   /33__  33\n  | 33  \\ 33  | 33        | 33  \\__/\n  | 3333333   | 33333     | 33      \n  | 33__  33  | 33__/     | 33      \n  | 33  \\ 33  | 33        | 33    33\n  | 3333333/  | 33333333  |  333333/\n  |_______/   |________/   \\______/ \n\n # http://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {ERC404B} from \"./erc404/ERC404B.sol\";\nimport {BECAccessControl} from \"./BECAccessControl.sol\";\nimport {BECGenesisEngine} from \"./BECGenesisEngine.sol\";\nimport {BECWithdrawable} from \"./BECWithdrawable.sol\";\nimport {EIP712} from \"./eip712/EIP712.sol\";\nimport {AccessControl} from \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport {Strings} from \"@openzeppelin/contracts/utils/Strings.sol\";\nimport {ECDSA} from \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\n\n/**\n * @title Black Eyed Creatures URI Storage\n * @dev Contract for managing URIs and IPFS-related functionality for Black Eyed Creatures (BEC) tokens.\n * @author https://42i.co\n */\nabstract contract BECURIStorage is ERC404B, BECAccessControl, BECWithdrawable, EIP712 {\n\n  /// @dev Using Elliptic Curve Digital Signature Algorithm (ECDSA).\n  using ECDSA for bytes32;\n\n  /// @dev Base URI for retrieve creature images.\n  string _tokenBaseURI;\n\n  /// @dev Base URL for the site.\n  string internal _siteBaseUrl;\n\n  /// @dev Genesis engine contract address.\n  address genesisEngineContractAddress;\n\n  /// @dev Mapping containing the IPFS uri of each token.\n  mapping(uint256 tokenId => string ipfsUri) public ipfsUris;\n\n  // The typehash for the data type specified in the structured data.\n  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-typehash\n  bytes32 public constant IPFS_URI_TYPEHASH = keccak256(\"SetIPFSUri(uint256 creatureId,string uri)\");\n\n  /**\n   * @dev See {IERC165-supportsInterface}.\n   */\n  function supportsInterface(bytes4 _interfaceId) public view virtual override(ERC404B, AccessControl) returns (bool) {\n    return super.supportsInterface(_interfaceId);\n  }\n\n  /**\n   * @notice Sets the Base Token URI.\n   * @param _uri the URI to set.\n   */\n  function setBaseURI(string memory _uri) public onlyOwner {\n    _tokenBaseURI = _uri;\n  }\n\n  /**\n   * @notice Sets the Site Base Token URI.\n   * @dev Allows the owner to set the base URL for the site.\n   * @param _uri The new site base URI to set.\n   */\n  function setSiteBaseURI(string memory _uri) public onlyOwner {\n    _siteBaseUrl = _uri;\n  }\n\n  /**\n   * @notice Sets the IPFS-specific Token URI.\n   * @dev Allows setting a specific IPFS URI for a creature token.\n   * @param _creatureId The ID of the creature token.\n   * @param _uri The IPFS URI to set for the token.\n   * @param _signature The signature to validate the operation.\n   */\n  function setIPFSTokenURI(uint256 _creatureId, string calldata _uri, bytes calldata _signature) public {\n    if (!validateIPFSUriSignature(_creatureId, _uri, _signature)) revert EIP712InvalidSignature(_signature);\n    ipfsUris[_creatureId] = _uri;\n  }\n\n  /**\n   * @notice Gets the Site Base Token URI.\n   * @dev Returns the current site base URI.\n   * @return uri The current site base URI.\n   */\n  function getSiteBaseURI() public view returns (string memory uri) {\n    return _siteBaseUrl;\n  }\n\n  /**\n   * @notice Gets the image URI for a creature token.\n   * @dev Generates and returns the image URI for a given creature token ID.\n   * @param _creatureId The ID of the creature token.\n   * @return uri The image URI for the creature token.\n   */\n  function getImageURI(uint256 _creatureId) public view returns (string memory uri) {\n    if (bytes(ipfsUris[_creatureId]).length > 0) {\n      return ipfsUris[_creatureId];\n    }\n    else {\n      return string(\n        abi.encodePacked(\n          _tokenBaseURI,\n          Strings.toHexString(uint256(uint160(address(this))), 20),\n          \"/\",\n          Strings.toString(_creatureId),\n          \".png\"\n        )\n      );\n    }\n  }\n\n  /**\n   * @dev See {IERC721Metadata-tokenURI}.\n   */\n  function tokenURI(uint256 _creatureId) public view virtual override returns (string memory) {\n    BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineContractAddress));\n    return genesisEngineContract.tokenURI(_creatureId);\n  }\n\n  /**\n   * @notice Sets the address of the Genesis Engine contract.\n   * @dev Allows the contract to interact with the Genesis Engine, enabling dynamic token URI generation based on creature DNA.\n   * @param _genesisEngineContractAddress The address of the Genesis Engine contract.\n   */\n  function setGenesisEngineContractAddress(address _genesisEngineContractAddress) public onlyRole(GENETICIST) {\n    genesisEngineContractAddress = _genesisEngineContractAddress;\n  }\n\n  /**\n   * @notice Sets a new signing key for the allowlist.\n   * @dev Updates the signing key used to validate signatures for certain privileged operations.\n   * @param _signingKey The new public address to be used as the signing key.\n   */\n  function setAllowlistSigningAddress(address _signingKey) public onlyOwner {\n    _setAllowlistSigningAddress(_signingKey);\n  }\n\n    /**\n   * @notice Validates the signature for setting IPFS image creature uri.\n   * @dev Uses EIP-712 signing standard to verify the signature against the expected message format and content,\n   *      including the creatureId, and the IPFS URI of the creature.\n   * @param _creatureId The creature.\n   * @param _uri The IPFS uri for the creature.\n   * @param _signature The signature to validate.\n   * @return bool True if the signature is valid, false otherwise.\n   */\n  function validateIPFSUriSignature(\n    uint256 _creatureId,\n    string calldata _uri,\n    bytes calldata _signature\n  ) internal view returns (bool) {\n    if (allowlistSigningKey == address(0)) revert EIP712BECSigningKeyNotSet();\n\n    bytes32 digest = keccak256(\n      abi.encodePacked(\n        \"\\x19\\x01\",\n        EIP712_DOMAIN_SEPARATOR,\n        keccak256(abi.encode(IPFS_URI_TYPEHASH, _creatureId, keccak256(bytes(_uri)), msg.sender))\n      )\n    );\n\n    address recoveredAddress = digest.recover(_signature);\n    return recoveredAddress == allowlistSigningKey;\n  }\n}\n"
      },
      "contracts/BECWithdrawable.sol": {
        "content": "// contracts/BECWithdrawable.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n   /3333333    /33333333    /333333 \n  | 33__  33  | 33_____/   /33__  33\n  | 33  \\ 33  | 33        | 33  \\__/\n  | 3333333   | 33333     | 33      \n  | 33__  33  | 33__/     | 33      \n  | 33  \\ 33  | 33        | 33    33\n  | 3333333/  | 33333333  |  333333/\n  |_______/   |________/   \\______/ \n\n # http://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {IBECErrors} from \"./IBECErrors.sol\";\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IERC721} from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\n\n/**\n * @title Black Eyed Creatures Widthdrawable Contract\n * @dev This contract adds the availablitily to extract ether and erc-20 token balance from the contract that\n *      implements it.\n * @author https://42i.co\n */\nabstract contract BECWithdrawable is Ownable, IBECErrors {\n\n  /// @dev Event emitted when the contract receives ether from an address.\n  event Received(address from, uint256 amount);\n\n  /// @dev Constructor for Withdrawable.\n  constructor () Ownable(msg.sender) {}\n\n  /**\n   * @dev Withdraws specified amount of royalties from contract to address.\n   * @param _amount amount of royalties to withdraw.\n   * @param _address address to withdraw the balance to.\n   */\n  function withdraw(uint256 _amount, address payable _address) public payable onlyOwner {\n    if (_address == address(0)) revert BECInvalidAddress(_address);\n    if (_amount > address(this).balance) revert BECInsufficientFunds(_amount, address(this).balance);\n    _address.transfer(_amount);\n  }\n\n  /**\n   * @dev Withdraws token specified ERC20 amount to the given address.\n   * @param _tokenAddress Address of the token to withdraw.\n   * @param _amount Amount of tokens to withdraw.\n   * @param _address Address to withdraw the tokens to.\n   */\n  function withdrawERC20Token(\n    address _tokenAddress,\n    uint256 _amount,\n    address payable _address\n  ) public payable onlyOwner {\n    IERC20 tokenContract = IERC20(_tokenAddress);\n    if (_address == address(0)) revert BECInvalidAddress(_address);\n    if (_amount > tokenContract.balanceOf(address(this))) revert BECInsufficientFunds(_amount, tokenContract.balanceOf(address(this)));\n    tokenContract.transfer(_address, _amount);\n  }\n\n  /**\n   * @dev Withdraws token specified ERC721 tokenId to the given address.\n   * @param _tokenAddress Address of the token to withdraw.\n   * @param _tokenId The id of the token to withdraw.\n   * @param _address Address to withdraw the tokens to.\n   */\n  function withdrawERC721Token(\n    address _tokenAddress,\n    uint256 _tokenId,\n    address _address\n  ) public payable onlyOwner {\n    IERC721 tokenContract = IERC721(_tokenAddress);\n    if (_address == address(0)) revert BECInvalidAddress(_address);\n    if (address(this) != tokenContract.ownerOf(_tokenId)) revert BECInvalidOwner(address(this), _tokenId);\n    tokenContract.safeTransferFrom(address(this), _address, _tokenId);\n  }\n\n  /**\n   * @dev Function to receive Ether. msg.data must be empty.\n   */\n  receive() external payable {\n    emit Received(msg.sender, msg.value);\n  }\n\n  /**\n   * @dev Fallback function is called when msg.data is not empty.\n   */\n  fallback() external payable {}\n}\n"
      },
      "contracts/eip712/EIP712.sol": {
        "content": "// contracts/eip712/EIP712.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n   /3333333    /33333333    /333333 \n  | 33__  33  | 33_____/   /33__  33\n  | 33  \\ 33  | 33        | 33  \\__/\n  | 3333333   | 33333     | 33      \n  | 33__  33  | 33__/     | 33      \n  | 33  \\ 33  | 33        | 33    33\n  | 3333333/  | 33333333  |  333333/\n  |_______/   |________/   \\______/ \n\n # http://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {ECDSA} from \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\n\n/**\n * @title EIP712 Base Contract for Typed Structured Data Hashing and Signing\n * @dev Implements EIP-712 standard providing a secure method for generating off-chain signatures \n *      that can be verified on-chain. Utilizes OpenZeppelin's ECDSA library for cryptographic operations, \n *      ensuring robust and secure handling of digital signatures.\n * @author https://42i.co\n */\ncontract EIP712 {\n\n  /**\n   * @dev Indicates that the signature was invalid.\n   * @param signature The used signature.\n   */\n  error EIP712InvalidSignature(bytes signature);\n\n  /**\n   * @dev Indicates that the signing key was not set.\n   */\n  error EIP712BECSigningKeyNotSet();\n\n  /// @dev Using Elliptic Curve Digital Signature Algorithm (ECDSA)\n  using ECDSA for bytes32;\n\n  /// @dev The key used to sign allowlist signatures.\n  address allowlistSigningKey = address(0);\n\n  /// @dev EIP-712 Domain Separator, providing protection against replay attacks across different contracts and networks.\n  /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#definition-of-domainseparator\n  bytes32 public immutable EIP712_DOMAIN_SEPARATOR;\n\n  /**\n   * @dev Initializes the contract by setting up the DOMAIN_SEPARATOR to include the contract's details \n   *      and the current chain ID, ensuring signatures are valid for specific interactions on the intended network.\n   */\n  constructor() {\n    // This should match whats in the client side allowlist signing code\n    EIP712_DOMAIN_SEPARATOR = keccak256(\n      abi.encode(\n        keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n        keccak256(bytes(\"BEC\")),\n        keccak256(bytes(\"3\")),\n        block.chainid,\n        address(this)\n      )\n    );\n  }\n\n  /**\n   * @notice Sets a new signing key for the allowlist, updating the key used for signature validation.\n   * @dev Internal function to update the allowlist signing key, ensuring only authorized signatures are considered valid.\n   * @param _signingKey The new signing key address to be used for validating signatures.\n   */\n  function _setAllowlistSigningAddress(address _signingKey) internal {\n    allowlistSigningKey = _signingKey;\n  }\n}"
      },
      "contracts/eip712/EIP712Allowlist.sol": {
        "content": "// contracts/eip712/EIP712Allowlist.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n   /3333333    /33333333    /333333 \n  | 33__  33  | 33_____/   /33__  33\n  | 33  \\ 33  | 33        | 33  \\__/\n  | 3333333   | 33333     | 33      \n  | 33__  33  | 33__/     | 33      \n  | 33  \\ 33  | 33        | 33    33\n  | 3333333/  | 33333333  |  333333/\n  |_______/   |________/   \\______/ \n\n # http://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {EIP712} from \"./EIP712.sol\";\nimport {ECDSA} from \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\n\n/**\n * @title EIP712 Allowlist Implementation\n * @dev Extends the EIP712 base contract to implement an allowlist mechanism using EIP-712 typed structured data signing.\n * @author https://42i.co\n */\ncontract EIP712Allowlist is EIP712 {\n\n  /// @dev Using Elliptic Curve Digital Signature Algorithm (ECDSA)\n  using ECDSA for bytes32;\n\n  /// @dev The typehash for the data type specified in the structured data\n  /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-typehash\n  bytes32 public constant HUNT_TYPEHASH = keccak256(\"Hunt(address wallet)\");\n\n  /**\n   * @dev Modifier to require a valid EIP-712 signature for allowlist operations. \n   *      It reconstructs the signed message's digest using the sender's address and the predefined HUNT_TYPEHASH, \n   *      then verifies the signature against the stored allowlist signing key.\n   * @param signature The EIP-712 signature provided by the sender, to be verified against the allowlist signing key.\n   */\n  modifier requiresAllowlist(bytes calldata signature) {\n    if (allowlistSigningKey == address(0)) revert EIP712BECSigningKeyNotSet();\n\n    bytes32 digest = keccak256(\n      abi.encodePacked(\"\\x19\\x01\", EIP712_DOMAIN_SEPARATOR, keccak256(abi.encode(HUNT_TYPEHASH, msg.sender)))\n    );\n\n    address recoveredAddress = digest.recover(signature);\n    if (recoveredAddress != allowlistSigningKey) revert EIP712InvalidSignature(signature);\n    _;\n  }\n}\n"
      },
      "contracts/erc404/ERC404B.sol": {
        "content": "// contracts/erc404/ERC404B.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n    /3333333     /33333333     /333333    \n   | 33__  33   | 33_____/    /33__  33   \n   | 33  \\ 33   | 33         | 33  \\__/   \n   | 3333333    | 33333      | 33         \n   | 33__  33   | 33__/      | 33         \n   | 33  \\ 33   | 33         | 33    33   \n   | 3333333/   | 33333333   |  333333/   \n   |_______/    |________/    \\______/    \n\n # https://blackeyedcreatures.com\n\n */\npragma solidity ^0.8.25;\n\nimport {IERC404B} from \"./IERC404B.sol\";\nimport {IERC404BErrors} from \"./IERC404BErrors.sol\";\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IERC721} from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\nimport {IERC721Receiver} from \"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol\";\nimport {IERC721Metadata} from \"@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol\";\nimport {IERC20Errors, IERC721Errors} from \"@openzeppelin/contracts/interfaces/draft-IERC6093.sol\";\nimport {DoubleEndedQueue} from \"./lib/DoubleEndedQueue.sol\";\nimport {BitMaps} from \"solidity-bits/contracts/BitMaps.sol\";\nimport {Strings} from \"@openzeppelin/contracts/utils/Strings.sol\";\n\n/**\n * @title Stash Contract\n * @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.\n */\ncontract Stash {}\n\n\n/**\n * @title ERC404B Contract\n * @dev Implements the IERC404 interface to provide a hybrid token mechanism supporting both ERC-20 and ERC-721 functionalities.\n * 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.\n * It also enables the actual burning of tokens, sending them irreversibly to the zero address.\n * Features include batch minting for ERC-721 tokens to optimize minting operations, gas savings optimizations, and support for EIP-2612 permit-based transactions.\n * @author https://42i.co\n */\ncontract ERC404B is IERC404B, IERC20Errors, IERC721Errors, IERC404BErrors {\n  using Strings for uint256;\n  using BitMaps for BitMaps.BitMap;\n  using DoubleEndedQueue for DoubleEndedQueue.Uint256Deque; // DoubleEndedQueue.Uint32Deque would be great\n\n  /// @dev Token Name.\n  string private _name;\n\n  /// @dev Token Symbol.\n  string private _symbol;\n\n  /// @dev Token decimal digits.\n  uint8 private immutable _DECIMALS;\n\n  /// @dev The number of ERC20 tokens required for one ERC721 token.\n  uint256 private immutable _UNIT;\n\n  /// @dev The number of tokens held by each address.\n  mapping(address holder => uint256 balance) private _balances;\n\n  /// @dev Identifier for the next token to mint.\n  uint256 internal _nextTokenId = _startTokenId();\n\n  /// @dev ERC721 token approvals.\n  mapping(uint256 tokenId => address approvedAddress) private _tokenApprovals;\n\n  /// @dev ERC721 operator approvals.\n  mapping(address holder => mapping(address operator => bool approval)) private _operatorApprovals;\n\n  /// @dev ERC20 token allowances.\n  mapping(address holder => mapping(address operator => uint256 allowance)) private _allowances;  \n\n  /// @dev Exempt addresses from ERC-721 transfers (e.g., pairs, routers) for gas savings.\n  mapping(address holder => bool exempt) private _erc721TransferExempt;\n\n  /// @dev Bitmask to extract lower 160 bits from a uint256.\n  uint256 private constant _BITMASK_LOWER160BITS = (1 << 160) - 1;\n\n  /// @dev Bitmask to extract upper 96 bits from a uint256.\n  uint256 private constant _BITMASK_UPPER96BITS = ((1 << 96) - 1) << 160;\n\n  /// @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).\n  mapping(address holder => uint256[] batchArray) private _owned;\n\n  /// @dev Mapping storing in each position the owner address (_BITMASK_LOWER160BITS) and index of this batch in _owned (_BITMASK_UPPER96BITS).\n  mapping(uint256 tokenId => uint256 addressAndPosition) private _ownedData;\n\n  /// @dev Bitmap storing the head of the batches, indicating where the _ownedData is located.\n  BitMaps.BitMap private _batchHead;\n\n  /// @dev Bitmap representing burned tokens.\n  BitMaps.BitMap private _burnedTokens;\n\n  /// @dev Amount of burned tokens.\n  uint256 private _burnedCount = 0;\n\n  /// @dev Queue of ERC-721 tokens in the stash.\n  DoubleEndedQueue.Uint256Deque private _stashQueue;\n\n  /// @dev Transfer(address,address,uint256) hash signature.\n  bytes32 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;\n\n  /// @dev Approval(address,address,uint256) hash signature.\n  bytes32 private constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;\n\n  /// @dev ApprovalForAll(address,address,bool) hash signature.\n  bytes32 private constant _APPROVALFORALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;\n\n  /// @dev Stash address for this token.\n  address private immutable _STASH_ADDRESS;\n\n  /// @dev EIP-2612 nonces.\n  mapping(address => uint256) public nonces;\n\n  /// @dev Initial chain id for EIP-2612 support.\n  uint256 internal immutable _INITIAL_CHAIN_ID;\n\n  /// @dev Initial domain separator for EIP-2612 support.\n  bytes32 internal immutable _INITIAL_DOMAIN_SEPARATOR;\n\n\n  /**\n   * @dev Initializes the contract with token details and necessary parameters.\n   * \n   * @param name_ The name of the token.\n   * @param symbol_ The symbol of the token.\n   * @param unit_ The equivalence between 1 ERC721 token and ERC20 needed for that token.\n   */\n  constructor(string memory name_, string memory symbol_, uint256 unit_) {\n    _name = name_;\n    _symbol = symbol_;\n\n    _DECIMALS = 18;\n    _UNIT = unit_ * 10 ** _DECIMALS;\n    _STASH_ADDRESS = address(new Stash());\n\n    // EIP-2612 initialization\n    _INITIAL_CHAIN_ID = block.chainid;\n    _INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator();\n  }\n\n  /**\n   * @dev Returns the starting token ID.\n   * \n   * @return The starting token ID, which is set to 1 by default.\n   * To change the starting token ID, please override this function.\n   */\n  function _startTokenId() internal pure returns (uint256) {\n    return 1;\n  }\n\n  /**\n   * @dev Returns the total number of tokens minted in the contract.\n   * \n   * @return The total number of tokens minted.\n   */\n  function _totalMinted() internal view virtual returns (uint256) {\n    return _nextTokenId - _startTokenId();\n  }\n\n  /**\n   * @dev See {IERC165-supportsInterface}.\n   */\n  function supportsInterface(bytes4 interfaceId_) public view virtual returns (bool) {\n    return interfaceId_ == type(IERC404B).interfaceId ||\n           interfaceId_ == type(IERC165).interfaceId ||\n           interfaceId_ == type(IERC20).interfaceId ||\n           interfaceId_ == type(IERC721).interfaceId ||\n           interfaceId_ == type(IERC721Receiver).interfaceId ||\n           interfaceId_ == type(IERC721Metadata).interfaceId;\n  }\n\n  /// IERC20 + ERC721 Metadata Methods ///\n\n  /**\n   * @dev See {IERC404-name}.\n   */\n  function name() public view virtual override returns (string memory) {\n    return _name;\n  }\n\n  /**\n   * @dev See {IERC404-symbol}.\n   */\n  function symbol() public view virtual override returns (string memory) {\n    return _symbol;\n  }\n\n  /**\n   * @dev See {IERC404-decimals}.\n   */\n  function decimals() public view virtual override returns (uint8) {\n    return _DECIMALS;\n  }\n\n  /**\n   * @dev See {IERC404-unit}.\n   */\n  function unit() public view virtual returns (uint256) {\n    return _UNIT;\n  }\n\n  /**\n   * @dev See {IERC404-tokenURI}.\n   */\n  function tokenURI(uint256 tokenId_) public view virtual override returns (string memory) {\n    if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_);\n    string memory baseURI = _baseURI();\n    return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId_.toString())) : \"\";\n  }\n\n  /**\n   * @dev Base URI for computing the {tokenURI}. If set, the resulting URI for each\n   * token will be the concatenation of the `baseURI` and the `tokenId`. \n   * \n   * It is empty by default and can be overridden in child contracts.\n   * @return The base URI string.\n   */\n  function _baseURI() internal view virtual returns (string memory) {\n    return \"\";\n  }\n\n  /**\n   * @dev Checks whether the specified `tokenId` exists in the contract.\n   * Tokens start existing when they are minted using the {_mint} function. Burned tokens are not considered to exist.\n   * \n   * @param tokenId_ The ID of the token to check.\n   * @return A boolean indicating whether the token exists.\n   */\n  function _exists(uint256 tokenId_) internal view virtual returns (bool) {\n    if (_burnedTokens.get(tokenId_)) {\n      return false;\n    }\n    return tokenId_ < _nextTokenId && _startTokenId() <= tokenId_;\n  }\n\n  /**\n   * @dev See {IERC404-exists}.\n   */\n  function exists(uint256 tokenId_) external view virtual returns (bool) {\n    return _exists(tokenId_);\n  }\n\n  /// ERC721 Methods ///\n\n  /**\n   * @dev See {IERC404-ownerOf}.\n   */\n  function ownerOf(uint256 tokenId_) public view virtual override returns (address owner) {\n    if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_);\n    uint256 data = _ownedData[_batchHead.scanForward(tokenId_)];\n    assembly {\n      owner := and(data, _BITMASK_LOWER160BITS)\n    }\n    if (owner == address(0)) {\n      owner = _STASH_ADDRESS;\n    }\n  }\n\n  /**\n   * @dev See {IERC404-safeTransferFrom}.\n   */\n  function safeTransferFrom(address from_, address to_, uint256 tokenId_) public virtual override {\n    safeTransferFrom(from_, to_, tokenId_, \"\");\n  }\n\n  /**\n   * @dev See {IERC404-safeTransferFrom}.\n   */\n  function safeTransferFrom(address from_, address to_, uint256 tokenId_, bytes memory data_) public virtual override {\n    if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_);\n    if (!_isApprovedOrOwner(msg.sender, tokenId_)) revert ERC721InsufficientApproval(msg.sender, tokenId_);\n    _safeTransferERC721(from_, to_, tokenId_, data_);\n  }\n\n  /**\n   * @dev Safely transfers `tokenId_` token from `from_` to `to_`, ensuring the recipient contract\n   * implements the ERC721Receiver interface to prevent tokens from being forever locked.\n   *\n   * `data_` is additional data without a specified format, included in the call to `to_`.\n   *\n   * This internal function is equivalent to {safeTransferFrom}, and can be used to implement alternative\n   * token transfer mechanisms, such as signature-based ones.\n   *\n   * Requirements:\n   * - `to_` cannot be the zero nor stash address.\n   * - `tokenId_` must exist and be owned by `from_`.\n   * - If `to_` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}.\n   *\n   * Emits a {Transfer} event.\n   *\n   * @param from_ The address sending the token.\n   * @param to_ The address receiving the token.\n   * @param tokenId_ The ID of the token being transferred.\n   * @param data_ Additional data sent during the token transfer.\n   */\n  function _safeTransferERC721(address from_, address to_, uint256 tokenId_, bytes memory data_) internal virtual {\n    if (!_checkOnERC721Received(from_, to_, tokenId_, 1, data_))\n      revert ERC721ReceiverNotImplemented(to_, tokenId_, 1, data_);\n    if (to_ == address(0) || to_ == _STASH_ADDRESS || to_ == from_) revert ERC721InvalidReceiver(to_);\n    _transferERC721(from_, to_, tokenId_);\n  }\n\n  /**\n   * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n   * The call is not executed if the target address is not a contract.\n   *\n   * @param from_ Address representing the previous owner of the given token ID.\n   * @param to_ Target address that will receive the tokens.\n   * @param startTokenId_ The first ID of the tokens to be transferred.\n   * @param quantity_ Amount of tokens to be transferred.\n   * @param data_ Optional data to send along with the call.\n   * @return r Boolean indicating whether the call returned the expected magic value.\n   */\n  function _checkOnERC721Received(address from_, address to_, uint256 startTokenId_, uint256 quantity_, bytes memory data_) private returns (bool r) {\n    if (to_.code.length > 0) {\n      r = true;\n      for (uint256 tokenId = startTokenId_; tokenId < startTokenId_ + quantity_; tokenId++) {\n        try IERC721Receiver(to_).onERC721Received(msg.sender, from_, tokenId, data_) returns (bytes4 retval) {\n          r = r && retval == IERC721Receiver.onERC721Received.selector;\n        } catch (bytes memory reason) {\n          if (reason.length == 0) {\n            revert ERC721ReceiverNotImplemented(to_, startTokenId_, quantity_, data_);\n          } else {\n            assembly {\n              revert(add(32, reason), mload(reason))\n            }\n          }\n        }\n      }\n      return r;\n    } else {\n      return true;\n    }\n  }\n\n  /**\n   * @dev Returns whether `spender` is allowed to manage `tokenId`.\n   *\n   * Requirements:\n   * - `tokenId` must exist.\n   *\n   * @param spender_ The address being checked for approval.\n   * @param tokenId_ The ID of the token being checked.\n   * @return A boolean indicating whether `spender` is allowed to manage `tokenId`.\n   */\n  function _isApprovedOrOwner(address spender_, uint256 tokenId_) internal view virtual returns (bool) {\n    address owner = ownerOf(tokenId_);\n    return (spender_ == owner || getApproved(tokenId_) == spender_ || isApprovedForAll(owner, spender_));\n  }\n\n  /**\n   * @dev Adds a batch of tokens to the `_owned` mapping for the given owner.\n   *\n   * @param batchInitialId_ The initial ID of the batch of tokens.\n   * @param owner_ The address of the owner.\n   * @param quantity_ The quantity of tokens in the batch.\n   */\n  function _pushOwned(uint256 batchInitialId_, address owner_, uint256 quantity_) internal virtual {\n    uint256 data;\n    assembly {\n      data := add(and(batchInitialId_, _BITMASK_LOWER160BITS), and(shl(160, quantity_), _BITMASK_UPPER96BITS))\n    }\n    _owned[owner_].push(data);\n  }\n\n  /**\n   * @dev Sets the data for a specific batch of tokens in the `_owned` mapping for the given owner and index.\n   *\n   * @param batchInitialId_ The initial ID of the batch of tokens.\n   * @param owner_ The address of the owner.\n   * @param index_ The index of the batch in the `_owned` array.\n   * @param quantity_ The quantity of tokens in the batch.\n   */\n  function _setOwned(uint256 batchInitialId_, address owner_, uint256 index_, uint256 quantity_) internal virtual {\n    uint256 data;\n    assembly {\n      data := add(and(batchInitialId_, _BITMASK_LOWER160BITS), and(shl(160, quantity_), _BITMASK_UPPER96BITS))\n    }\n    _owned[owner_][index_] = data;\n  }\n\n  /**\n   * @dev Retrieves the initial ID and quantity of tokens in a batch owned by a specific address.\n   *\n   * @param owner_ The address of the token owner.\n   * @param index_ The index of the batch in the owner's collection.\n   * @return batchInitialId The initial ID of the tokens in the batch.\n   * @return batchQuantity The quantity of tokens in the batch.\n   */\n  function _getOwnedBatchInitialIdAndQuantity(address owner_, uint256 index_) internal view virtual returns (uint256 batchInitialId, uint256 batchQuantity) {\n    uint256 data = _owned[owner_][index_];\n    assembly {\n      batchInitialId := and(data, _BITMASK_LOWER160BITS)\n      batchQuantity := shr(160, data)\n    }\n  }\n\n  /**\n   * @dev Sets the data for a batch of owned tokens at a specific index in the _ownedData mapping.\n   * This function is used to update the data associated with a batch of tokens owned by an address.\n   * It ensures that the index does not exceed the upper limit defined by _BITMASK_UPPER96BITS >> 160.\n   *\n   * @param batchInitialId_ The initial ID of the tokens in the batch.\n   * @param ownerOf_ The address of the owner of the tokens in the batch.\n   * @param index_ The index of the batch within the _owned[ownerOf_] mapping.\n   */\n  function _setOwnedData(uint256 batchInitialId_, address ownerOf_, uint256 index_) internal virtual {\n    if (index_ > _BITMASK_UPPER96BITS >> 160) {\n      revert ERC404OwnedIndexOverflow(index_);\n    }\n    uint256 data;\n    assembly {\n      data := add(and(ownerOf_, _BITMASK_LOWER160BITS), and(shl(160, index_), _BITMASK_UPPER96BITS))\n    }\n    _ownedData[batchInitialId_] = data;\n  }\n\n  /**\n   * @dev Retrieves the owner, index within the owner's batch, and token ID at the head of the batch for the given token ID.\n   *\n   * Requirements:\n   * - The token ID must exist.\n   *\n   * @param tokenId_ The ID of the token for which to retrieve information.\n   * @return owner The address of the token's owner.\n   * @return index The index of the token within the owner's batch.\n   * @return tokenIdBatchHead The token ID at the head of the batch.\n   */\n  function _getOwnerOwnedIndexAndBatchHeadId(uint256 tokenId_) internal view returns (address owner, uint256 index, uint256 tokenIdBatchHead) {\n    tokenIdBatchHead = _batchHead.scanForward(tokenId_);\n    uint256 data = _ownedData[tokenIdBatchHead];\n    assembly {\n      index := shr(160, data)\n      owner := and(data, _BITMASK_LOWER160BITS)\n    }\n  }\n\n  /**\n   * @dev Transfers an ERC721 token from one address to another.\n   *\n   * Requirements:\n   * - `from_` must be the owner of the token.\n   * - Token ID must exist and be owned by `from_`.\n   * - If `to_` is a smart contract, it must implement {IERC721Receiver-onERC721Received}.\n   * - If `to_` is exempt from ERC721 transfer, the token is moved to the stash.\n   *\n   * Emits an {IERC721-Transfer} event.\n   * Emits an {IERC20-Transfer} event.\n   *\n   * @param from_ The address transferring the token.\n   * @param to_ The address receiving the token.\n   * @param tokenId_ The ID of the token being transferred.\n   */\n  function _transferERC721(address from_, address to_, uint256 tokenId_) internal virtual {\n    (address owner, uint256 index, uint256 tokenIdBatchHead) = _getOwnerOwnedIndexAndBatchHeadId(tokenId_);\n    // _beforeTokenTransfers(from_, to_, tokenId_, 1);\n\n    delete _tokenApprovals[tokenId_]; // On transfer, any previous approval is reset.\n\n    uint256 batchQuantity;\n    uint256 data = _owned[owner][index];\n    assembly {\n      batchQuantity := shr(160, data)\n    }\n    _removeTokenFrom(from_, index, tokenId_, tokenIdBatchHead, batchQuantity);\n\n    if (_erc721TransferExempt[to_]) {\n      // Is exempt: move to stash\n      _batchHead.set(tokenId_);\n      _stashQueue.pushFront(tokenId_);\n\n      address mutableStashAddress = _STASH_ADDRESS;\n      assembly {\n        // Emit ERC721.Transfer(from_, _STASH_ADDRESS, tokenId_)\n        log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(mutableStashAddress, _BITMASK_LOWER160BITS), tokenId_)\n      }\n    }\n    else {\n      // Add ownership to \"to_\"\n      assembly {\n        data := add(and(tokenId_, _BITMASK_LOWER160BITS), and(shl(160, 1), _BITMASK_UPPER96BITS))\n      }\n      _owned[to_].push(data);\n      uint256 index_ = _owned[to_].length - 1;\n      assembly {\n        data := add(and(to_, _BITMASK_LOWER160BITS), and(shl(160, index_), _BITMASK_UPPER96BITS))\n      }\n      _ownedData[tokenId_] = data;\n\n      assembly {\n        // emit IERC721.Transfer(from_, to_, tokenId_);\n        log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS), tokenId_)\n      }\n    }\n\n    unchecked {\n      // `_balances[from]` cannot overflow for the same reason as described in `_burn`:\n      // `from`'s balance is the number of token held, which is at least one before the current\n      // transfer.\n      // `_balances[to]` could overflow in the conditions described in `_mint`. That would require\n      // all 2**256 token ids to be minted, which in practice is impossible.\n      _balances[from_] -= _UNIT;\n      _balances[to_] += _UNIT;\n    }\n\n    data = _UNIT;\n    assembly {\n      // emit IERC20.Transfer(from_, to_, _UNIT);\n      mstore(0x00, data)\n      log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS))\n    }\n    // _afterTokenTransfers(from_, to_, tokenId_, 1);\n  }\n\n  /**\n   * @dev Removes a token from an address, adjusting the internal data structures accordingly.\n   *\n   * Requirements:\n   * - `from_` must be the owner of the token.\n   *\n   * @param from_ The address from which the token is being removed.\n   * @param index_ The index of the token within the owner's batch.\n   * @param tokenId_ The ID of the token being removed.\n   * @param batchInitialId_ The initial ID of the batch.\n   * @param batchQuantity_ The quantity of tokens in the batch.\n   */\n  function _removeTokenFrom(address from_, uint256 index_, uint256 tokenId_, uint256 batchInitialId_, uint256 batchQuantity_) internal {\n    unchecked {\n      // If Is Batch Head == No tokens before in the batch.\n      if (batchInitialId_ == tokenId_) {\n        if (batchQuantity_ == 1) {\n          _removeSingleToken(from_, index_);\n        } else {\n          _removeBatchHeadToken(from_, index_, tokenId_, batchQuantity_);\n        }\n      } else {\n        // Is not batch head == There is tokens before for the\n        _removeNonHeadToken(from_, index_, tokenId_, batchInitialId_, batchQuantity_);\n      }\n    }\n  }\n\n  /**\n   * @dev Removes a single token from the owner's collection.\n   * \n   * This internal function is used during ERC721 token transfers to remove a single token from the owner's collection.\n   * It shifts the token data in the owner's collection to fill the gap left by the removed token, ensuring continuous indexing.\n   * If the removed token is not the last token in the collection, it updates the metadata and batch information accordingly.\n   *\n   * @param from_ The address of the owner from which the token is being removed.\n   * @param index_ The index of the token in the owner's collection to be removed.\n   */\n  function _removeSingleToken(address from_, uint256 index_) internal {\n    unchecked {\n      uint256[] storage ownedFrom = _owned[from_];\n      uint256 fromStackLastIndex = ownedFrom.length - 1;\n      if (fromStackLastIndex != index_) {\n        uint256 data = ownedFrom[fromStackLastIndex];\n        ownedFrom[index_] = data;\n        uint256 lastBatchInitialId;\n        assembly {\n          lastBatchInitialId := and(data, _BITMASK_LOWER160BITS)\n          data := add(and(from_, _BITMASK_LOWER160BITS), and(shl(160, index_), _BITMASK_UPPER96BITS))\n        }\n        _ownedData[lastBatchInitialId] = data;\n      }\n      ownedFrom.pop();\n    }\n  }\n\n  /**\n   * @dev Removes the batch head token from the owner's collection.\n   * \n   * This internal function is used during ERC721 token transfers to remove the batch head token from the owner's collection.\n   * It sets the subsequent token ID as the new batch head, updates the batch information, and shifts the remaining tokens accordingly.\n   *\n   * @param from_ The address of the owner from which the batch head token is being removed.\n   * @param index_ The index of the batch head token in the owner's collection to be removed.\n   * @param tokenId_ The ID of the batch head token being removed.\n   * @param batchQuantity_ The quantity of tokens in the batch (including the batch head).\n   */\n  function _removeBatchHeadToken(address from_, uint256 index_, uint256 tokenId_, uint256 batchQuantity_) internal {\n    unchecked {\n      uint256 subsequentTokenId = tokenId_ + 1;\n      _batchHead.set(subsequentTokenId);\n\n      uint256 data;\n      assembly {\n        data := add(and(from_, _BITMASK_LOWER160BITS), and(shl(160, index_), _BITMASK_UPPER96BITS))\n      }\n      _ownedData[subsequentTokenId] = data;\n\n      assembly {\n        data := add(\n          and(subsequentTokenId, _BITMASK_LOWER160BITS),\n          and(shl(160, sub(batchQuantity_, 1)), _BITMASK_UPPER96BITS)\n        )\n      }\n      _owned[from_][index_] = data;\n    }\n  }\n\n  /**\n   * @dev Removes a non-head token from the owner's collection within a batch.\n   * \n   * 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.\n   * It updates the batch information, shifts the remaining tokens accordingly, and creates a new batch if necessary.\n   *\n   * @param from_ The address of the owner from which the token is being removed.\n   * @param index_ The index of the token in the owner's collection to be removed.\n   * @param tokenId_ The ID of the token being removed.\n   * @param batchInitialId_ The ID of the first token in the batch.\n   * @param batchQuantity_ The quantity of tokens in the batch.\n   */\n  function _removeNonHeadToken(address from_, uint256 index_, uint256 tokenId_, uint256 batchInitialId_, uint256 batchQuantity_) internal {\n    unchecked {\n      _batchHead.set(tokenId_);\n      uint256 batchSizeAndIndex = tokenId_ - batchInitialId_;\n      uint256 data;\n      assembly {\n        data := add(and(batchInitialId_, _BITMASK_LOWER160BITS), and(shl(160, batchSizeAndIndex), _BITMASK_UPPER96BITS))\n      }\n      _owned[from_][index_] = data;\n\n      if (batchSizeAndIndex < batchQuantity_ - 1) {\n        // It means that the batch continues\n        uint256 subsequentTokenId = tokenId_ + 1;\n        _batchHead.set(subsequentTokenId);\n\n        batchSizeAndIndex = (batchQuantity_ - 1) - (tokenId_ - batchInitialId_);\n        assembly {\n          data := add(and(subsequentTokenId, _BITMASK_LOWER160BITS), and(shl(160, batchSizeAndIndex), _BITMASK_UPPER96BITS))\n        }\n        _owned[from_].push(data);\n\n        batchSizeAndIndex = _owned[from_].length - 1;\n        assembly {\n          data := add(and(from_, _BITMASK_LOWER160BITS), and(shl(160, batchSizeAndIndex), _BITMASK_UPPER96BITS))\n        }\n        _ownedData[subsequentTokenId] = data;\n      }\n    }\n  }\n\n  /**\n   * @dev See {IERC404-getApproved}.\n   */\n  function getApproved(uint256 tokenId_) public view virtual override returns (address) {\n    if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_);\n    return _tokenApprovals[tokenId_];\n  }\n\n  /**\n   * @dev See {IERC404-setApprovalForAll}.\n   */\n  function setApprovalForAll(address operator_, bool approved_) public virtual override {\n    address owner = msg.sender;\n    if(operator_ == owner) revert ERC721InvalidOperator(operator_);\n    _operatorApprovals[owner][operator_] = approved_;\n    assembly {\n      // emit IERC721.ApprovalForAll(owner, operator, approved);\n      mstore(0x00, approved_)\n      log3(0x00, 0x20, _APPROVALFORALL_EVENT_SIGNATURE, and(owner, _BITMASK_LOWER160BITS), and(operator_, _BITMASK_LOWER160BITS))\n    }\n  }\n\n  /**\n   * @dev See {IERC404-isApprovedForAll}.\n   */\n  function isApprovedForAll(address owner_, address operator_) public view virtual override returns (bool) {\n    return _operatorApprovals[owner_][operator_];\n  }\n\n  /**\n   * @dev Safely mints a specified quantity of ERC721 tokens and assigns them to the specified address.\n   *\n   * This internal function is equivalent to calling `_safeMint(to, quantity, \"\")`, providing an empty data parameter.\n   * It ensures that the minted tokens are safely transferred to the recipient by calling the ERC721 safe transfer function.\n   *\n   * @param to_ The address to which the minted tokens will be assigned.\n   * @param quantity_ The number of tokens to mint.\n   */\n  function _safeMint(address to_, uint256 quantity_) internal virtual {\n    _safeMint(to_, quantity_, \"\");\n  }\n\n  /**\n   * @dev Safely mints a specified quantity of ERC721 tokens and assigns them to the specified address.\n   *\n   * This internal function is equivalent to calling `_mint(to_, quantity_)` followed by a check to ensure that the recipient contract implements ERC721Receiver.\n   * It requires the recipient contract to implement the ERC721Receiver interface's `onERC721Received` function to receive the tokens safely.\n   *\n   * @param to_ The address to which the minted tokens will be assigned.\n   * @param quantity_ The number of tokens to mint.\n   * @param data_ Additional data sent along with the token transfer, if any.\n   */\n  function _safeMint(address to_, uint256 quantity_, bytes memory data_) internal virtual {\n    if (!_checkOnERC721Received(address(0), to_, _nextTokenId, quantity_, data_)) {\n      revert ERC721ReceiverNotImplemented(to_, _nextTokenId, quantity_, data_);\n    }\n    _mint(to_, quantity_);\n  }\n\n\n  /**\n   * @dev Mints a specified quantity of ERC721 tokens and assigns them to the specified address.\n   *\n   * This internal function performs the minting of ERC721 tokens and updates the balances accordingly. \n   * It also emits one ERC20 Transfer event and a ERC721 Transfer event for each minted token.\n   * If the recipient address is exempt from ERC721 transfer fees, the method sets the batch head accordingly; \n   * otherwise, it adds the minted tokens to the recipient's ownership.\n   *\n   * Requirements:\n   * - `quantity_` must be greater than 0.\n   * - `to_` address must not be the zero nor stash address.\n   *\n   * Emits an IERC20 {Transfer} event.\n   * Emits an IERC721 {Transfer} event for each minted token.\n   *\n   * @param to_ The address to which the minted tokens will be assigned.\n   * @param quantity_ The number of tokens to mint.\n   */\n  function _mint(address to_, uint256 quantity_) internal virtual {\n    if (quantity_ == 0) revert ERC721InvalidMintQuantity();\n    if (to_ == address(0) || to_ == _STASH_ADDRESS) revert ERC20InvalidReceiver(to_);\n    // _beforeTokenTransfers(address(0), to_, _nextTokenId, quantity_);\n\n    uint256 value;\n    uint256 toMasked;\n    uint256 end;\n    uint256 batchTokenId = _nextTokenId;\n    unchecked {\n      value = quantity_ * _UNIT;\n      _balances[to_] += value; // May overflow in big quantities if total balance not controlled. \n      end = batchTokenId + quantity_;\n    }\n\n    assembly {\n      // emit IERC20.Transfer(0x00, to_, _UNIT);\n      toMasked := and(to_, _BITMASK_LOWER160BITS)\n      mstore(0x00, value)\n      log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, 0x00, toMasked)\n    }\n\n    if (_erc721TransferExempt[to_]) {\n      _batchHead.setBatch(batchTokenId, quantity_);\n    } else {\n      _batchHead.set(batchTokenId);\n      _pushOwned(batchTokenId, to_, quantity_);\n      _setOwnedData(batchTokenId, to_, _owned[to_].length - 1);\n\n      // Use assembly to loop and emit the `Transfer` event for gas savings.\n      // The duplicated `log4` removes an extra check and reduces stack juggling.\n      assembly {\n        // emit IERC721.Transfer(0x00, to_, batchTokenId);\n        log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, 0x00, toMasked, batchTokenId)\n\n        // The `iszero(eq(,))` check ensures that large values of `quantity`\n        // that overflows uint256 will make the loop run out of gas.\n        // The compiler will optimize the `iszero` away for performance.\n        for {\n          let tokenId := add(batchTokenId, 1)\n        } iszero(eq(tokenId, end)) {\n          tokenId := add(tokenId, 1)\n        } {\n          // emit IERC721.Transfer(0x00, to_, tokenId);\n          log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, 0x00, toMasked, tokenId)\n        }\n      }\n    }\n\n    // _afterTokenTransfers(address(0), to_, _nextTokenId, quantity_);\n    unchecked {\n      _nextTokenId += quantity_;\n    }\n  }\n\n  /// ERC20 Methods ///\n\n  /**\n   * @dev See {IERC404-totalSupply}.\n   */\n  function totalSupply() public view virtual override returns (uint256) {\n    return _totalTokens() * _UNIT;\n  }\n\n  /**\n   * @dev Calculates the total number of tokens that have been minted and not burned.\n   *\n   * This internal function returns the difference between the total minted tokens and the burned tokens, representing the total number of existing tokens in circulation.\n   *\n   * @return The total number of existing tokens in circulation.\n   */\n  function _totalTokens() internal view virtual returns (uint256) {\n    return _totalMinted() - _burned();\n  }\n\n  /**\n   * @dev Retrieves the total number of tokens that have been burned.\n   *\n   * This internal function returns the count of tokens that have been burned within the contract.\n   *\n   * @return The total number of tokens that have been burned.\n   */\n  function _burned() internal view virtual returns (uint256) {\n    return _burnedCount;\n  }\n\n  /**\n   * @dev See {IERC404-transfer}.\n   */\n  function transfer(address to_, uint256 valueOrId_) public virtual override returns (bool) {\n    address owner = msg.sender;\n    transferFrom(owner, to_, valueOrId_); \n    return true;\n  }\n\n  /**\n   * @dev See {IERC404-allowance}.\n   */\n  function allowance(address owner_, address spender_) public view virtual override returns (uint256) {\n    return _allowances[owner_][spender_];\n  }\n\n  /// ERC404 Combined (Methods with similar interfaces and behavior in ERC20 & ERC721) ///\n\n  /**\n   * @dev See {IERC404-balanceOf}.\n   */\n  function balanceOf(address account_) public view virtual override returns (uint256) {\n    return _balances[account_];\n  }\n\n  /**\n   * @dev See {IERC404-transferFrom}.\n   */\n  function transferFrom(address from_, address to_, uint256 valueOrId_) public virtual returns (bool) {\n    if (_exists(valueOrId_)) {\n      safeTransferFrom(from_, to_, valueOrId_, \"\");\n    } else {\n      return _transferFromERC20(from_, to_, valueOrId_);\n    }\n    return true;\n  }\n\n  /**\n   * @dev Transfers ERC20 tokens from one address to another, handling ERC721 exemptions internally.\n   *\n   * This function is used to transfer ERC20 tokens directly between addresses, handling exemptions for ERC721 transfers\n   * internally. It checks for valid recipients, allowances, and handles ERC721 exemptions if the recipient address is\n   * exempt from ERC721 transfers.\n   *\n   * Requirements:\n   * - `to_` cannot be the zero address or the stash address.\n   *\n   * @param from_ The address sending the ERC20 tokens.\n   * @param to_ The address receiving the ERC20 tokens.\n   * @param value_ The amount of ERC20 tokens to transfer.\n   * @return A boolean indicating whether the transfer was successful.\n   */\n  function _transferFromERC20(address from_, address to_, uint256 value_) public virtual returns (bool) {\n    if (to_ == address(0) || to_ == _STASH_ADDRESS || to_ == from_) revert ERC20InvalidReceiver(to_);\n\n    if (from_ != msg.sender) {\n      uint256 allowed = _allowances[from_][msg.sender];\n\n      // Check that the operator has sufficient allowance.\n      if (allowed != type(uint256).max) {\n        if(value_ > allowed) revert ERC20InsufficientAllowance(from_, allowed, value_);\n        _allowances[from_][msg.sender] = allowed - value_;\n      }\n    }\n\n    // Transferring ERC-20s directly requires the _transferERC20WithERC721 function.\n    return _transferERC20WithERC721(from_, to_, value_);\n  }\n\n  /**\n   * @dev This function handles the transfer of ERC-20 tokens and optionally adjusts the ERC-721 token balances based on the transfer exemptions.\n   * \n   * Requirements:\n   * - The sender (`from_`) must have a balance of at least `value_`.\n   * \n   * Emits:\n   * - {IERC20.Transfer} event for ERC-20 and possibly a {IERC721.Transfer} for each ERC-721 Token.\n   * \n   * @param from_ Address sending the tokens.\n   * @param to_ Address receiving the tokens.\n   * @param value_ Amount of ERC-20 tokens to transfer.\n   * @return bool True if the transfer is successful.\n   */\n  function _transferERC20WithERC721(address from_, address to_, uint256 value_) internal virtual returns (bool) {\n    uint256 erc20BalanceOfSenderBefore = _balances[from_];\n    uint256 erc20BalanceOfReceiverBefore = _balances[to_];\n\n    if (erc20BalanceOfSenderBefore < value_) revert ERC20InsufficientBalance(from_, erc20BalanceOfSenderBefore, value_);\n\n    unchecked {\n      _balances[from_] -= value_;\n      _balances[to_] += value_;\n    }\n\n    assembly {\n      // emit IERC20.Transfer(from_, to_, value_);\n      mstore(0x00, value_)\n      log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS))\n    }\n\n    // Skip ERC-721 transfer to exempt addresses to save gas\n    bool isFromERC721TransferExempt = _erc721TransferExempt[from_];\n    bool isToERC721TransferExempt = _erc721TransferExempt[to_];\n    if (isFromERC721TransferExempt && isToERC721TransferExempt) {\n      // Case 1) Both sender and recipient are ERC-721 transfer exempt. No ERC-721s need to be transferred.\n    } else if (isFromERC721TransferExempt) {\n      // Case 2) The sender is ERC-721 transfer exempt, but the recipient is not. \n      unchecked {\n        uint256 tokensToRetrieveFromStash = (_balances[to_] / _UNIT) - (erc20BalanceOfReceiverBefore / _UNIT);\n        _retrieveFromStash(to_, tokensToRetrieveFromStash);\n      }\n    } else if (isToERC721TransferExempt) {\n      // Case 3) The sender is not ERC-721 transfer exempt, but the recipient is. \n      unchecked {\n        uint256 tokensToStash = (erc20BalanceOfSenderBefore / _UNIT) - (_balances[from_] / _UNIT);\n        _stash(from_, tokensToStash);\n      }\n    } else {\n      // Case 4) Neither the sender nor the recipient are ERC-721 transfer exempt.\n      _batchTransferERC721WithBalanceAdjustment(from_, to_, erc20BalanceOfSenderBefore, erc20BalanceOfReceiverBefore, value_);\n    }\n    return true;\n  }\n\n  /**\n   * @dev Internal function to batch transfer ERC721 tokens with balance adjustment.\n   * \n   * Emits a {IERC721.Transfer} event for each token transferred, including the initial token ID and all subsequent IDs in the batch.\n   *\n   * @param from_ The address from which to transfer tokens.\n   * @param to_ The address to which to transfer tokens.\n   * @param fromPreviousBalance_ The previous balance of tokens for the sender.\n   * @param toPreviousBalance_ The previous balance of tokens for the recipient.\n   * @param transferedValue_ The value of tokens to be transferred.\n   */\n  function _batchTransferERC721WithBalanceAdjustment(address from_, address to_, uint256 fromPreviousBalance_, uint256 toPreviousBalance_, uint256 transferedValue_) internal {\n    uint256 tokenId;\n    uint256 end;\n    uint256 nftsToTransfer = transferedValue_ / _UNIT;\n    for (uint256 i = 0; i < nftsToTransfer; ) {\n      // Transfers the whole batch\n      uint256 lastOwnedIndex = _owned[from_].length - 1;\n      (uint256 batchInitialId_, uint256 batchQuantity_) = _getOwnedBatchInitialIdAndQuantity(from_, lastOwnedIndex);\n\n      if (batchQuantity_ + i <= nftsToTransfer) {\n        // Transfer whole batch\n        _owned[to_].push(_owned[from_][lastOwnedIndex]);\n        _owned[from_].pop();\n\n        uint256 lastToIndex = _owned[to_].length - 1;\n        _setOwnedData(batchInitialId_, to_, lastToIndex);\n\n        unchecked {\n          tokenId = batchInitialId_;\n          end = batchInitialId_ + batchQuantity_;\n          i += batchQuantity_;\n        }\n      } else {\n        // Transfers part of the batch\n        unchecked {\n          uint256 tokensToTransfer = nftsToTransfer - i;\n          uint256 tokensInPreviousBatch = batchQuantity_ - tokensToTransfer;\n          _setOwned(batchInitialId_, from_, lastOwnedIndex, tokensInPreviousBatch);\n\n          uint256 newBatchInitialId = batchInitialId_ + tokensInPreviousBatch;\n          _batchHead.set(newBatchInitialId);\n          _pushOwned(newBatchInitialId, to_, tokensToTransfer);\n          _setOwnedData(newBatchInitialId, to_, _owned[to_].length - 1);\n\n          tokenId = newBatchInitialId;\n          end = newBatchInitialId + tokensToTransfer;\n          i = nftsToTransfer;\n        }\n      }\n      unchecked {\n        for (uint256 j = tokenId; j < end; ++j) {\n          delete _tokenApprovals[j]; // On transfer, any previous approval is reset.\n\n          assembly {\n            // emit IERC721.Transfer(from_, to_, emitInitialId);\n            log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS), j)\n          }\n        }\n      }\n    }\n\n    // If the transfer changes either the sender or the recipient's holdings from a fractional to a non-fractional\n    // amount (or vice versa), adjust ERC-721s.\n    unchecked {\n      // First check if the send causes the sender to lose a whole token that was represented by an ERC-721\n      // due to a fractional part being transferred.\n      if (fromPreviousBalance_ / _UNIT - _balances[from_] / _UNIT > nftsToTransfer) {\n        _stash(from_, 1);\n      }\n\n      // Then, check if the transfer causes the receiver to gain a whole new token which requires gaining\n      // an additional ERC-721.\n      if (_balances[to_] / _UNIT - toPreviousBalance_ / _UNIT > nftsToTransfer) {\n        _retrieveFromStash(to_);\n      }\n    }\n  }\n\n  /**\n   * @dev Internal virtual function to stash ERC721 tokens.\n   * \n   * Emits a {IERC721.Transfer} event for each token stashed.\n   *\n   * @param from_ The address from which to stash tokens.\n   * @param quantity_ The quantity of tokens to be stashed.\n   */\n  function _stash(address from_, uint256 quantity_) internal virtual {\n    unchecked {\n      uint256 batchInitialId_;\n      uint256 batchQuantity_;\n      uint256 data;\n      // Stash loop variables\n      uint256 begin;\n      uint256 end;\n\n      for (uint256 stashed = 0; stashed < quantity_; ) {\n        data = _owned[from_][_owned[from_].length - 1];\n        assembly {\n          batchInitialId_ := and(data, _BITMASK_LOWER160BITS)\n          batchQuantity_ := shr(160, data)\n        }\n        if (stashed + batchQuantity_ <= quantity_) {\n          // Transfer the whole batch\n          delete _ownedData[batchInitialId_];\n          _batchHead.setBatch(batchInitialId_, batchQuantity_); // Set batchead in a massive way to all tokens.\n          _owned[from_].pop(); // Remove batch from owned ids\n          stashed += batchQuantity_; // Increment the stashed items\n          begin = batchInitialId_; \n          end = begin + batchQuantity_;\n        } else {\n          // Only transfer the amount needed, maintain the batch\n          uint256 tokensToStash = quantity_ - stashed;\n          uint256 nonStashedBatchSize = batchQuantity_ - tokensToStash;\n          begin = batchInitialId_ + nonStashedBatchSize;\n          end = begin + tokensToStash;\n          _batchHead.setBatch(begin, tokensToStash); // Set batchead in a massive way to all tokens to be stashed\n          _setOwned(batchInitialId_, from_, _owned[from_].length - 1, nonStashedBatchSize); // Update the batch size\n          stashed = quantity_; // Update the stashed items\n        }\n        address mutableStashAddress = _STASH_ADDRESS;\n        for (uint256 i=begin; i<end; ++i) {\n          _stashQueue.pushFront(i);\n          delete _tokenApprovals[i]; // On stash of a token, any previous approval is reset.\n          assembly {\n            // emit IERC721.Transfer(from_, _STASH_ADDRESS, tokenId);\n            log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(mutableStashAddress, _BITMASK_LOWER160BITS), i)\n          }\n        }\n      }\n    }\n  }\n\n  /**\n   * @dev Internal virtual function to retrieve ERC721 tokens from the stash.\n   * \n   * Emits a {IERC721.Transfer} event for each token retrieved.\n   *\n   * @param to_ The address to which retrieved tokens will be transferred.\n   */\n  function _retrieveFromStash(address to_) internal virtual {\n    uint256 id = _stashQueue.popBack();\n    _pushOwned(id, to_, 1);\n    unchecked {\n      _setOwnedData(id, to_, _owned[to_].length - 1);\n    }\n\n    address mutableStashAddress = _STASH_ADDRESS;\n    assembly {\n      // emit IERC721.Transfer(_STASH_ADDRESS, to_, tokenId);\n      log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(mutableStashAddress, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS), id)\n    }\n  }\n\n  /**\n   * @dev Internal function to retrieve multiple ERC721 tokens from the stash and transfer them to a recipient.\n   * \n   * Emits a {IERC721.Transfer} event for each token retrieved, including the token ID transferred to the recipient.\n   * \n   * @param to_ The address to which retrieved tokens will be transferred.\n   * @param amount_ The number of tokens to retrieve from the stash.\n   */\n  function _retrieveFromStash(address to_, uint256 amount_) internal {\n    for (uint256 i = 0; i < amount_; ) {\n      _retrieveFromStash(to_);\n      unchecked {\n        ++i;\n      }\n    }\n  }\n\n  /**\n   * @dev See {IERC404-approve}.\n   */\n  function approve(address spender_, uint256 valueOrId_) public virtual returns (bool) {\n    if (_exists(valueOrId_)) {\n      _erc721Approve(spender_, valueOrId_);\n    } else {\n      return _erc20Approve(spender_, valueOrId_);\n    }\n    return true;\n  }\n\n  /**\n   * @dev Approves a specific address to transfer the specified ERC-721 token.\n   * \n   * Requirements:\n   * - The caller must be the owner of the ERC-721 token or have been approved by the owner.\n   * \n   * Emits:\n   * - {IERC721.Approval} event for ERC-721 Tokens.\n   * \n   * @param spender_ Address to be approved for the specified ERC-721 token.\n   * @param id_ ID of the ERC-721 token to be approved.\n   */\n  function _erc721Approve(address spender_, uint256 id_) public virtual {\n    address erc721Owner = ownerOf(id_);\n    if (msg.sender != erc721Owner && !isApprovedForAll(erc721Owner, msg.sender)) {\n      revert ERC721InvalidApprover(msg.sender);\n    }\n    _tokenApprovals[id_] = spender_;\n\n    assembly {\n      // emit IERC721.Approval(erc721Owner, spender_, id_);\n      log4(0x00, 0x00, _APPROVAL_EVENT_SIGNATURE, and(erc721Owner, _BITMASK_LOWER160BITS), and(spender_, _BITMASK_LOWER160BITS), id_)\n    }\n  }\n\n  /**\n   * @dev Approves a specific address to spend a specified amount of ERC-20 tokens on behalf of the caller.\n   * \n   * Requirements:\n   * - The spender address must not be the zero address.\n   * \n   * Emits:\n   * - {IERC20.Approval} event for ERC-20 Tokens.\n   * \n   * @param spender_ Address to be approved for spending the specified ERC-20 tokens.\n   * @param value_ Amount of ERC-20 tokens to be approved for spending.\n   * @return bool True if the approval is successful.\n   */\n  function _erc20Approve(address spender_, uint256 value_) public virtual returns (bool) {\n    address owner = msg.sender;\n    if (spender_ == address(0) || spender_ == _STASH_ADDRESS) {\n      revert ERC20InvalidSpender(spender_);\n    }\n    _allowances[owner][spender_] = value_;\n\n    assembly {\n      // emit IERC20.Approval(msg.sender, spender_, value_);\n      let ownerMasked := and(owner, _BITMASK_LOWER160BITS)\n      let approvedMasked := and(spender_, _BITMASK_LOWER160BITS)\n      mstore(0x00, value_)\n      log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, ownerMasked, approvedMasked)\n    }\n    return true;\n  }\n\n  /**\n   * @dev See {IERC20Permit-permit}. \n   */\n  function permit(address owner_, address spender_, uint256 value_, uint256 deadline_, uint8 v_, bytes32 r_, bytes32 s_) public virtual {\n    if (deadline_ < block.timestamp) {\n      revert EIP2612PermitDeadlineExpired(owner_, spender_, value_, deadline_, v_, r_, s_);\n    }\n\n    // permit cannot be used for ERC-721 token approvals, so ensure\n    // the value does not fall within the valid range of ERC-721 token ids.\n    if (_exists(value_)) {\n      revert ERC404InvalidTransferValue(value_);\n    }\n\n    if (spender_ == address(0) || spender_ == _STASH_ADDRESS) {\n      revert ERC20InvalidSpender(spender_);\n    }\n\n    unchecked {\n      address recoveredAddress = ecrecover(\n        keccak256(\n          abi.encodePacked(\n            \"\\x19\\x01\",\n            DOMAIN_SEPARATOR(),\n            keccak256(\n              abi.encode(\n                keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"),\n                owner_,\n                spender_,\n                value_,\n                nonces[owner_]++,\n                deadline_\n              )\n            )\n          )\n        ),\n        v_,\n        r_,\n        s_\n      );\n\n      if (recoveredAddress == address(0) || recoveredAddress != owner_) {\n        revert EIP2612InvalidSigner(recoveredAddress, owner_, spender_, value_, deadline_, v_, r_, s_);\n      }\n\n      _allowances[recoveredAddress][spender_] = value_;\n    }\n\n    assembly {\n      // emit IERC20.Approval(owner_, spender_, value_);\n      let ownerMasked := and(owner_, _BITMASK_LOWER160BITS)\n      let approvedMasked := and(spender_, _BITMASK_LOWER160BITS)\n      mstore(0x00, value_)\n      log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, ownerMasked, approvedMasked)\n    }\n  }\n\n  /**\n   * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. \n   */\n  function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n    return block.chainid == _INITIAL_CHAIN_ID ? _INITIAL_DOMAIN_SEPARATOR : _computeDomainSeparator();\n  }\n\n  /**\n   * @notice Internal function to compute the domain separator for EIP-2612 permits.\n   * @dev This function computes the domain separator based on the contract's name, version, chain ID, and address.\n   * \n   * @return bytes32 The computed domain separator value.\n   */\n  function _computeDomainSeparator() internal view virtual returns (bytes32) {\n    return\n      keccak256(\n        abi.encode(\n          keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n          keccak256(bytes(_name)),\n          keccak256(\"1\"),\n          block.chainid,\n          address(this)\n        )\n      );\n  }\n\n  /**\n   * @dev See {IERC404-isERC721TransferExempt}. \n   */\n  function isERC721TransferExempt(address target_) external view override returns (bool isExempt) {\n    isExempt = _erc721TransferExempt[target_];\n  }\n\n  /**\n   * @dev See {IERC404-setERC721TransferExempt}. \n   */\n  function setERC721TransferExempt(bool state_) external override {\n    _setERC721TransferExempt(msg.sender, state_);\n  }\n\n  /**\n   * @dev Internal function to set the exemption status for ERC-721 transfers.\n   * \n   * Requirements:\n   * - `target_` address cannot be the zero address or the stash address.\n   * \n   * @param target_ The address for which to set the exemption status.\n   * @param state_ The new exemption state to set (true for exempt, false for non-exempt).\n   */\n  function _setERC721TransferExempt(address target_, bool state_) internal virtual {\n    if (target_ == address(0) || target_ == _STASH_ADDRESS) {\n      revert ERC404InvalidERC721Exemption(target_);\n    }\n\n    // Adjust the ERC721 balances of the target to respect exemption rules.\n    if (state_) {\n      _stashAll(target_);\n    } else {\n      _retrieveAllFromStash(target_);\n    }\n\n    _erc721TransferExempt[target_] = state_;\n  }\n\n  /**\n   * @dev Internal function to stash all ERC-721 tokens owned by the target address.\n   * \n   * Emits:\n   * - {IERC721.Transfer} event for ERC-721 tokens being transferred to the stash.\n   * \n   * @param target_ The address whose tokens are to be stashed.\n   */\n  function _stashAll(address target_) private {\n    uint256[] memory ownedTarget = _owned[target_];\n    for (uint256 i = 0; i < ownedTarget.length; ) {\n      (uint256 batchInitialId_, uint256 batchQuantity_) = _getOwnedBatchInitialIdAndQuantity(target_, i);\n      delete _ownedData[batchInitialId_]; // Resets _ownedData\n      _batchHead.setBatch(batchInitialId_, batchQuantity_); // Set batchead in a massive way to all tokens.\n\n      // add all tokens to the stash\n      unchecked {\n        uint256 end = batchInitialId_ + batchQuantity_;\n        address mutableStashAddress = _STASH_ADDRESS;\n\n        for (uint256 b = batchInitialId_; b < end; ++b) {\n          delete _tokenApprovals[b]; // On stash of a token, any previous approval is reset.\n          _stashQueue.pushFront(b);\n          assembly {\n            // emit IERC721.Transfer(target_, _STASH_ADDRESS, batchInitialId_);\n            log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(target_, _BITMASK_LOWER160BITS), and(mutableStashAddress, _BITMASK_LOWER160BITS), b)\n          }\n        }\n        ++i;\n      }\n    }\n    delete _owned[target_];\n  }\n\n  /**\n   * @dev Internal function to retrieve all ERC-721 tokens from the stash for the target address.\n   * \n   * Emits:\n   * - {IERC721.Transfer} event for ERC-721 tokens being transferred from the stash.\n   * \n   * @param target_ The address to retrieve ERC-721 tokens for.\n   */\n  function _retrieveAllFromStash(address target_) private {\n    uint256 expectedERC721Balance = _balances[target_] / _UNIT;\n    uint256 actualERC721Balance = 0;\n    uint256[] memory ownedTarget = _owned[target_];\n    for (uint256 i = 0; i < ownedTarget.length; ) {\n      uint256 data = ownedTarget[i];\n      assembly {\n        actualERC721Balance := add(actualERC721Balance, shr(160, data))\n        i := add(i, 1) // Avoiding an unchecked block after this one\n      }\n    }\n\n    unchecked {\n      expectedERC721Balance -= actualERC721Balance;\n      for (uint256 i = 0; i < expectedERC721Balance; ++i) {\n        // Transfer ERC721 balance in from pool\n        _retrieveFromStash(target_);\n      }\n    }\n  }\n\n  /**\n   * @dev See {IERC404-owned}. \n   */\n  function owned(address owner_) public view virtual returns (uint256[] memory ownedCreatureIds) {\n    if (owner_ == _STASH_ADDRESS) return tokensInStash();\n    uint256 size = 0;\n    uint256 data;\n    uint256[] memory ownedOwner = _owned[owner_];\n    for (uint256 i = 0; i < ownedOwner.length; ) {\n      data = ownedOwner[i];\n      assembly {\n        size := add(size, shr(160, data))\n        i := add(i, 1)\n      }\n    }\n    ownedCreatureIds = new uint256[](size);\n\n    unchecked {\n      uint256 ix = 0;\n      uint256 batchInitialId_;\n      uint256 batchQuantity_;\n      for (uint256 i = 0; i < ownedOwner.length; ++i) {\n        data = ownedOwner[i];\n        assembly {\n          batchInitialId_ := and(data, _BITMASK_LOWER160BITS)\n          batchQuantity_ := shr(160, data)\n        }\n\n        for (uint256 j = 0; j < batchQuantity_; ++j) {\n          ownedCreatureIds[ix] = batchInitialId_ + j;\n          ++ix;\n        }\n      }\n    }\n  }\n\n  /**\n   * @dev Internal function to burn (destroy) an ERC-721 token.\n   * \n   * Emits:\n   * - {IERC721.Transfer} event from `from` to `address(0)` (burning the token).\n   * - {IERC20.Transfer} event from `from` to `address(0)` with `_UNIT` value (The ERC-20 side of the token).\n   * \n   * @param tokenId_ ID of the ERC-721 token to be burned.\n   */\n  function _burn(uint256 tokenId_) internal virtual {\n    if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_);\n    (address from, uint256 index, uint256 tokenIdBatchHead) = _getOwnerOwnedIndexAndBatchHeadId(tokenId_);\n    // _beforeTokenTransfers(from, to, tokenId, 1);\n\n    delete _tokenApprovals[tokenId_]; // On transfer, any previous approval is reset.\n\n    uint256 batchQuantity_;\n    uint256 data = _owned[from][index];\n    assembly {\n      batchQuantity_ := shr(160, data)\n    }\n\n    _removeTokenFrom(from, index, tokenId_, tokenIdBatchHead, batchQuantity_);\n    delete _ownedData[tokenId_];\n    _batchHead.set(tokenId_);\n    _burnedTokens.set(tokenId_);\n\n    unchecked {\n      // Cannot overflow, as that would require more tokens to be burned/transferred\n      // out than the owner initially received through minting and transferring in.\n      _balances[from] -= _UNIT;\n      ++_burnedCount;\n    }\n\n    data = _UNIT;\n    assembly {\n      let fromMasked := and(from, _BITMASK_LOWER160BITS)\n      // emit IERC20.Transfer(from_, to_, _UNIT);\n      mstore(0x00, data)\n      log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, fromMasked, 0x00)\n\n      // emit IERC721.Transfer(from, address(0), tokenId_);\n      log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, fromMasked, 0x00, tokenId_)\n    }\n    // _afterTokenTransfers(from, address(0), tokenId, 1);\n  }\n\n  /**\n   * @dev See {IERC404-stashAddress}. \n   */\n  function stashAddress() public view returns (address) {\n    return _STASH_ADDRESS;\n  }\n\n  /**\n   * @dev See {IERC404-stashLength}. \n   */\n  function stashLength() public view returns (uint256) {\n    return _stashQueue.length();\n  }\n\n  /**\n   * @dev See {IERC404-tokensInStash}. \n   */\n  function tokensInStash() public view returns (uint256[] memory) {\n    return _stashQueue.retriveQueueItems();\n  }\n\n  /**\n   * @dev See {IERC404-exchangeWithStash}. \n   */\n  function exchangeWithStash(uint256 tokenId_, uint128 index_) public {\n    uint256 stashTokenId = _stashQueue.at(index_);\n    if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_);\n    if (!_isApprovedOrOwner(msg.sender, tokenId_)) revert ERC721InsufficientApproval(msg.sender, tokenId_);\n    (address owner, uint256 index, uint256 tokenIdBatchHead) = _getOwnerOwnedIndexAndBatchHeadId(tokenId_);\n    // _beforeTokenTransfers(msg.sender, _STASH_ADDRESS, tokenId_, 1);\n    // _beforeTokenTransfers(_STASH_ADDRESS, msg.sender, stashTokenId, 1);\n\n    delete _tokenApprovals[tokenId_]; // On transfer, any previous approval is reset.\n\n    uint256 batchQuantity_;\n    uint256 data = _owned[owner][index];\n    assembly {\n      batchQuantity_ := shr(160, data)\n    }\n    _removeTokenFrom(owner, index, tokenId_, tokenIdBatchHead, batchQuantity_);\n    delete _ownedData[tokenId_];\n    _batchHead.set(tokenId_);\n    _stashQueue.setIndexValue(index_, tokenId_); // Sets the token to exchange into the stash\n\n    // Now, sets the Stash token to the tokenId owner\n    assembly {\n      data := add(and(stashTokenId, _BITMASK_LOWER160BITS), and(shl(160, 1), _BITMASK_UPPER96BITS))\n    }\n    _owned[owner].push(data);\n    unchecked {\n      uint256 ownedIndex = _owned[owner].length - 1;\n      assembly {\n        data := add(and(owner, _BITMASK_LOWER160BITS), and(shl(160, ownedIndex), _BITMASK_UPPER96BITS))\n      }\n    }\n    _ownedData[stashTokenId] = data;\n\n    address stashMasked = _STASH_ADDRESS;\n    assembly {\n      stashMasked := and(stashMasked, _BITMASK_LOWER160BITS)\n      let ownerMasked := and(owner, _BITMASK_LOWER160BITS)\n\n      // emit IERC721.Transfer(_STASH_ADDRESS, owner, stashTokenId);\n      log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, stashMasked, ownerMasked, stashTokenId)\n      // emit IERC721.Transfer(owner, _STASH_ADDRESS, tokenId_);\n      log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, ownerMasked, stashMasked, tokenId_)\n    }\n    // _afterTokenTransfers(msg.sender, _STASH_ADDRESS, tokenId_, 1);\n    // _afterTokenTransfers(_STASH_ADDRESS, msg.sender, stashTokenId, 1);\n  }\n}\n"
      },
      "contracts/erc404/IERC404B.sol": {
        "content": "// contracts/erc404/IERC404B.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n    /3333333     /33333333     /333333    \n   | 33__  33   | 33_____/    /33__  33   \n   | 33  \\ 33   | 33         | 33  \\__/   \n   | 3333333    | 33333      | 33         \n   | 33__  33   | 33__/      | 33         \n   | 33  \\ 33   | 33         | 33    33   \n   | 3333333/   | 33333333   |  333333/   \n   |_______/    |________/    \\______/    \n\n # https://blackeyedcreatures.com\n\n */\npragma solidity ^0.8.25;\n\nimport {IERC165} from \"@openzeppelin/contracts/interfaces/IERC165.sol\";\nimport {IERC20Permit} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\";\n\n/**\n * @title IERC404B Interface\n * @dev Interface for a hybrid token contract combining ERC20 and ERC721 functionalities with a unique \"stash\" feature.\n * The stash is a holding area for tokens that are currently unowned but not burned, allowing for controlled management and re-distribution.\n * Supports ERC165 for interface detection and ERC20Permit for token allowance via signatures.\n */\ninterface IERC404B is IERC165, IERC20Permit {\n \n  /// IERC20 + ERC721 Metadata Methods ///\n\n  /**\n   * @dev Returns the name of the token.\n   */\n  function name() external view returns (string memory);\n\n  /**\n   * @dev Returns the symbol of the token.\n   */\n  function symbol() external view returns (string memory);\n\n  /**\n   * @dev Returns the number of decimals used to get its user representation.\n   * For example, if `decimals` equals `2`, a balance of `505` tokens should\n   * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n   *\n   * Tokens usually opt for a value of 18, imitating the relationship between\n   * Ether and Wei. This is the default value returned by this function, unless\n   * it's overridden.\n   *\n   * NOTE: This information is only used for _display_ purposes: it in\n   * no way affects any of the arithmetic of the contract, including\n   * {IERC20-balanceOf} and {IERC20-transfer}.\n   */\n  function decimals() external view returns (uint8);\n\n  /**\n   * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n   */\n  function tokenURI(uint256 tokenId) external view returns (string memory);\n\n\n  /// ERC721 Methods ///\n\n  /**\n   * @dev Returns the owner of the `tokenId` token.\n   *\n   * Requirements:\n   * - `tokenId` must exist.\n   */\n  function ownerOf(uint256 tokenId) external view returns (address owner);\n\n  /**\n   * @dev Safely transfers `tokenId` token from `from` to `to`.\n   *\n   * Requirements:\n   * - `from` cannot be the zero address.\n   * - `to` cannot be the zero address.\n   * - `tokenId` token must exist and be owned by `from`.\n   * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n   * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n   *\n   * Emits a {Transfer} event.\n   */\n  function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;\n\n  /**\n   * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n   * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n   *\n   * Requirements:\n   * - `from` cannot be the zero address.\n   * - `to` cannot be the zero address.\n   * - `tokenId` token must exist and be owned by `from`.\n   * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n   * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n   *\n   * Emits a {Transfer} event.\n   */\n  function safeTransferFrom(address from, address to, uint256 tokenId) external;\n\n  /**\n   * @dev Approve or remove `operator` as an operator for the caller.\n   * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n   *\n   * Requirements:\n   * - The `operator` cannot be the caller.\n   *\n   * Emits an {ApprovalForAll} event.\n   */\n  function setApprovalForAll(address operator, bool approved) external;\n\n  /**\n   * @dev Returns the account approved for `tokenId` token.\n   *\n   * Requirements:\n   * - `tokenId` must exist.\n   */\n  function getApproved(uint256 tokenId) external view returns (address operator);\n\n  /**\n   * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n   *\n   * See {setApprovalForAll}\n   */\n  function isApprovedForAll(address owner, address operator) external view returns (bool);\n\n  /// ERC20 Methods ///\n\n  /**\n   * @dev Returns the amount of ERC20 tokens in existence.\n   */\n  function totalSupply() external view returns (uint256);\n\n  /**\n   * @dev Moves `amountOrId` tokens from the caller's account to `to`.\n   *\n   * Returns a boolean value indicating whether the operation succeeded.\n   *\n   * Emits {Transfer} events.\n   */\n  function transfer(address to, uint256 amountOrId) external returns (bool);\n\n  /**\n   * @dev Returns the remaining number of tokens that `spender` will be\n   * allowed to spend on behalf of `owner` through {transferFrom}. This is\n   * zero by default.\n   *\n   * This value changes when {approve} or {transferFrom} are called.\n   */\n  function allowance(address owner, address spender) external view returns (uint256);\n\n  /// ERC404 Combined (Methods with similar interfaces and behavior in ERC20 & ERC721) ///\n\n  /**\n   * @dev Returns the amount of tokens owned by `account`.\n   */\n  function balanceOf(address account) external view returns (uint256 balance);\n\n  /**\n   * @dev Moves `amountOrId` tokens from `from` to `to` using the\n   * allowance mechanism. `amountOrId` is then deducted from the caller's\n   * allowance.\n   *\n   * Returns a boolean value indicating whether the operation succeeded.\n   *\n   * WARNING: In case of Id, note that the caller is responsible to confirm that the recipient is capable of\n   * receiving ERC721 or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though\n   * the caller must understand this adds an external call which potentially creates a reentrancy vulnerability.\n   *\n   * Requirements:\n   * - `from` cannot be the zero address.\n   * - `to` cannot be the zero address.\n   * - `amountOrId` amount should be less or equal than balance OR tokenId must be owned by `from`.\n   * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n   *\n   * Emits {Transfer} events.\n   */\n  function transferFrom(address from, address to, uint256 amountOrId) external returns (bool);\n\n  /**\n   * @dev Sets `amountOrId` as the allowance of `spender` over the caller's tokens.\n   *\n   * Returns a boolean value indicating whether the operation succeeded.\n   *\n   * IMPORTANT: Beware that changing an allowance with this method brings the risk\n   * that someone may use both the old and the new allowance by unfortunate\n   * transaction ordering. One possible solution to mitigate this race\n   * condition is to first reduce the spender's allowance to 0 and set the\n   * desired value afterwards:\n   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n   *\n   * Emits an {Approval} event.\n   */\n  function approve(address spender, uint256 amountOrId) external returns (bool);\n\n\n  /// ERC404 Specific ///\n\n /**\n   * @notice Retrieves the equivalence between 1 ERC721 token and ERC20 needed for that token.\n   * @dev This function returns the unit value used in conversions between ERC721 and ERC20 tokens.\n   * @return The unit value representing the equivalence between 1 ERC721 token and ERC20.\n   */\n  function unit() external view returns (uint256);\n\n    /**\n   * @notice Checks if the specified token exists.\n   *\n   * A token is considered to exist if it has been minted using {_mint} and is not in the set of burned tokens.\n   *\n   * @param tokenId_ The ID of the token to check.\n   * @return True if the token exists, false otherwise.\n   */\n  function exists(uint256 tokenId_) external view returns (bool);\n\n  /**\n   * @dev Checks if the specified address is exempt from ERC-721 transfers.\n   * This function retrieves the exemption status for ERC-721 transfers for the given address.\n   * \n   * @param target_ The address to check for ERC-721 transfer exemption.\n   * @return isExempt True if the address is exempt from ERC-721 transfers, false otherwise.\n   */\n  function isERC721TransferExempt(address target_) external view returns (bool isExempt);\n\n  /**\n   * @dev Sets the exemption status for ERC-721 transfers for the caller.\n   * \n   * Emits:\n   * - {Transfer} event for each target_ ERC721 token from/to the stash.\n   * \n   * @param state_ The new exemption state to set (true for exempt, false for non-exempt).\n   */\n  function setERC721TransferExempt(bool state_) external;\n\n  /**\n   * @dev Retrieves the IDs of ERC-721 tokens owned by a specific address.\n   * \n   * @param owner_ The address for which ERC-721 token IDs are being retrieved.\n   * @return ownedCreatureIds An array of uint256 representing the ERC-721 token IDs owned by the specified address.\n   */\n  function owned(address owner_) external view returns (uint256[] memory);\n\n  /**\n   * @dev External function to get the current stash address.\n   * \n   * @return address Current stash address.\n   */\n  function stashAddress() external view returns (address);\n\n  /**\n   * @dev External function to get the current length of the stash queue.\n   * \n   * @return uint256 Current length of the stash queue.\n   */\n  function stashLength() external view returns (uint256);\n\n  /**\n   * @dev External function to retrieve all tokens currently in the stash queue.\n   * \n   * @return uint256[] An array containing all tokens currently in the stash queue.\n   */\n  function tokensInStash() external view returns (uint256[] memory);\n\n  /**\n   * @dev Public function to exchange an ERC-721 token with a token in the stash.\n   * \n   * Requirements:\n   * - The caller must be the owner or have approval to transfer the tokenId_.\n   * - The stashTokenId_ must belong to the stash.\n   * \n   * Emits:\n   * - {Transfer} event for the token exchanged from the stash to the caller.\n   * - {Transfer} event for the token exchanged from the caller to the stash.\n   * \n   * @param tokenId_ The ID of the ERC-721 token to exchange.\n   * @param index_ The index of the token at the stash to exchange with.\n   */\n  function exchangeWithStash(uint256 tokenId_, uint128 index_) external;\n}\n"
      },
      "contracts/erc404/IERC404BErrors.sol": {
        "content": "// contracts/erc404/IERC404BErrors.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n    /3333333     /33333333     /333333    \n   | 33__  33   | 33_____/    /33__  33   \n   | 33  \\ 33   | 33         | 33  \\__/   \n   | 3333333    | 33333      | 33         \n   | 33__  33   | 33__/      | 33         \n   | 33  \\ 33   | 33         | 33    33   \n   | 3333333/   | 33333333   |  333333/   \n   |_______/    |________/    \\______/    \n\n # https://blackeyedcreatures.com\n\n */\npragma solidity ^0.8.25;\n\n/**\n * @dev ERC404B3Errors interface defines custom error messages for the ERC404B3 contract.\n */\ninterface IERC404BErrors {\n\n  /**\n   * @dev Indicates that the specified token is not found in the stash.\n   * @param stashTokenId The ID of the token in the stash.\n   */\n  error ERC404TokenNotInStash(uint256 stashTokenId);\n\n  /**\n   * @dev Indicates that the index value provided is not valid in the stash queue.\n   * @param indexInQueue The index value in the queue.\n   * @param stashTokenId The ID of the token in the stash.\n   */\n  error ERC404NotValidIndexValueInStash(uint128 indexInQueue, uint256 stashTokenId);\n\n  /**\n   * @dev Indicates that the transfer value is invalid.\n   * @param value The invalid transfer value.\n   */\n  error ERC404InvalidTransferValue(uint256 value);\n\n  /**\n   * @dev Indicates that the target address is not eligible for ERC721 exemption.\n   * @param target The address that is not eligible for exemption.\n   */\n  error ERC404InvalidERC721Exemption(address target);\n\n  /**\n   * @dev Indicates an overflow in the owned index.\n   * @param index The index value causing the overflow.\n   */\n  error ERC404OwnedIndexOverflow(uint256 index);\n\n  /**\n   * @dev Indicates an invalid mint quantity for ERC721.\n   */\n  error ERC721InvalidMintQuantity();\n\n  /**\n   * @dev Indicates that the recipient address has not implemented ERC721Receiver.\n   * @param to The recipient address.\n   * @param tokenId The ID of the token being transferred.\n   * @param quantity The quantity of tokens being transferred.\n   * @param data Additional data for the transfer.\n   */\n  error ERC721ReceiverNotImplemented(address to, uint256 tokenId, uint256 quantity, bytes data);\n\n  /**\n   * @dev Indicates that the permit deadline has expired for EIP-2612 permit.\n   * @param owner The owner of the tokens.\n   * @param spender The spender of the tokens.\n   * @param value The token value.\n   * @param deadline The expired deadline.\n   * @param v Signature parameter v.\n   * @param r Signature parameter r.\n   * @param s Signature parameter s.\n   */\n  error EIP2612PermitDeadlineExpired(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s);\n\n  /**\n   * @dev Indicates that the signer of the permit is invalid for EIP-2612 permit.\n   * @param recoveredAddress The recovered signer address.\n   * @param owner The owner of the tokens.\n   * @param spender The spender of the tokens.\n   * @param value The token value.\n   * @param deadline The permit deadline.\n   * @param v Signature parameter v.\n   * @param r Signature parameter r.\n   * @param s Signature parameter s.\n   */\n  error EIP2612InvalidSigner(address recoveredAddress, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s);\n}\n"
      },
      "contracts/erc404/lib/DoubleEndedQueue.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/DoubleEndedQueue.sol)\n// Modified by Pandora Labs to support native uint256 operations\n// Modified by 42i.co to retriveQueueItems && setIndexValue\npragma solidity ^0.8.25;\n\n/**\n * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of\n * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and\n * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that\n * the existing queue contents are left in storage.\n *\n * The struct is called `Uint256Deque`. This data structure can only be used in storage, and not in memory.\n *\n * ```solidity\n * DoubleEndedQueue.Uint256Deque queue;\n * ```\n */\nlibrary DoubleEndedQueue {\n  /**\n   * @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty.\n   */\n  error QueueEmpty();\n\n  /**\n   * @dev A push operation couldn't be completed due to the queue being full.\n   */\n  error QueueFull();\n\n  /**\n   * @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds.\n   */\n  error QueueOutOfBounds();\n\n  /**\n   * @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access.\n   *\n   * Struct members have an underscore prefix indicating that they are \"private\" and should not be read or written to\n   * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and\n   * lead to unexpected behavior.\n   *\n   * The first item is at data[begin] and the last item is at data[end - 1]. This range can wrap around.\n   */\n  struct Uint256Deque {\n    uint128 _begin;\n    uint128 _end;\n    mapping(uint128 index => uint256) _data;\n  }\n\n  /**\n   * @dev Retrieves all items from the queue as an array of uint256 values.\n   * This function does not modify the state of the queue.\n   */\n  function retriveQueueItems(Uint256Deque storage deque) internal view returns (uint256[] memory dequeTokens) {\n    unchecked {\n      uint128 beginIndex = deque._begin;\n      uint128 queueLenght = deque._end - beginIndex;\n      dequeTokens = new uint256[](queueLenght);\n      for (uint128 i = 0; i < queueLenght; ++i) {\n        dequeTokens[i] = deque._data[beginIndex+i];\n      }\n    }\n  }\n\n  /**\n   * @dev Sets the value at a specific index in the queue. The index is relative to the current `begin` of the queue.\n   * This function allows for direct manipulation of queue items at a given index, and should be used with caution as\n   * improper usage can lead to logical errors in the queue state.\n   *\n   * Reverts with `QueueOutOfBounds` if the index is out of bounds.\n   */\n  function setIndexValue(Uint256Deque storage deque, uint128 index, uint256 value) internal {\n    if (index >= length(deque)) revert QueueOutOfBounds();\n    deque._data[index+deque._begin] = value;\n  }\n\n  /**\n   * @dev Inserts an item at the end of the queue.\n   *\n   * Reverts with {QueueFull} if the queue is full.\n   */\n  function pushBack(Uint256Deque storage deque, uint256 value) internal {\n    unchecked {\n      uint128 backIndex = deque._end;\n      if (backIndex + 1 == deque._begin) revert QueueFull();\n      deque._data[backIndex] = value;\n      deque._end = backIndex + 1;\n    }\n  }\n\n  /**\n   * @dev Removes the item at the end of the queue and returns it.\n   *\n   * Reverts with {QueueEmpty} if the queue is empty.\n   */\n  function popBack(\n    Uint256Deque storage deque\n  ) internal returns (uint256 value) {\n    unchecked {\n      uint128 backIndex = deque._end;\n      if (backIndex == deque._begin) revert QueueEmpty();\n      --backIndex;\n      value = deque._data[backIndex];\n      delete deque._data[backIndex];\n      deque._end = backIndex;\n    }\n  }\n\n  /**\n   * @dev Inserts an item at the beginning of the queue.\n   *\n   * Reverts with {QueueFull} if the queue is full.\n   */\n  function pushFront(Uint256Deque storage deque, uint256 value) internal {\n    unchecked {\n      uint128 frontIndex = deque._begin - 1;\n      if (frontIndex == deque._end) revert QueueFull();\n      deque._data[frontIndex] = value;\n      deque._begin = frontIndex;\n    }\n  }\n\n  /**\n   * @dev Removes the item at the beginning of the queue and returns it.\n   *\n   * Reverts with `QueueEmpty` if the queue is empty.\n   */\n  function popFront(\n    Uint256Deque storage deque\n  ) internal returns (uint256 value) {\n    unchecked {\n      uint128 frontIndex = deque._begin;\n      if (frontIndex == deque._end) revert QueueEmpty();\n      value = deque._data[frontIndex];\n      delete deque._data[frontIndex];\n      deque._begin = frontIndex + 1;\n    }\n  }\n\n  /**\n   * @dev Returns the item at the beginning of the queue.\n   *\n   * Reverts with `QueueEmpty` if the queue is empty.\n   */\n  function front(\n    Uint256Deque storage deque\n  ) internal view returns (uint256 value) {\n    if (empty(deque)) revert QueueEmpty();\n    return deque._data[deque._begin];\n  }\n\n  /**\n   * @dev Returns the item at the end of the queue.\n   *\n   * Reverts with `QueueEmpty` if the queue is empty.\n   */\n  function back(\n    Uint256Deque storage deque\n  ) internal view returns (uint256 value) {\n    if (empty(deque)) revert QueueEmpty();\n    unchecked {\n      return deque._data[deque._end - 1];\n    }\n  }\n\n  /**\n   * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at\n   * `length(deque) - 1`.\n   *\n   * Reverts with `QueueOutOfBounds` if the index is out of bounds.\n   */\n  function at(\n    Uint256Deque storage deque,\n    uint256 index\n  ) internal view returns (uint256 value) {\n    if (index >= length(deque)) revert QueueOutOfBounds();\n    // By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128\n    unchecked {\n      return deque._data[deque._begin + uint128(index)];\n    }\n  }\n\n  /**\n   * @dev Resets the queue back to being empty.\n   *\n   * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses\n   * out on potential gas refunds.\n   */\n  function clear(Uint256Deque storage deque) internal {\n    deque._begin = 0;\n    deque._end = 0;\n  }\n\n  /**\n   * @dev Returns the number of items in the queue.\n   */\n  function length(Uint256Deque storage deque) internal view returns (uint256) {\n    unchecked {\n      return uint256(deque._end - deque._begin);\n    }\n  }\n\n  /**\n   * @dev Returns true if the queue is empty.\n   */\n  function empty(Uint256Deque storage deque) internal view returns (bool) {\n    return deque._end == deque._begin;\n  }\n}"
      },
      "contracts/erc4626/BECETHPoolRewardsVault.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.25;\n\nimport \"./RewardsVault.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ncontract BECETHPoolRewardsVault is RewardsVault {\n  IERC20 public immutable pool;\n\n  constructor(\n    address _poolAddress,\n    address _rewardTokenAddress,\n    string memory name,\n    string memory symbol\n  ) RewardsVault(_poolAddress, _rewardTokenAddress, name, symbol) {\n    pool = IERC20(_poolAddress);\n  }\n}\n"
      },
      "contracts/erc4626/ERC404RewardsVault.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.25;\n\nimport \"./RewardsVault.sol\";\nimport {IERC404B} from \"../erc404/IERC404B.sol\";\n\ncontract ERC404RewardsVault is RewardsVault {\n  IERC404B public immutable erc404;\n\n  /// @dev tracking of which token is deposited by address\n  mapping(address owner => uint256[] tokenIds) public depositedTokens;\n\n  constructor(\n    address _erc404TokenAddress,\n    address _rewardTokenAddress,\n    string memory name,\n    string memory symbol\n  ) RewardsVault(_erc404TokenAddress, _rewardTokenAddress, name, symbol) {\n    erc404 = IERC404B(_erc404TokenAddress);\n  }\n\n  // Override the deposit function to handle ERC404 token deposits by token ID\n  function deposit(uint256 tokenId, address receiver) public virtual override returns (uint256 shares) {\n    require(erc404.exists(tokenId), \"ERC404Vault: Token does not exist\");\n    depositedTokens[receiver].push(tokenId);\n    return super.deposit(tokenId, receiver);\n  }\n\n  // Override the deposit function to handle ERC404 token withdraws by token ID\n  function withdraw(uint256 tokenId, address receiver, address owner) public virtual override returns (uint256) {\n    require(erc404.exists(tokenId), \"ERC404Vault: Token does not exist\");\n\n    uint256[] storage tokens = depositedTokens[owner];\n    for (uint256 i = 0; i < tokens.length; i++) {\n      if (tokens[i] == tokenId) {\n        tokens[i] = tokens[tokens.length - 1];\n        tokens.pop();\n        break;\n      }\n    }\n\n    return super.withdraw(tokenId, receiver, owner);\n  }\n\n  // Override the deposit function to handle ERC404, asuming the first value is a tokenId\n  function _convertToShares(uint256, Math.Rounding rounding) internal view virtual override returns (uint256) {\n    return super._convertToShares(erc404.unit(), rounding); // Assuming 1 unit of assets always converts to 1 share\n  }\n}\n"
      },
      "contracts/erc4626/RewardsVault.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.25;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol\";\nimport \"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol\";\nimport \"./RewardTreasury.sol\";\nimport \"../BECLab.sol\";\n\n// https://hackernoon.com/how-to-implement-a-stake-and-reward-contract-in-solidity\nabstract contract RewardsVault is ERC4626, IERC721Receiver, Ownable {\n  using Cast for uint256;\n\n  event RewardsSet(uint32 start, uint32 end, uint256 rate);\n  event RewardsPerTokenUpdated(uint256 accumulated);\n  event UserRewardsUpdated(address user, uint256 userRewards, uint256 paidRewardPerToken);\n  event Claimed(address user, address receiver, uint256 claimed);\n\n  struct RewardsInterval {\n    uint32 start; // Start time for the current rewardsToken schedule\n    uint32 end; // End time for the current rewardsToken schedule\n    uint96 rate; // Wei rewarded per unit of time among all token holders\n  }\n\n  struct RewardsPerToken {\n    uint128 accumulated; // Accumulated rewards per token for the interval, scaled up by 1e18\n    uint32 lastUpdated; // Last time the rewards per token accumulator was updated\n  }\n\n  struct UserRewards {\n    uint128 accumulated; // Accumulated rewards for the user until the checkpoint\n    uint128 checkpoint; // RewardsPerToken the last time the user rewards were updated\n  }\n\n  RewardTreasury public immutable rewardTreasury;\n  IERC20 public immutable rewardToken;\n  RewardsInterval public rewardsInterval; // Interval in which rewards are accumulated by users\n  RewardsPerToken public rewardsPerToken; // Accumulator to track rewards per token\n  mapping(address => UserRewards) public accumulatedRewards; // Rewards accumulated per user\n\n  constructor(\n    address _assetTokenAddress,\n    address _rewardTokenAddress,\n    string memory name,\n    string memory symbol\n  ) ERC20(name, symbol) ERC4626(IERC20(_assetTokenAddress)) Ownable(msg.sender) {\n    rewardToken = IERC20(_rewardTokenAddress);\n\n    // Deploy the RewardTreasury and set max allowance for this vault\n    rewardTreasury = new RewardTreasury();\n    rewardTreasury.grantMaxAllowance(rewardToken, address(this));\n  }\n\n  function treasuryBalance() public view virtual returns (uint256) {\n    return rewardToken.balanceOf(address(rewardTreasury));\n  }\n\n  /// @dev Set a rewards schedule\n  function setRewardsInterval(uint256 start, uint256 end, uint256 totalRewards) public onlyOwner {\n    require(start < end, \"Incorrect interval\");\n\n    // A new rewards program can be set if one is not running\n    require(\n      block.timestamp.u32() < rewardsInterval.start || block.timestamp.u32() > rewardsInterval.end,\n      \"Rewards still ongoing\"\n    );\n\n    // Transfer the rewards required for the interval to the Treasury\n    SafeERC20.safeTransferFrom(rewardToken, msg.sender, address(rewardTreasury), totalRewards);\n\n    // Update the rewards per token so that we don't lose any rewards\n    _updateRewardsPerToken();\n\n    uint256 rate = totalRewards / (end - start);\n    rewardsInterval.start = start.u32();\n    rewardsInterval.end = end.u32();\n    rewardsInterval.rate = rate.u96();\n\n    // If setting up a new rewards program, the rewardsPerToken.accumulated is used and built upon\n    // New rewards start accumulating from the new rewards program start\n    // Any unaccounted rewards from last program can still be added to the user rewards\n    // Any unclaimed rewards can still be claimed\n    rewardsPerToken.lastUpdated = start.u32();\n\n    emit RewardsSet(start.u32(), end.u32(), rate);\n  }\n\n  /// @notice Update the rewards per token accumulator according to the rate, the time elapsed since the last update, and the current total staked amount.\n  function _calculateRewardsPerToken(\n    RewardsPerToken memory rewardsPerTokenIn,\n    RewardsInterval memory rewardsInterval_\n  ) internal view returns (RewardsPerToken memory rewardsPerTokenOut) {\n    rewardsPerTokenOut = RewardsPerToken(rewardsPerTokenIn.accumulated, rewardsPerTokenIn.lastUpdated);\n    uint256 totalSupply_ = totalSupply();\n\n    // No changes if the program hasn't started\n    if (block.timestamp < rewardsInterval_.start) return rewardsPerTokenOut;\n\n    // Stop accumulating at the end of the rewards interval\n    uint256 updateTime = block.timestamp < rewardsInterval_.end ? block.timestamp : rewardsInterval_.end;\n    uint256 elapsed = updateTime - rewardsPerTokenIn.lastUpdated;\n\n    // No changes if no time has passed\n    if (elapsed == 0) return rewardsPerTokenOut;\n\n    rewardsPerTokenOut.lastUpdated = updateTime.u32();\n\n    // If there are no stakers we just change the last update time, the rewards for intervals without stakers are not accumulated\n    if (totalSupply_ == 0) return rewardsPerTokenOut;\n\n    // Calculate and update the new value of the accumulator.\n    rewardsPerTokenOut.accumulated = (rewardsPerTokenIn.accumulated +\n      (1e18 * elapsed * rewardsInterval_.rate) /\n      totalSupply_).u128(); // The rewards per token are scaled up for precision\n  }\n\n  /// @notice Calculate the rewards accumulated by a stake between two checkpoints.\n  function _calculateUserRewards(\n    uint256 stake_,\n    uint256 earlierCheckpoint,\n    uint256 latterCheckpoint\n  ) internal pure returns (uint256) {\n    return (stake_ * (latterCheckpoint - earlierCheckpoint)) / 1e18; // We must scale down the rewards by the precision factor\n  }\n\n  /// @notice Update and return the rewards per token accumulator according to the rate, the time elapsed since the last update, and the current total staked amount.\n  function _updateRewardsPerToken() internal returns (RewardsPerToken memory rewardsPerTokenOut) {\n    RewardsPerToken memory rewardsPerTokenIn = rewardsPerToken;\n    rewardsPerTokenOut = _calculateRewardsPerToken(rewardsPerTokenIn, rewardsInterval);\n\n    // We skip the storage changes if already updated in the same block, or if the program has ended and was updated at the end\n    if (rewardsPerTokenIn.lastUpdated == rewardsPerTokenOut.lastUpdated) return rewardsPerTokenOut;\n\n    rewardsPerToken = rewardsPerTokenOut;\n    emit RewardsPerTokenUpdated(rewardsPerTokenOut.accumulated);\n  }\n\n  /// @notice Calculate and store current rewards for an user. Checkpoint the rewardsPerToken value with the user.\n  function _updateUserRewards(address user) internal returns (UserRewards memory userRewards_) {\n    RewardsPerToken memory rewardsPerToken_ = _updateRewardsPerToken();\n    userRewards_ = accumulatedRewards[user];\n\n    // We skip the storage changes if there are no changes to the rewards per token accumulator\n    if (userRewards_.checkpoint == rewardsPerToken_.accumulated) return userRewards_;\n\n    // Calculate and update the new value user reserves.\n    userRewards_.accumulated += _calculateUserRewards(\n      balanceOf(user),\n      userRewards_.checkpoint > 0 ? userRewards_.checkpoint : rewardsPerToken_.accumulated,\n      rewardsPerToken_.accumulated\n    ).u128();\n    userRewards_.checkpoint = rewardsPerToken_.accumulated;\n\n    accumulatedRewards[user] = userRewards_;\n    emit UserRewardsUpdated(user, userRewards_.accumulated, userRewards_.checkpoint);\n  }\n\n  /// @notice Claim rewards for an user\n  function _claim(address from, address to, uint256 amount) internal virtual {\n    _updateUserRewards(from);\n    accumulatedRewards[from].accumulated -= amount.u128();\n    SafeERC20.safeTransferFrom(rewardToken, address(rewardTreasury), to, amount);\n    emit Claimed(from, to, amount);\n  }\n\n  /// @dev Transfer tokens, after updating rewards for source and destination.\n  function transfer(address to, uint amount) public virtual override(ERC20, IERC20) returns (bool) {\n    _updateUserRewards(msg.sender);\n    _updateUserRewards(to);\n    return super.transfer(to, amount);\n  }\n\n  /// @dev Transfer tokens, after updating rewards for source and destination.\n  function transferFrom(address from, address to, uint amount) public virtual override(ERC20, IERC20) returns (bool) {\n    _updateUserRewards(from);\n    _updateUserRewards(to);\n    return super.transferFrom(from, to, amount);\n  }\n\n  /// @notice Claim all rewards for the caller\n  function claim(address to) public virtual returns (uint256 claimed) {\n    claimed = currentUserRewards(msg.sender);\n    _claim(msg.sender, to, claimed);\n  }\n\n  /// @dev See {ERC4626-deposit}.\n  function deposit(uint256 tokenId, address receiver) public virtual override returns (uint256 shares) {\n    uint256 result = super.deposit(tokenId, receiver);\n    _updateUserRewards(receiver);\n    return result;\n  }\n\n  /// @notice Calculate and return current rewards per token.\n  function currentRewardsPerToken() public view returns (uint256) {\n    return _calculateRewardsPerToken(rewardsPerToken, rewardsInterval).accumulated;\n  }\n\n  /// @notice Calculate and return current rewards for a user.\n  /// @dev This repeats the logic used on transactions, but doesn't update the storage.\n  function currentUserRewards(address user) public view returns (uint256) {\n    UserRewards memory accumulatedRewards_ = accumulatedRewards[user];\n    RewardsPerToken memory rewardsPerToken_ = _calculateRewardsPerToken(rewardsPerToken, rewardsInterval);\n    return\n      accumulatedRewards_.accumulated +\n      _calculateUserRewards(\n        balanceOf(user),\n        accumulatedRewards_.checkpoint > 0 ? accumulatedRewards_.checkpoint : rewardsPerToken_.accumulated,\n        rewardsPerToken_.accumulated\n      );\n  }\n    \n  function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) {\n    return this.onERC721Received.selector;\n  }\n}\n\nlibrary Cast {\n  function u128(uint256 x) internal pure returns (uint128 y) {\n    require(x <= type(uint128).max, \"Cast overflow\");\n    y = uint128(x);\n  }\n\n  function u96(uint256 x) internal pure returns (uint96 y) {\n    require(x <= type(uint96).max, \"Cast overflow\");\n    y = uint96(x);\n  }\n\n  function u32(uint256 x) internal pure returns (uint32 y) {\n    require(x <= type(uint32).max, \"Cast overflow\");\n    y = uint32(x);\n  }\n}\n"
      },
      "contracts/erc4626/RewardTreasury.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.25;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\ncontract RewardTreasury is Ownable {\n  // Constructor is empty as you requested no initialization logic or storage of state\n  constructor() Ownable(msg.sender) {}\n\n  // This function sets the maximum allowance for a specified address on a given ERC20 token\n  function grantMaxAllowance(IERC20 token, address spender) public onlyOwner {\n    require(token.approve(spender, type(uint256).max), \"RewardTreasury: Failed to approve max allowance\");\n  }\n}\n"
      },
      "contracts/erc4626/WVBECRewardsVault.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.25;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./ERC404RewardsVault.sol\";\nimport \"../BECCore.sol\";\nimport \"../BECLab.sol\";\n\ncontract WVBECRewardsVault is ERC404RewardsVault {\n  address internal immutable labContractAddress;\n\n  constructor(\n    address _becCoreContractAddress,\n    address _labContractAddress\n  ) ERC404RewardsVault(_becCoreContractAddress, _becCoreContractAddress, \"Wrapped Virgin BEC\", \"WVBEC\") {\n    labContractAddress = _labContractAddress;\n  }\n\n  // Override the deposit function to handle ERC404 token deposits by token ID\n  function deposit(uint256 tokenId, address receiver) public virtual override returns (uint256 shares) {\n    BECCore coreContract = BECCore(payable(address(erc404)));\n    BECLab labContract = BECLab(payable(labContractAddress));\n    require(coreContract.exists(tokenId), \"WVBECRewardsVault: Token must exists\");\n\n    require(labContract.getOmegas(tokenId) == 0, \"WVBECRewardsVault: Token must be virgin\");\n\n    bytes32 seed = coreContract.getSeed(tokenId);\n    uint256 generation = (uint256(seed) >> 246) & 0x3;\n\n    require(generation < 3, \"WVBECRewardsVault: Generation must be less than 3\");\n    return super.deposit(tokenId, receiver);\n  }\n\n  // Mint feature disabled, use deposit instead.\n  function maxMint(address) public view virtual override returns (uint256) {\n    return 0;\n  }\n\n  // Redeem feature disabled, use withdraw instead.\n  function maxRedeem(address) public view virtual override returns (uint256) {\n    return 0;\n  }\n}\n"
      },
      "contracts/erc4626/WVG0BECRewardsVault.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.25;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./ERC404RewardsVault.sol\";\nimport \"../BECCore.sol\";\n\ncontract WVG0BECRewardsVault is ERC404RewardsVault {\n  address internal immutable labContractAddress;\n\n  constructor(\n    address _becCoreContractAddress,\n    address _labContractAddress\n  ) ERC404RewardsVault(_becCoreContractAddress, _becCoreContractAddress, \"Wrapped Virgin Gen 0 BEC\", \"WVG0BEC\") {\n    labContractAddress = _labContractAddress;\n  }\n\n  // Override the deposit function to handle ERC404 token deposits by token ID\n  function deposit(uint256 tokenId, address receiver) public virtual override returns (uint256 shares) {\n    BECCore coreContract = BECCore(payable(address(erc404)));\n    BECLab labContract = BECLab(payable(labContractAddress));\n    require(coreContract.exists(tokenId), \"WVG0BECRewardsVault: Token must exists\");\n\n    require(labContract.getOmegas(tokenId) == 0, \"WVG0BECRewardsVault: Token must be virgin\");\n\n    bytes32 seed = coreContract.getSeed(tokenId);\n    uint256 generation = (uint256(seed) >> 246) & 0x3;\n\n    require(generation == 0, \"WVG0BECRewardsVault: Token must be gen 0\");\n    return super.deposit(tokenId, receiver);\n  }\n\n  // Mint feature disabled, use deposit instead.\n  function maxMint(address) public view virtual override returns (uint256) {\n    return 0;\n  }\n\n  // Redeem feature disabled, use withdraw instead.\n  function maxRedeem(address) public view virtual override returns (uint256) {\n    return 0;\n  }\n}\n"
      },
      "contracts/IBECErrors.sol": {
        "content": "// contracts/IBECErrors.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n    /3333333     /33333333     /333333    \n   | 33__  33   | 33_____/    /33__  33   \n   | 33  \\ 33   | 33         | 33  \\__/   \n   | 3333333    | 33333      | 33         \n   | 33__  33   | 33__/      | 33         \n   | 33  \\ 33   | 33         | 33    33   \n   | 3333333/   | 33333333   |  333333/   \n   |_______/    |________/    \\______/    \n\n # https://blackeyedcreatures.com\n\n */\npragma solidity ^0.8.25;\n\n/**\n * @title IBECErrors\n * @dev Interface for Black Eyed Creatures (BEC) custom errors.\n * @author https://42i.co\n */\ninterface IBECErrors {\n\n    /**\n     * @dev Indicates that a minting operation attempted to mint zero creatures.\n     */\n    error BECZeroQuantityMinting();\n\n    /**\n     * @dev Indicates that a minting operation has exceeded the cap limit for creatures.\n     */\n    error BECCapLimitReached();\n\n    /**\n     * @dev Indicates that invalid ambassadors were provided.\n     * @param alpha ID of the first ambassador.\n     * @param beta ID of the second ambassador.\n     * @param gamma ID of the third ambassador.\n     */\n    error BECInvalidAmbassadors(uint256 alpha, uint256 beta, uint256 gamma);\n\n    /**\n     * @dev Indicates that an incorrect number of ambassadors was provided.\n     * @param length The number of ambassadors provided.\n     */\n    error BECInvalidAmbassadorsLength(uint256 length);\n\n    /**\n     * @dev Indicates that a creature is already set as a variation ambassador.\n     * @param creatureId The ID of the creature.\n     */\n    error BECAlreadyVariationAmbassador(uint256 creatureId);\n\n    /**\n     * @dev Indicates that a creature is already set as a family ambassador.\n     * @param creatureId The ID of the creature.\n     */\n    error BECAlreadyFamilyAmbassador(uint256 creatureId);\n\n    /**\n     * @dev Indicates that a creature is not a variation ambassador when required.\n     * @param creatureId The ID of the creature.\n     */\n    error BECNotVariationAmbassador(uint256 creatureId);\n\n    /**\n     * @dev Indicates that an invalid phenotype was provided.\n     * @param phenotype The invalid phenotype identifier.\n     */\n    error BECInvalidPhenotype(uint256 phenotype);\n\n    /**\n     * @dev Indicates that an invalid family was provided for a creature.\n     * @param creatureId The ID of the creature.\n     */\n    error BECInvalidFamily(uint256 creatureId);\n\n    /**\n     * @dev Indicates that an invalid variation was provided for a creature.\n     * @param creatureId The ID of the creature.\n     */\n    error BECInvalidVariation(uint256 creatureId);\n\n    /**\n     * @dev Indicates that an invalid name was provided, either empty or too long.\n     * @param name The invalid name submitted.\n     */\n    error BECInvalidName(string name);\n\n    /**\n     * @dev Indicates that a duplicated name was provided.\n     * @param name The duplicate name submitted.\n     */\n    error BECDuplicatedName(string name);\n\n    /**\n     * @dev Indicates that a variation name has already been set for a given phenotype, family, and variation.\n     * @param phenotype The phenotype identifier.\n     * @param family The family identifier.\n     * @param variation The variation identifier.\n     */\n    error BECVariationNameAlreadySet(uint256 phenotype, uint256 family, uint256 variation);\n\n    /**\n     * @dev Indicates that a family name has already been set for a given phenotype and family.\n     * @param phenotype The phenotype identifier.\n     * @param family The family identifier.\n     */\n    error BECFamilyNameAlreadySet(uint256 phenotype, uint256 family);\n\n    /**\n     * @dev Indicates that not all variations have been set for a given phenotype and family.\n     * @param phenotype The phenotype identifier.\n     * @param family The family identifier.\n     * @param variation The variation identifier that is missing.\n     */\n    error BECNotAllVariationsSet(uint256 phenotype, uint256 family, uint256 variation);\n\n    /**\n     * @dev Indicates that not all required variations were present.\n     */\n    error BECNotAllVariationsPresent();\n\n    /**\n     * @dev Indicates that a hunt has already finished.\n     */\n    error BECHuntFinished();\n\n    /**\n     * @dev Indicates that the ritual price was not fully paid.\n     * @param price The expected price.\n     * @param paid The amount that was actually paid.\n     */\n    error BECRitualPriceNotPaid(uint256 price, uint256 paid);\n\n    /**\n     * @dev Indicates that the maximum number of hunts allowed was exceeded.\n     * @param allowed The allowed number of hunts.\n     * @param required The required number of hunts attempted.\n     */\n    error BECMaxHuntsAllowed(uint256 allowed, uint256 required);\n\n    /**\n     * @dev Indicates that the maximum number of reproductions allowed was exceeded.\n     * @param allowed The allowed number of reproductions.\n     * @param required The required number of reproductions attempted.\n     */\n    error BECMaxReproductionsAllowed(uint256 allowed, uint256 required);\n\n    /**\n     * @dev Indicates that the maximum number of reproductions for a specific creature was exceeded.\n     * @param creatureId The ID of the creature.\n     * @param allowed The allowed number of reproductions for this creature.\n     * @param required The required number of reproductions attempted.\n     */\n    error BECMaxCreatureReproductionsAllowed(uint256 creatureId, uint256 allowed, uint256 required);\n\n    /**\n     * @dev Indicates that the creature is not of type 0, which is required for the operation.\n     * @param creatureId The ID of the creature.\n     */\n    error BECNotType0Creature(uint256 creatureId);\n\n    /**\n     * @dev Indicates that the creature is fruitless, meaning it cannot reproduce.\n     * @param creatureId The ID of the creature.\n     */\n    error BECFruitlessCreature(uint256 creatureId);\n\n    /**\n     * @dev Indicates that a parent creature was attempted to be used as payment, which is not allowed.\n     * @param creatureId The ID of the creature.\n     */\n    error BECParentCreatureAsPayment(uint256 creatureId);\n\n    /**\n     * @dev Indicates that an invalid owner was provided for a token.\n     * @param operator The address of the operator trying to act on the token.\n     * @param tokenId The token ID being acted upon.\n     */\n    error BECInvalidOwner(address operator, uint256 tokenId);\n\n    /**\n     * @dev Indicates that there are insufficient funds for the requested operation.\n     * @param requested The amount of funds requested.\n     * @param available The amount of funds available.\n     */\n    error BECInsufficientFunds(uint256 requested, uint256 available);\n\n    /**\n     * @dev Indicates that an invalid owner was provided for a Black Sphere.\n     * @param owner The incorrect owner address.\n     * @param blacksphere The Black Sphere ID involved.\n     */\n    error BlackSphereInvalidOwner(address owner, uint256 blacksphere);\n\n    /**\n     * @dev Indicates that the function or feature called is not currently enabled.\n     */\n    error BECNotEnabled();\n\n    /**\n     * @dev Indicates that the genesis store for a creature has already been set.\n     * @param creatureId The ID of the creature.\n     */\n    error BECGenesisStoreAlreadySet(uint256 creatureId);\n\n    /**\n     * @dev Indicates that the distribution for a creature has already been set.\n     * @param distribution The distribution ID.\n     */\n    error BECDistributionAlreadySet(uint256 distribution);\n\n    /**\n     * @dev Indicates that the wrong distribution ID was provided.\n     * @param distributionId The incorrect distribution ID provided.\n     */\n    error BECWrongDistributionId(uint256 distributionId);\n\n    /**\n     * @dev Indicates that the domain for a creature has already been set.\n     * @param domain The domain ID.\n     */\n    error BECDomainAlreadySet(uint256 domain);\n\n    /**\n     * @dev Indicates that an empty array was provided for golden data.\n     */\n    error BECEmptyGoldenDataArray();\n\n    /**\n     * @dev Indicates that a non-empty golden deltas array was provided when expected to be empty.\n     */\n    error BECNotEmptyGoldenDeltasArray();\n\n    /**\n     * @dev Indicates that more creatures were provided than there are phenotypes available.\n     */\n    error BECMoreCreaturesThanPhenotypes();\n\n    /**\n     * @dev Indicates that an awakening operation has already been performed.\n     */\n    error BECAlreadyAwaken();\n\n    /**\n     * @dev Indicates that IDs were not provided in order.\n     */\n    error BECIdsNotInOrder();\n\n    /**\n     * @dev Indicates that an invalid address was provided.\n     * @param target The target address.\n     */\n    error BECInvalidAddress(address target);\n\n    /**\n     * @dev Indicates that an invalid protocol bit was used.\n     */\n    error BECInvalidProtocolBit();\n\n    /**\n     * @dev Indicates that an index was out of bounds.\n     */\n    error BECIndexOutOfBounds();\n}\n"
      },
      "contracts/meta-extensions/AwakenBECURLExtension.sol": {
        "content": "// contracts/meta-extensions/AwakenBECURLExtension.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n    /3333333     /33333333     /333333    \n   | 33__  33   | 33_____/    /33__  33   \n   | 33  \\ 33   | 33         | 33  \\__/   \n   | 3333333    | 33333      | 33         \n   | 33__  33   | 33__/      | 33         \n   | 33  \\ 33   | 33         | 33    33   \n   | 3333333/   | 33333333   |  333333/   \n   |_______/    |________/    \\______/    \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {GoldenDnaStrategy} from \"../strategies/GoldenDnaStrategy.sol\";\nimport {IBECMetaExtension} from \"../meta-extensions/IBECMetaExtension.sol\";\nimport {Strings} from \"@openzeppelin/contracts/utils/Strings.sol\";\n\n/**\n * @title Awaken BEC Meta Extension\n * @notice Use this contract to apply the \"Awaken\" status extension to BEC creatures based on their current state in the GoldenDnaStrategy contract.\n * @dev This contract implements an extension for the Black Eyed Creatures (BEC) metadata system, \n *      specifically targeting the \"Awaken\" status of creatures. \n * @author https://42i.co\n */\ncontract AwakenBECMetaExtension is IBECMetaExtension {\n\n  /// @dev The golden strategy address.\n  address private goldenDnaStrategyAddress;\n\n  /**\n   * @notice Initializes a new instance of the AwakenBECMetaExtension contract.\n   * @dev Stores the address of the GoldenDnaStrategy contract address, allowing this extension to query creature statuses.  \n   * @param _goldenDnaStrategyAddress The address of the GoldenDnaStrategy contract, \n   *        which contains the logic to check if a creature is awakened.\n   */\n  constructor(address _goldenDnaStrategyAddress) {\n    goldenDnaStrategyAddress = _goldenDnaStrategyAddress;\n  }\n\n  /**\n   * @dev See {IBECMetaExtension-applyExtension}.\n   */\n  function applyExtension(uint256 _creatureId) external view override returns (string memory) {\n    if (isAwaken(_creatureId)) {\n      return ',{\"value\": \"Awaken\"}';\n    }\n    return \"\";\n  }\n\n  /**\n   * @notice Checks if a creature is awakened by consulting the GoldenDnaStrategy contract.\n   * @dev This function encapsulates the logic to determine a creature's \"Awaken\" status.\n   * @param _creatureId The ID of the creature to check.\n   * @return bool True if the creature is awakened, false otherwise.\n   */\n  function isAwaken(uint256 _creatureId) private view returns (bool) {\n    // Adapting the logic from GoldenDnaStrategy's verifyNotAwaken method\n    uint256[] memory ids = new uint256[](1);\n    ids[0] = _creatureId;\n    // If verifyNotAwaken returns false, it means the creature is awaken\n    return !GoldenDnaStrategy(payable(goldenDnaStrategyAddress)).verifyNotAwaken(ids);\n  }\n}\n"
      },
      "contracts/meta-extensions/IBECMetaExtension.sol": {
        "content": "// contracts/meta-extensions/IBECMetaExtension.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n    /3333333     /33333333     /333333    \n   | 33__  33   | 33_____/    /33__  33   \n   | 33  \\ 33   | 33         | 33  \\__/   \n   | 3333333    | 33333      | 33         \n   | 33__  33   | 33__/      | 33         \n   | 33  \\ 33   | 33         | 33    33   \n   | 3333333/   | 33333333   |  333333/   \n   |_______/    |________/    \\______/    \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\n/**\n * @title Black Eyed Creatures Meta Extension Interface\n * @dev Defines the interface for meta extensions within the Black Eyed Creatures ecosystem. \n *      Meta extensions are modular contracts that provide additional token metadata for creatures, enhancing their attributes, \n *      appearance, or interactions within the ecosystem.\n * @notice Implementations of this interface should ensure that extensions are applied in a manner that is consistent with \n *         the ecosystem's rules and enhances the user experience.\n * @author https://42i.co\n */\ninterface IBECMetaExtension {\n\n  /**\n   * @notice Applies the meta extension to a creature and returns the additional metadata.\n   * @dev When implemented, this function should handle the logic for appending the creature's metadata based on the extension's purpose. \n   * @param _creatureId The unique identifier of the creature to which the extension is applied.\n   * @return string A string representing the modified or additional metadata for the creature.\n   */\n  function applyExtension(uint256 _creatureId) external view returns (string memory);\n}\n"
      },
      "contracts/mocks/BECCoreMock.sol": {
        "content": "// contracts/BECCoreMock.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n   /3333333    /33333333    /333333 \n  | 33__  33  | 33_____/   /33__  33\n  | 33  \\ 33  | 33        | 33  \\__/\n  | 3333333   | 33333     | 33      \n  | 33__  33  | 33__/     | 33      \n  | 33  \\ 33  | 33        | 33    33\n  | 3333333/  | 33333333  |  333333/\n  |_______/   |________/   \\______/ \n\n # http://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport \"../BECCore.sol\";\n\n/**\n * @title BECCore Mock contract\n * @dev This contract can be used as a mock for BECCore contract during tests.\n * @author https://42i.co\n */\ncontract BECCoreMock {\n  struct HuntMeta {\n    address owner;\n    uint256 tokenId;\n    bytes32 seed;\n  }\n\n  /// @dev Mapping between token id and hunt metadata related to that token\n  mapping(uint256 => HuntMeta) huntsMeta;\n\n  /**\n   * @dev Fills huntsMeta mapping with provided data\n   * @param _hunts hunt metadata to store\n   */\n  function fillHuntsMeta(HuntMeta[] memory _hunts) external {\n    for (uint i = 0; i < _hunts.length; i++) {\n      huntsMeta[_hunts[i].tokenId] = _hunts[i];\n    }\n  }\n\n  /**\n   * @notice Updates a token's dna\n   * @param _tokenId token id\n   * @param _seed new seed\n   */\n  function setSeed(uint256 _tokenId, bytes32 _seed) external {\n    huntsMeta[_tokenId].seed = _seed;\n  }\n\n  /**\n   * @notice Gets the seed of a token id\n   * @param _tokenId token id\n   * @return seed seed\n   */\n  function getSeed(uint256 _tokenId) external view returns (bytes32) {    \n    return huntsMeta[_tokenId].seed;\n  }\n\n  /**\n   * @notice Gets the seeds of a set of tokens ids\n   * @param _tokenIds token ids\n   * @return seeds array of token ids\n   */\n  function getSeeds(uint256[] calldata _tokenIds) external view returns (bytes32[] memory) {\n    bytes32[] memory seeds = new bytes32[](_tokenIds.length);\n    for (uint256 i = 0; i < _tokenIds.length; i++) {\n      seeds[i] = huntsMeta[_tokenIds[i]].seed;\n    }\n    return seeds;\n  }\n\n  /**\n   * @dev See {IERC721-ownerOf}.\n   */\n  function ownerOf(uint256 _tokenId) public view virtual returns (address) {\n    return huntsMeta[_tokenId].owner;\n  }\n\n  /**\n   * @dev See {@openzeppelin/contracts/access/AccessControl-grantRole}.\n   */\n  function grantRole(bytes32 role, address account) public virtual {}\n}\n"
      },
      "contracts/strategies/BECDnaStrategy.sol": {
        "content": "// contracts/strategies/BECDnaStrategy.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n    /3333333     /33333333     /333333    \n   | 33__  33   | 33_____/    /33__  33   \n   | 33  \\ 33   | 33         | 33  \\__/   \n   | 3333333    | 33333      | 33         \n   | 33__  33   | 33__/      | 33         \n   | 33  \\ 33   | 33         | 33    33   \n   | 3333333/   | 33333333   |  333333/   \n   |_______/    |________/    \\______/    \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {IBECDnaStrategy} from \"./IBECDnaStrategy.sol\";\nimport {BECCore} from \"../BECCore.sol\";\nimport {BECGenesisEngine} from \"../BECGenesisEngine.sol\";\nimport {BECLab} from \"../BECLab.sol\";\nimport {BECEnabler} from \"../BECEnabler.sol\";\nimport {IBECMetaExtension} from \"../meta-extensions/IBECMetaExtension.sol\";\nimport {Fate, FateLibrary} from \"../utils/Fate.sol\";\nimport {BECMetadata, BECMetadataLibrary} from \"./BECMetadataLibrary.sol\";\nimport {Strings} from \"@openzeppelin/contracts/utils/Strings.sol\";\nimport {Base64} from \"@openzeppelin/contracts/utils/Base64.sol\";\n\n/**\n * @title Black Eyed Creatures DNA Strategy Abstract Contract\n * @notice This strategy are the base abstrat strategy for the BECs metada.\n * @dev Manages common beheavior for all current BEC Strategies.\n * @author https://42i.co\n */\nabstract contract BECDnaStrategy is IBECDnaStrategy, BECEnabler {\n\n  /// @dev Using Fate Library\n  using FateLibrary for Fate;\n\n  /// @dev Using Metadata Library\n  using BECMetadataLibrary for BECMetadata;\n\n  /// @dev Core contract address.\n  address internal immutable coreContractAddress;\n\n  /// @dev Genesis engine contract address.\n  address internal immutable genesisEngineContractAddress;\n\n  /// @dev Lab contract address.\n  address internal immutable labContractAddress;\n\n  /// @dev Blcksphr contract address.\n  address internal immutable blcksphrContractAddress;\n\n  /// @dev Represents a packed storage of typeId, strategyId, and distributionId.\n  /// The packing is done as follows:\n  /// - typeId: 3 bits (least significant bits)\n  /// - strategyId: 5 bits (next bits after typeId)\n  /// - distributionId: 8 bits (next bits after strategyId)\n  uint256 internal immutable strategyLogs;\n\n  /// @dev A price for minting with this strategy.\n  uint256 internal price;\n\n  /**\n   * @notice Initializes the BEC DNA Strategy.\n   * @dev Sets the necesary data for this contract.\n   * @param _coreContractAddress The address of the BEC core contract.\n   * @param _genesisEngineContractAddress The address of the genesis engine contract.\n   */\n  constructor(\n    address _coreContractAddress,\n    address _genesisEngineContractAddress,\n    address _labContractAddress,\n    address _blcksphrContractAddress,\n    uint256 _strategyId,\n    uint256 _distributionId,\n    uint256 _typeId\n  ) {\n    coreContractAddress = _coreContractAddress;\n    genesisEngineContractAddress = _genesisEngineContractAddress;\n    labContractAddress = _labContractAddress;\n    blcksphrContractAddress = _blcksphrContractAddress;\n    price = 3 * 0.0001 ether;\n\n    strategyLogs = _typeId | (_strategyId << 3) | (_distributionId << 8);\n  }\n\n  /**\n   * @dev See {IBECDnaStrategy-getStrategyId}.\n   */\n  function getStrategyId() external view returns (uint256) {\n    return (strategyLogs >> 3) & 0x1F;\n  }\n\n  /**\n   * @dev See {IBECDnaStrategy-getDistributionId}.\n   */\n  function getDistributionId() external view returns (uint256) {\n    return (strategyLogs >> 8) & 0xFF;\n  }\n\n  /**\n   * @dev Obtains the trait for the specified phenotype and ticket value.\n   *      The traits are stored in the way: familyId (8b), variationId (8b).\n   * @param _phenotype The phenotype for which to retrieve the trait value.\n   * @param _value The value for which to retrieve the trait value.\n   * @param _distribution The distribution of tickets used for obtaining this traits.\n   * @return uint256 representing the phenotype traits value.\n   */\n  function getFamilyAndVariation(\n    uint256 _phenotype,\n    uint256 _value,\n    uint256 _distribution\n  ) internal view returns (uint256) {\n    BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineContractAddress));\n\n    uint256 family = 0;\n    uint256 accumulator = 0;\n    for (family = 0; ; family++) {\n      accumulator += genesisEngineContract.getFamilyTickets(_distribution, _phenotype, family);\n      if (_value < accumulator) {\n        accumulator -= genesisEngineContract.getFamilyTickets(_distribution, _phenotype, family);\n        break;\n      }\n    }\n\n    return getFamilyVariation(_phenotype, family, _value - accumulator, _distribution);\n  }\n\n  /**\n   * @notice Determines the variation for a creature based on its phenotype, family, ticket value, and distribution.\n   * @dev Calculates which variation a creature belongs to within a given phenotype and family,\n   *      based on a random value and the distribution of possibilities.\n   * @param _phenotype The phenotype index for which the family and variation are being determined.\n   * @param _value A pseudo-random value used to select the family and variation.\n   * @param _distribution The distribution ID used to determine the rarity and distribution of families and variations.\n   * @return uint256 representing the packed family and variation IDs.\n   */\n  function getFamilyVariation(\n    uint256 _phenotype,\n    uint256 _family,\n    uint256 _value,\n    uint256 _distribution\n  ) internal view returns (uint256) {\n    BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineContractAddress));\n\n    uint256 variation = 0;\n    uint256 accumulator = 0;\n\n    for (variation = 0; ; variation++) {\n      accumulator += genesisEngineContract.getVariationTickets(_distribution, _phenotype, _family, variation);\n      if (_value < accumulator) {\n        return ((variation << 8) + _family) << (_phenotype * 16);\n      }\n    }\n    revert(\"Value is out of range\");\n  }\n\n  /**\n   * @notice Retrieves the attributes for a creature based on its metadata.\n   * @dev This function should be overridden in derived contracts to generate and return the attributes\n   *      string that describes the visual traits and characteristics of the creature based on its DNA.\n   * @param _metadata The metadata structure containing information about the creature.\n   * @return string representing the attributes of the creature.\n   */\n  function getAttributes(BECMetadata memory _metadata) internal view virtual returns (string memory) {\n    return _metadata.getMetadataAttributes(getBackgroundColor(_metadata.dna), getSkinColor(_metadata.dna), getHairColor(_metadata.dna));\n  }\n\n  /**\n   * @notice Generates the token URI for a creature, containing its metadata.\n   * @dev Constructs a data URI that encodes the metadata of the creature in JSON format.\n   *      This metadata includes names, images, and other traits.\n   * @param _creatureId The ID of the creature whose token URI is being generated.\n   * @return string representing the data URI containing the creature's metadata.\n   */\n  function tokenURI(uint256 _creatureId) external view virtual returns (string memory) {\n    BECCore coreContract = BECCore(payable(coreContractAddress));\n    BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineContractAddress));\n    uint256 dna = genesisEngineContract.getDna(_creatureId);\n    BECMetadata memory metadata = BECMetadata(coreContractAddress, labContractAddress, genesisEngineContractAddress, _creatureId, dna);\n\n    string memory base = metadata.getMetadataBaseInformation(getHEXBackgroundColor(dna), coreContract.getSiteBaseURI());\n    string memory attributes = getAttributes(metadata);\n\n    return BECMetadataLibrary.getMetadataJson(base, attributes);\n  }\n\n  /**\n   * @notice Retrieves the HEX color code for the background based on the creature's DNA.\n   * @dev This function should be overridden in derived contracts to calculate and return the HEX color code for\n   *      the background of a creature's image or representation, based on its DNA.\n   * @param _dna The DNA of the creature, used to determine the background color.\n   * @return string representing the HEX color code for the background.\n   */\n  function getHEXBackgroundColor(uint256 _dna) internal view virtual returns (string memory);\n\n  /**\n   * @notice Retrieves the name or description of the background color based on the creature's DNA.\n   * @dev This function should be overridden in derived contracts to provide a human-readable name or description of\n   *      the background color, which could be used in the creature's metadata or displayed on a UI.\n   * @param _dna The DNA of the creature, used to determine the background color description.\n   * @return string representing the name or description of the background color.\n   */\n  function getBackgroundColor(uint256 _dna) internal view virtual returns (string memory);\n\n  /**\n   * @notice Retrieves the skin color attribute for a creature based on its DNA.\n   * @dev Intended to be overridden in derived contracts to calculate the creature's skin color attribute from its DNA.\n   *      This could influence the visual representation of the creature and be listed as part of its metadata.\n   * @param _dna The DNA of the creature, used to determine its skin color.\n   * @return string representing the skin color of the creature.\n   */\n  function getSkinColor(uint256 _dna) internal view virtual returns (string memory);\n\n  /**\n   * @notice Retrieves the hair color attribute for a creature based on its DNA.\n   * @dev Should be overridden in derived contracts to determine the creature's hair color from its DNA.\n   *      This attribute can be used in visual representations or included in the creature's metadata.\n   * @param _dna The DNA of the creature, which influences its hair color.\n   * @return string representing the hair color of the creature.\n   */\n  function getHairColor(uint256 _dna) internal view virtual returns (string memory);\n}\n"
      },
      "contracts/strategies/BECDnaType0Strategy.sol": {
        "content": "// contracts/strategies/BECDnaStrategy.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n    /3333333     /33333333     /333333    \n   | 33__  33   | 33_____/    /33__  33   \n   | 33  \\ 33   | 33         | 33  \\__/   \n   | 3333333    | 33333      | 33         \n   | 33__  33   | 33__/      | 33         \n   | 33  \\ 33   | 33         | 33    33   \n   | 3333333/   | 33333333   |  333333/   \n   |_______/    |________/    \\______/    \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {IBECDnaStrategy} from \"./IBECDnaStrategy.sol\";\nimport {BECDnaStrategy} from \"./BECDnaStrategy.sol\";\nimport {BECCore} from \"../BECCore.sol\";\nimport {BECGenesisEngine} from \"../BECGenesisEngine.sol\";\nimport {BECLab} from \"../BECLab.sol\";\nimport {BECEnabler} from \"../BECEnabler.sol\";\nimport {BECMetadataLibrary} from \"./BECMetadataLibrary.sol\";\n\n/**\n * @title Black Eyed Creatures DNA Type 0 Strategy Abstract Contract\n * @notice This strategy are the base abstrat strategy for the type 0 BECs metada.\n * @dev Manages common beheavior for all type 0 BEC Strategies.\n * @author https://42i.co\n */\nabstract contract BECDnaType0Strategy is BECDnaStrategy {\n\n  /**\n   * @notice Initializes a new Type0 Strategy contract.\n   * @param _coreContractAddress Address of the BEC core contract.\n   * @param _genesisEngineContractAddress Address of the genesis engine contract.\n   * @param _labContractAddress Address of the lab contract.\n   * @param _blcksphrsAddress Address of the Blcksphr contract.\n   * @param _strategyId Unique ID for this strategy.\n   * @param _distributionId ID representing the distribution logic for creature creation.\n   */\n  constructor(\n    address _coreContractAddress,\n    address _genesisEngineContractAddress,\n    address _labContractAddress,\n    address _blcksphrsAddress,\n    uint256 _strategyId,\n    uint256 _distributionId\n  )\n    BECDnaStrategy(\n      _coreContractAddress,\n      _genesisEngineContractAddress,\n      _labContractAddress,\n      _blcksphrsAddress,\n      _strategyId,\n      _distributionId,\n      0\n    )\n  {}\n\n  /**\n   * @dev See {BECDnaStrategy-getHEXBackgroundColor}.\n   */\n  function getHEXBackgroundColor(uint256 _dna) internal pure override returns (string memory) {\n    return BECMetadataLibrary.getType0HEXBackgroundColor(_dna);\n  }\n\n  /**\n   * @dev See {BECDnaStrategy-getBackgroundColor}.\n   */\n  function getBackgroundColor(uint256 _dna) internal pure override returns (string memory) {\n    return BECMetadataLibrary.getType0BackgroundColor(_dna);\n  }\n\n  /**\n   * @dev See {BECDnaStrategy-getSkinColor}.\n   */\n  function getSkinColor(uint256 _dna) internal pure override returns (string memory) {\n    return BECMetadataLibrary.getType0SkinColor(_dna);\n  }\n\n  /**\n   * @dev See {BECDnaStrategy-getHairColor}.\n   */\n  function getHairColor(uint256 _dna) internal pure override returns (string memory) {\n    return BECMetadataLibrary.getType0HairColor(_dna);\n  }\n}"
      },
      "contracts/strategies/BECMetadataLibrary.sol": {
        "content": "// contracts/strategies/BECMetadataLibrary.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n    /3333333     /33333333     /333333    \n   | 33__  33   | 33_____/    /33__  33   \n   | 33  \\ 33   | 33         | 33  \\__/   \n   | 3333333    | 33333      | 33         \n   | 33__  33   | 33__/      | 33         \n   | 33  \\ 33   | 33         | 33    33   \n   | 3333333/   | 33333333   |  333333/   \n   |_______/    |________/    \\______/    \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {BECCore} from \"../BECCore.sol\";\nimport {BECLab} from \"../BECLab.sol\";\nimport {BECGenesisEngine} from \"../BECGenesisEngine.sol\";\nimport {IBECMetaExtension} from \"../meta-extensions/IBECMetaExtension.sol\";\nimport {Strings} from \"@openzeppelin/contracts/utils/Strings.sol\";\nimport {Base64} from \"@openzeppelin/contracts/utils/Base64.sol\";\n\n/**\n * @notice Structure with the information needed for creating the metadata of a creature.\n * @dev Contains the addresses of the contracts, creatureId and dna.\n *      All the needed information in order to create the metadata.\n */\nstruct BECMetadata {\n  address coreContractAddress;\n  address labContractAddress;\n  address genesisEngineContractAddress;\n  uint256 creatureId;\n  uint256 dna;\n}\n\n/**\n * @notice Library providing utility functions for handling BEC metadata.\n * @dev Exports all shared functionality to a library to save gas with strings.\n */\nlibrary BECMetadataLibrary {\n\n  /**\n   * @notice Gets the different attribute names.\n   * @dev Obtains the trait names in an ordered array.\n   * @return string[6] An array with the different trait names.\n   */\n  function getTraitNames() public pure returns (string[6] memory) {\n    return [\"Body\", \"Head\", \"Ears\", \"Face\", \"Hair\", \"Eyes\"];\n  }\n\n  /**\n   * @notice Constructs the metadata trait information for a given phenotype and DNA.\n   * @dev Generates a JSON string representing the traits of a creature based on its phenotype and DNA value.\n   * @param _phenotype The phenotype for which traits are being generated.\n   * @return json A string in JSON format containing the trait information.\n   */\n  function getTraits(BECMetadata memory _self, uint256 _phenotype) public view returns (string memory json) {\n    BECLab labContract = BECLab(payable(_self.labContractAddress));\n    return\n      string(\n        abi.encodePacked(\n          '{\"trait_type\": \"',\n          getTraitNames()[_phenotype],\n          ' Family\", \"value\": \"',\n          labContract.getFamilyName(_phenotype, (_self.dna >> (16 * _phenotype)) & 0xFF),\n          '\"}, {\"trait_type\": \"',\n          getTraitNames()[_phenotype],\n          ' Variation\", \"value\": \"',\n          labContract.getVariationName(_phenotype, (_self.dna >> (16 * _phenotype)) & 0xFF, (_self.dna >> (16 * _phenotype + 8)) & 0xFF),\n          '\"}'\n        )\n      );\n  }\n\n  /**\n   * @notice Retrieves the generation information for a creature based on its ID.\n   * @dev Obtains and returns the generation information of a creature based on its ID,\n   *      calculated from the seed of the creature.\n   * @param _coreContractAddress The address of the BEC core contract.\n   * @param _creatureId The ID of the creature for which the generation information is being retrieved.\n   * @return json A json string representing the generation information of the creature.\n   */\n  function getGeneration(address _coreContractAddress, uint256 _creatureId) public view returns (string memory json) {\n    BECCore coreContract = BECCore(payable(_coreContractAddress));\n    bytes32 seed = coreContract.getSeed(_creatureId);\n    uint256 generation = (uint256(seed) >> 246) & 0x3;\n    return string(abi.encodePacked('{\"trait_type\": \"Generation\", \"value\": \"', Strings.toString(generation), '\" }'));\n  }\n\n  /**\n   * @notice Retrieves the omegas information for a creature based on its ID.\n   * @dev Obtains and returns the omegas information of a creature based on its ID,\n   *      retrieved from the lab contract.\n   * @param _labContractAddress The address of the BEC lab contract.\n   * @param _creatureId The ID of the creature for which the omegas information is being retrieved.\n   * @return json A json string representing the omegas information of the creature.\n   */\n  function getOmegas(address _labContractAddress, uint256 _creatureId) internal view returns (string memory json) {\n    BECLab labContract = BECLab(payable(_labContractAddress));\n    return string(abi.encodePacked('{\"trait_type\": \"Omegas\", \"value\": \"',Strings.toString(labContract.getOmegas(_creatureId)),'\" }'));\n  }\n\n  /**\n   * @notice Retrieves the fertility status for a creature based on its ID.\n   * @dev Obtains and returns the fertility status of a creature based on its ID,\n   *      based in game logic.\n   * @param _coreContractAddress The address of the BEC core contract.\n   * @param _labContractAddress The address of the BEC lab contract.\n   * @param _creatureId The ID of the creature for which the omegas information is being retrieved.\n   * @return json A json string representing the omegas information of the creature.\n   */\n  function getFertility(address _coreContractAddress, address _labContractAddress, uint256 _creatureId) internal view returns (string memory json) {\n    BECCore coreContract = BECCore(payable(_coreContractAddress));\n    BECLab labContract = BECLab(payable(_labContractAddress));\n    bytes32 seed = coreContract.getSeed(_creatureId);\n    uint256 genSeed = (uint256(seed) >> 246) & 0x3;\n    uint256 omegas = labContract.getOmegas(_creatureId);\n    string memory status;\n    if (genSeed > 2) status = \"Fruitless\"; \n    else if (omegas == 0) status = \"Virgin\"; \n    else if (omegas == 9) status = \"Depleted\";\n    else status = \"Primed\";\n    return string(abi.encodePacked('{\"trait_type\": \"Fertility\", \"value\": \"',status,'\" }'));\n  }\n\n  /**\n   * @notice Generates the image data URL for a creature based on its ID.\n   * @dev Constructs a URL pointing to the creature's image resource.\n   *      The URL structure is determined by the base URI of the core contract and the creature's unique identifier.\n   * @param _creatureId The ID of the creature whose image URL is being generated.\n   * @return uri A string representing the URL to the creature's image.\n   */\n  function getImageURI(uint256 _creatureId, address _coreContractAddress) public view returns (string memory uri) {\n    BECCore coreContract = BECCore(payable(_coreContractAddress));\n    return coreContract.getImageURI(_creatureId);\n  }\n\n  /**\n   * @notice Generates an external URL for the creature image.\n   * @dev Constructs a URL that points to an external file containing the image of the creature.\n   * @param _creatureId The ID of the creature for which the external URL is being generated.\n   * @param _baseURI The external base URL.\n   * @return uri A string representing the external URL.\n   */\n  function getExternalURI(uint256 _creatureId, string memory _baseURI) public pure returns (string memory uri) {\n    return string(abi.encodePacked(_baseURI, \"creatures/\", Strings.toString(_creatureId)));\n  }\n\n  /**\n   * @notice Generates the metadata JSON for a creature.\n   * @dev Constructs and encodes the metadata JSON for a creature based on the provided base and attributes.\n   *      The JSON includes the base information and attributes array.\n   * @param _base The base information JSON string for the creature.\n   * @param _attributes The attributes JSON string for the creature.\n   * @return json A string representing the complete metadata JSON.\n   */\n  function getMetadataJson(string memory _base, string memory _attributes) public pure returns (string memory json) {\n    json = Base64.encode(bytes(abi.encodePacked(\"{\", _base, '\"attributes\": [', _attributes, \"]\", \"}\")));\n    json = string(abi.encodePacked(\"data:application/json;base64,\", json));\n  }\n  \n  /**\n   * @notice Constructs the metadata base information for a given creature.\n   * @dev Generates and returns the base information for the metadata of a creature,\n   *      including its name, image URI, background color, and external URL.\n   * @param _self The BECMetadata struct.\n   * @param hexBgColor The hexadecimal representation of the background color.\n   * @param _baseURI The base URI for external URLs.\n   * @return json A json part string representing the base information of the metadata.\n   */\n  function getMetadataBaseInformation(BECMetadata memory _self, string memory hexBgColor, string memory _baseURI) public view returns (string memory json) {\n    BECLab labContract = BECLab(payable(_self.labContractAddress));\n    return\n      string(\n        abi.encodePacked(\n          '\"name\": \"',\n          labContract.getCreatureName(_self.creatureId),\n          '\",',\n          '\"image\": \"',\n          getImageURI(_self.creatureId, _self.coreContractAddress),\n          '\",',\n          '\"background_color\": \"',\n          hexBgColor,\n          '\",',\n          '\"external_url\": \"',\n          getExternalURI(_self.creatureId, _baseURI),\n          '\",'\n        )\n      );\n  }\n\n  /**\n   * @notice Constructs the metadata attributes for a given creature.\n   * @dev Generates and returns the attributes for the metadata of a creature,\n   *      including its traits, background color, skin color, hair color, generation, omegas, and any additional extensions.\n   * @param _self The BECMetadata struct.\n   * @param _bgColor The background color attribute.\n   * @param _skinColor The skin color attribute.\n   * @param _hairColor The hair color attribute.\n   * @return json A json string representing the metadata attributes.\n   */\n  function getMetadataAttributes(BECMetadata memory _self, string memory _bgColor, string memory _skinColor, string memory _hairColor) public view returns (string memory json) {\n    BECLab labContract = BECLab(payable(_self.labContractAddress));\n    string memory attrs = getTraits(_self, 0);\n    attrs = string(abi.encodePacked(attrs, \",\", getTraits(_self, 1)));\n    attrs = string(abi.encodePacked(attrs, \",\", getTraits(_self, 2)));\n    attrs = string(abi.encodePacked(attrs, \",\", getTraits(_self, 3)));\n    attrs = string(abi.encodePacked(attrs, \",\", getTraits(_self, 4)));\n    attrs = string(abi.encodePacked(attrs, \",\", getTraits(_self, 5)));\n    attrs = string(abi.encodePacked(attrs, \",\", _bgColor));\n    attrs = string(abi.encodePacked(attrs, \",\", _skinColor));\n    attrs = string(abi.encodePacked(attrs, \",\", _hairColor));\n\n    attrs = string(abi.encodePacked(attrs, \",\", getGeneration(_self.coreContractAddress, _self.creatureId)));\n    attrs = string(abi.encodePacked(attrs, \",\", getOmegas(_self.labContractAddress, _self.creatureId)));\n    attrs = string(abi.encodePacked(attrs, \",\", getFertility(_self.coreContractAddress, _self.labContractAddress, _self.creatureId)));\n\n    uint256 labRecord = labContract.getLabRegistryRecord(_self.creatureId);\n    if (labRecord & 1 == 1) {\n      attrs = string(\n        abi.encodePacked(\n          attrs,\n          ',{\"value\": \"Variation Ambassador\" }, { \"trait_type\": \"Ambassador Phenotype\", \"value\": \"',\n          getTraitNames()[(labRecord >> 2) & 0x7],\n          '\" }, { \"trait_type\": \"Variation Ambassador Family\", \"value\": \"',\n          labContract.getFamilyName((labRecord >> 2) & 0x7, (labRecord >> 5) & 0x1F),\n          '\" }, { \"trait_type\": \"Variation Ambassador Name\", \"value\": \"',\n          labContract.getVariationName((labRecord >> 2) & 0x7, (labRecord >> 5) & 0x1F, (labRecord >> 10) & 0x3F),\n          '\" }'\n        )\n      );\n    }\n    if ((labRecord >> 1) & 1 == 1) {\n      attrs = string(\n        abi.encodePacked(\n          attrs,\n          ',{\"value\": \"Family Ambassador\" }, { \"trait_type\": \"Family Ambassador Name\", \"value\": \"',\n          labContract.getFamilyName((labRecord >> 2) & 0x7, (labRecord >> 5) & 0x1F),\n          '\" }'\n        )\n      );\n    }\n\n    // Get the extensions array from genesis engine\n    BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(_self.genesisEngineContractAddress));\n    IBECMetaExtension[] memory extensions = genesisEngineContract.getExtensions();\n\n    // Iterate over extensions and apply them\n    for (uint i = 0; i < extensions.length; i++) {\n      attrs = string(abi.encodePacked(attrs, extensions[i].applyExtension(_self.creatureId)));\n    }\n\n    return attrs;\n  }\n\n  /**\n   * @notice Retrieves the HEX background color for a creature of type 0 based on its DNA.\n   * @dev Calculates and returns the HEX background color for a creature of type 0 based on its DNA.\n   * @param _dna The DNA of the creature.\n   * @return json A json string representing the HEX background color.\n   */\n  function getType0HEXBackgroundColor(uint256 _dna) public pure returns (string memory json) {\n    string[13] memory bgColors = [\n      \"#3E4866\", //  0 Sapphire Fiord\n      \"#433E66\", //  1 Mulled Wine\n      \"#583E66\", //  2 Voodoo\n      \"#663E60\", //  3 Blueberry Eggplant\n      \"#663E48\", //  4 Burgundy Eggplant\n      \"#66483E\", //  5 Kabul\n      \"#66583E\", //  6 Tabacco Brown\n      \"#60663E\", //  7 Helmlock\n      \"#52663E\", //  8 Green Chalet\n      \"#43663E\", //  9 Tom Thumb\n      \"#3E6660\", // 10 William\n      \"#3E5866\", // 11 Deepwater Fiord\n      \"#747486\"  // 12 Storm Gray\n    ];\n\n    return string(abi.encodePacked(bgColors[(_dna >> (13 * 8)) & 0xFF]));\n  }\n\n  /**\n   * @notice Retrieves the background color name for a creature of type 0 based on its DNA.\n   * @dev Determines and returns the name of the background color for a creature of type 0 based on its DNA.\n   * @param _dna The DNA of the creature.\n   * @return json A json string representing the background color name.\n   */\n  function getType0BackgroundColor(uint256 _dna) public pure returns (string memory json) {\n    string[13] memory bgColors = [\n      \"Sapphire Fiord\",\n      \"Mulled Wine\",\n      \"Voodoo\",\n      \"Blueberry Eggplant\",\n      \"Burgundy Eggplant\",\n      \"Kabul\",\n      \"Tabacco Brown\",\n      \"Helmlock\",\n      \"Green Chalet\",\n      \"Tom Thumb\",\n      \"William\",\n      \"Deepwater Fiord\",\n      \"Storm Gray\"\n    ];\n\n    return string(abi.encodePacked('{\"trait_type\": \"Background Color\", \"value\": \"', bgColors[(_dna >> (13 * 8)) & 0xFF], '\"}'));\n  }\n\n  /**\n   * @notice Retrieves the skin color attribute for a creature of type 0 based on its DNA.\n   * @dev Determines and returns the skin color attribute for a creature of type 0 based on its DNA.\n   * @param _dna The DNA of the creature.\n   * @return json A json string representing the skin color attribute.\n   */\n  function getType0SkinColor(uint256 _dna) public pure returns (string memory json) {\n    string[13] memory skinColors = [\n      \"East Bay\",\n      \"Victoria\",\n      \"Affair\",\n      \"Cannon Pink\",\n      \"Tosca\",\n      \"Spicy Mix\",\n      \"Soil Sycamore\",\n      \"Leaf Sycamore\",\n      \"Fern Green\",\n      \"Goblin\",\n      \"Viridian\",\n      \"Ming\",\n      \"Green Spring\"\n    ];\n\n    return string(abi.encodePacked('{\"trait_type\": \"Skin Color\", \"value\": \"', skinColors[(_dna >> (15 * 8)) & 0xFF], '\"}'));\n  }\n\n  /**\n   * @notice Retrieves the hair color attribute for a creature of type 0 based on its DNA.\n   * @dev Determines and returns the hair color attribute for a creature of type 0 based on its DNA.\n   * @param _dna The DNA of the creature.\n   * @return json A json string representing the hair color attribute.\n   */\n  function getType0HairColor(uint256 _dna) public pure returns (string memory json) {\n    string[13] memory hairColors = [\n      \"Glacier\",\n      \"Blue Marguerite\",\n      \"Amethyst\",\n      \"Fuchsia Pink\",\n      \"Puce\",\n      \"Contessa\",\n      \"Laser\",\n      \"Wild Willow\",\n      \"Olivine\",\n      \"De York\",\n      \"Monte Carlo\",\n      \"Half Baked\",\n      \"Silver Chalice\"\n    ];\n\n    return string(abi.encodePacked('{\"trait_type\": \"Hair Color\", \"value\": \"', hairColors[(_dna >> (17 * 8)) & 0xFF], '\"}'));\n  }\n}\n"
      },
      "contracts/strategies/GoldenDnaStrategy.sol": {
        "content": "// contracts/strategies/GoldenDnaStrategy.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n   /3333333    /33333333    /333333 \n  | 33__  33  | 33_____/   /33__  33\n  | 33  \\ 33  | 33        | 33  \\__/\n  | 3333333   | 33333     | 33      \n  | 33__  33  | 33__/     | 33      \n  | 33  \\ 33  | 33        | 33    33\n  | 3333333/  | 33333333  |  333333/\n  |_______/   |________/   \\______/ \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {BECCore} from \"../BECCore.sol\";\nimport {BECDnaStrategy} from \"./BECDnaStrategy.sol\";\nimport {BECGenesisEngine} from \"../BECGenesisEngine.sol\";\nimport {EIP712} from \"../eip712/EIP712.sol\";\nimport {IERC721} from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\nimport {ECDSA} from \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport {Fate, FateLibrary} from \"../utils/Fate.sol\";\nimport {BECMetadata} from \"./BECMetadataLibrary.sol\";\n\n/**\n * @title Golden DNA Strategy for Black Eyed Creatures\n * @notice Implements the strategy for generating \"Golden\" creatures within the Black Eyed Creatures ecosystem.\n *         This strategy extends the Type 1 DNA strategy to introduce unique golden creatures with special traits and attributes.\n * @dev This contract utilizes the Fate library for deterministic randomness in creature generation and supports\n *      EIP-712 based signatures for verifying actions.\n *      It manages golden creature generation, including domain-specific metadata for phenotype variations and family counts.\n * @author https://42i.co\n */\ncontract GoldenDnaStrategy is BECDnaStrategy, EIP712 {\n  /// @dev Using Fate Library\n  using FateLibrary for Fate;\n\n  /// @dev Using Elliptic Curve Digital Signature Algorithm (ECDSA)\n  using ECDSA for bytes32;\n\n  /// @dev A nested mapping structure storing bitwise the amount of families and variatios of each phenotype within a domain.\n  /// The outer mapping is indexed by [domain], and the inner mapping by [phenotype].\n  /// The uint256 associated with each [domain][phenotype] contains:\n  ///   - familiesCount (8b): The number of families within that phenotype.\n  ///   - variationsCount (8b): 8-bit segments, each representing the number of variations for a family in the phenotype.\n  mapping(uint256 domain => mapping(uint256 phenotype => uint256 metaRegistry)) domainMeta;\n\n  /// @dev tokenId => list of delta values\n  mapping(uint256 goldenId => bytes deltas) public deltas;\n\n  /// @dev An array to store tokenIds\n  uint256[] public goldenIds;\n\n  // The typehash for the data type specified in the structured data\n  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-typehash\n  bytes32 public constant GOLDEN_TYPEHASH = keccak256(\"GetGolden(uint256 lastGolden,bytes deltas,address wallet)\");\n\n  /**\n   * @notice Initializes a new Golden DNA Strategy instance.\n   * @param _coreContractAddress Address of the BEC core contract.\n   * @param _genesisEngineContractAddress Address of the Genesis Engine contract.\n   * @param _labContractAddress Address of the Lab contract.\n   * @param _blcksphrsAddress Address of the Blcksphrs contract.\n   * @param _strategyId Unique ID for this strategy.\n   * @param _distributionId ID indicating the distribution logic for this strategy.\n   */\n  constructor(\n    address _coreContractAddress,\n    address _genesisEngineContractAddress,\n    address _labContractAddress,\n    address _blcksphrsAddress,\n    uint256 _strategyId,\n    uint256 _distributionId\n  )\n    BECDnaStrategy(\n      _coreContractAddress,\n      _genesisEngineContractAddress,\n      _labContractAddress,\n      _blcksphrsAddress,\n      _strategyId,\n      _distributionId,\n      1\n    )\n  {}\n\n  /**\n   * @notice Retrieves the information for a given domain and phenotype.\n   * @dev The metadata includes the count of families and variations for each phenotype within a domain.\n   * @param _domain The domain ID for which metadata is being retrieved.\n   * @param _phenotype The phenotype ID within the domain.\n   * @return uint256 The metadata value associated with the specified domain and phenotype.\n   */\n  function getDomainMeta(uint256 _domain, uint256 _phenotype) public view returns (uint256) {\n    return domainMeta[_domain][_phenotype];\n  }\n\n  /**\n   * @notice Adds a new domain with its associated metadata to the contract.\n   * @dev This function updates the `domainMeta` mapping with the count of families and variations\n   *      for each phenotype within the new domain. Can only be called by an account with the GENETICIST role.\n   * @param _domain The domain ID to be added.\n   * @param _newDomain An array of metadata values for the new domain, where each value corresponds to a phenotype.\n   */\n  function addDomain(uint256 _domain, uint256[] memory _newDomain) public onlyOwner {\n    if (domainMeta[_domain][0] != 0) revert BECDomainAlreadySet(_domain);\n    for (uint256 i = 0; i < _newDomain.length; i++) {\n      domainMeta[_domain][i] = _newDomain[i];\n    }\n  }\n\n  /**\n   * @notice Sets a new signing key for the allowlist.\n   * @dev Updates the signing key used to validate signatures for certain privileged operations, such as minting golden creatures.\n   *      This function can only be called by an account with the GENETICIST role, ensuring that only authorized personnel can change the signing key.\n   * @param newSigningKey The new public address to be used as the signing key.\n   */\n  function setAllowlistSigningAddress(address newSigningKey) public onlyOwner {\n    _setAllowlistSigningAddress(newSigningKey);\n  }\n\n  /**\n   * @dev See {IBECDnaStrategy-getDna}.\n   */\n  function getDna(uint256 _creatureId) external view override returns (uint256 dna) {\n    BECCore coreContract = BECCore(payable(coreContractAddress));\n    BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineContractAddress));\n\n    bytes32 seed = coreContract.getSeed(_creatureId);\n    Fate memory prophecy = FateLibrary.initiate(keccak256(abi.encodePacked(seed, _creatureId)));\n\n    dna = 0;\n    for (uint256 phenotype = 0; phenotype < 6; phenotype++) {\n      // Obtains the phenotype tickets bitwise.\n      uint256 phenotypeTickets = (genesisEngineContract.getPhenotypeTickets(1) >> (phenotype * 32)) & 0xFFFFFFFF;\n      uint256 winnerTicket = prophecy.pathWithin(phenotypeTickets);\n      dna += getFamilyAndVariation(phenotype, winnerTicket, 1);\n    }\n    for (uint256 colorPhenotype = 0; colorPhenotype < 3; colorPhenotype++) {\n      // Sets the color traits to 1,0\n      dna += 1 << ((colorPhenotype + 6) * 16);\n    }\n\n    dna += 1 << 248; // set type to golden\n  }\n\n  /**\n   * @notice Verifies if a candidate creature is not part of the golden deltas, ensuring it hasn't been awakened.\n   * @dev Iterates through the delta values to check if the candidate's ID matches any delta, indicating it has been awakened.\n   * @param _ids Array of creature IDs to check.\n   * @param candidatesIndex Index of the current candidate in the _ids array.\n   * @param data The delta data for comparison.\n   * @param numberOfDeltas The number of deltas to consider in the verification.\n   * @param deltaBits The bit length of each delta value.\n   * @return bool True if the candidate is not part of the golden deltas, false otherwise.\n   */\n  function verifyCandidateNotInGoldenDeltas(\n    uint256[] calldata _ids,\n    uint256 candidatesIndex,\n    bytes memory data,\n    uint256 numberOfDeltas,\n    uint256 deltaBits\n  ) public pure returns (bool) {\n    uint256 bitPosition = 16; // First 16 bits processed for protocol, deltaBits, and numberOfDeltas\n    uint256 current = 0;\n\n    for (uint256 i = 0; i < numberOfDeltas; i++) {\n      uint256 delta = extractBits(data, bitPosition, deltaBits);\n      current += delta;\n      bitPosition += deltaBits;\n      if (_ids[candidatesIndex] == current) {\n        return false; // At least one is awaken\n      }\n    }\n\n    return true;\n  }\n\n  /**\n   * @notice Verifies if a specific candidate creature has not been awakened based on golden deltas.\n   * @dev Utilizes `verifyCandidateNotInGoldenDeltas` to check against all stored golden deltas for the candidate's presence.\n   * @param _ids Array of creature IDs to check.\n   * @param candidatesIndex Index of the current candidate in the _ids array.\n   * @return bool True if the candidate has not been awakened, false otherwise.\n   */\n  function verifyCantidateNotAwaken(uint256[] calldata _ids, uint256 candidatesIndex) public view returns (bool) {\n    for (uint256 goldenIndex = 0; goldenIndex < goldenIds.length; goldenIndex++) {\n      bytes memory data = deltas[goldenIds[goldenIndex]];\n      if (data.length == 0) revert BECEmptyGoldenDataArray();\n\n      // Extract the protocol bit (not used in this function, but for completeness)\n      uint256 protocolBit = extractBits(data, 0, 1); // Cast bytes1 to uint256\n\n      // Ensure it's the correct protocol\n      if (protocolBit != 0) revert BECInvalidProtocolBit();\n\n      uint256 deltaBits = extractBits(data, 1, 6); // Extract 6 bits starting from the second bit\n      uint256 numberOfDeltas = extractBits(data, 7, 9); // Extract 9 bits starting from the ninth bit\n      if (!verifyCandidateNotInGoldenDeltas(_ids, candidatesIndex, data, numberOfDeltas, deltaBits)) {\n        return false; // At least one is awaken\n      }\n    }\n    return true;\n  }\n\n  /**\n   * @notice Verifies if none of the specified creatures have been awakened.\n   * @dev Calls `verifyCantidateNotAwaken` for each creature ID in the provided array to ensure none are part of the golden deltas.\n   * @param _ids Array of creature IDs to check.\n   * @return bool True if none of the creatures have been awakened, false otherwise.\n   */\n  function verifyNotAwaken(uint256[] calldata _ids) public view returns (bool) {\n    for (uint256 candidatesIndex = 0; candidatesIndex < _ids.length; candidatesIndex++) {\n      if (!verifyCantidateNotAwaken(_ids, candidatesIndex)) {\n        return false; // At least one is awaken\n      }\n    }\n    return true; // No one is awaken\n  }\n\n  /**\n   * @notice Generate the family variations flags set for a given phenotype and family. A variation is flagged if it is present in the provided creatures.\n   * @dev The value is returned as a bitwise flag, where each bit represents a variation within the family.\n   * @param dnas Array of creature DNA values to use for the verification.\n   * @param phenotype The phenotype ID for which to retrieve variations flags.\n   * @param family The family ID within the phenotype.\n   * @param familyVariationsCount The number of variations within the family.\n   * @return uint256 The variations flags for the specified phenotype and family.\n   */\n  function generateVariationsFlags(\n    uint256[] memory dnas,\n    uint256 phenotype,\n    uint256 family,\n    uint256 familyVariationsCount\n  ) private pure returns (uint256) {\n    uint256 variationsFlags = 0;\n    for (uint256 i = 0; i < dnas.length; i++) {\n      uint256 dnaFamily = (dnas[i] >> (phenotype * 16)) & 0xFF;\n\n      if (dnaFamily == family) {\n        uint256 dnaVariation = (dnas[i] >> ((phenotype * 16) + 8)) & 0xFF;\n        variationsFlags |= (1 << dnaVariation);\n\n        // Optimization: If all variations are flagged, break out.\n        if ((variationsFlags & ((1 << familyVariationsCount) - 1)) == ((1 << familyVariationsCount) - 1)) {\n          break;\n        }\n      }\n    }\n\n    return variationsFlags;\n  }\n\n  /**\n   * @notice Verifies if all variations of a given phenotype and family are present in the provided creatures.\n   * @param dnas Array of creature DNA values to use for the verification.\n   * @param phenotype The phenotype ID for which to verify variations.\n   * @param phenotypeFamilies The number of families within the phenotype.\n   */\n  function verifyAllFamilyVariationsPresent(\n    uint256[] memory dnas,\n    uint256 phenotype,\n    uint256 phenotypeFamilies\n  ) private view {\n    for (uint256 family = 0; family < phenotypeFamilies; family++) {\n      uint256 familyVariationsCount = uint8((getDomainMeta(0, phenotype) >> (8 * (family + 1))) & 0xFF);\n      uint256 variationsFlags = generateVariationsFlags(dnas, phenotype, family, familyVariationsCount);\n\n      // Check if all variations in familyVariationsCount were flagged.\n      if ((variationsFlags & ((1 << familyVariationsCount) - 1)) != ((1 << familyVariationsCount) - 1)) revert BECNotAllVariationsPresent();\n    }\n  }\n\n  /**\n   * @notice Gets the dna for the ids provided.\n   * @dev Verifies that the provided creature IDs are owned by the caller and returns their DNA values.\n   * @param _ids Array of creature IDs to use for the verification.\n   * @return uint256[] The DNA values for the specified creature IDs.\n   */\n  function getOwnedCreaturesDnas(uint256[] calldata _ids) private view returns (uint256[] memory) {\n    BECCore coreContract = BECCore(payable(coreContractAddress));\n    BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineContractAddress));\n\n    uint256 previousId = 0;\n    // Gets the dna of every id.\n    uint256[] memory dnas = new uint256[](_ids.length);\n    for (uint256 i = 0; i < dnas.length; i++) {\n      dnas[i] = genesisEngineContract.getDna(_ids[i]);\n\n      // Verify all ids are in order\n      if (!(i == 0 || (i > 0 && previousId < _ids[i]))) revert BECIdsNotInOrder();\n      if (coreContract.ownerOf(_ids[i]) != msg.sender) revert BECInvalidOwner(msg.sender, _ids[i]);\n\n      previousId = _ids[i];\n    }\n\n    return dnas;\n  }\n\n  /**\n   * @notice Verifies if all family variations are present in the provided creatures.\n   * @param _ids Array of creature IDs to use for the verification.\n   * @return bool True if all family variations are present, false otherwise.\n   */\n  function verifyAllFamilyVarationsCompleted(uint256[] calldata _ids) public view returns (bool) {\n    uint256[] memory dnas = getOwnedCreaturesDnas(_ids);\n\n    for (uint256 phenotype = 0; phenotype < 6; phenotype++) {\n      uint256 phenotypeFamilies = getDomainMeta(0, phenotype) & 0xFF;\n      verifyAllFamilyVariationsPresent(dnas, phenotype, phenotypeFamilies);\n    }\n\n    return true;\n  }\n\n  /**\n   * @notice Verifies if the specified creatures can form a valid golden creature.\n   * @dev Ensures that all provided creature IDs represent a complete set of variations across all families for a given phenotype, and that none have been previously awakened.\n   * @param _ids Array of creature IDs to use for the verification.\n   * @return bool True if the creatures can form a golden creature, false otherwise.\n   */\n  function verifyGolden(uint256[] calldata _ids) public view returns (bool) {\n    if (_ids.length > 480) revert BECMoreCreaturesThanPhenotypes();\n    if (!verifyNotAwaken(_ids)) revert BECAlreadyAwaken();\n    verifyAllFamilyVarationsCompleted(_ids);\n    return true;\n  }\n\n  /**\n   * @notice Retrieves the last golden ID created.\n   * @dev Iterates through `goldenIds` to find the highest tokenId, indicating the most recently created golden creature.\n   * @return uint256 The highest tokenId among golden creatures.\n   */\n  function getLastGoldenId() public view returns (uint256) {\n    uint256 maxId = 0;\n    for (uint i = 0; i < goldenIds.length; i++) {\n      if (goldenIds[i] > maxId) {\n        maxId = goldenIds[i];\n      }\n    }\n    return maxId;\n  }\n\n  /**\n   * @notice Generates a golden creature based on provided deltas and a signature.\n   * @dev Validates the provided signature against the expected format and content, then mints a new golden creature if valid.\n   *      Updates `deltas` and `goldenIds` accordingly.\n   * @param _deltas The delta values to use for the golden creature generation.\n   * @param _signature A signature to validate the request.\n   * @return uint256[] An array containing the tokenId of the newly created golden creature.\n   */\n  function getGoldenBEC(bytes calldata _deltas, bytes calldata _signature) public returns (uint256[] memory) {\n    if (!enabled) revert BECNotEnabled();\n    if (goldenIds.length > 2) revert BECCapLimitReached();\n    BECCore coreContract = BECCore(payable(coreContractAddress));\n\n    // Validate Signature\n    // Add `previous golden token id (if exists)` in the signature (for avoiding hacks)\n    uint256 lastGolden = getLastGoldenId();\n    if (!validateGoldenSignature(lastGolden, _deltas, _signature)) revert EIP712InvalidSignature(_signature);\n\n    unchecked {\n      uint256 nextTokenId = coreContract.nextTokenId();\n      // Check if it's a new tokenId\n      if (deltas[nextTokenId].length != 0) revert BECNotEmptyGoldenDeltasArray();\n\n      goldenIds.push(nextTokenId);\n\n      deltas[nextTokenId] = _deltas;\n      // Calculate the golden seed\n      bytes32 seedValue = keccak256(abi.encodePacked(address(this), block.number, nextTokenId, _deltas));\n\n\n      // Clear the first 10 bits of seedValue, Set type, strategy and generation of the new creature.\n      seedValue &= bytes32(~(uint256(0x3FF) << 246)); // 246 = 256-10\n      seedValue |= bytes32(uint256(strategyLogs & 0xFF) << 248);\n\n      return coreContract.mintWithSeed(msg.sender, seedValue, 1);\n    }\n  }\n\n  /**\n   * @notice Validates the signature for a golden creature generation request.\n   * @dev Uses EIP-712 signing standard to verify the signature against the expected message format and content,\n   *      including the last golden tokenId, deltas, and the caller's address.\n   * @param _lastGolden The last golden tokenId created.\n   * @param _deltas The delta values for the golden creature generation.\n   * @param _signature The signature to validate.\n   * @return bool True if the signature is valid, false otherwise.\n   */\n  function validateGoldenSignature(\n    uint256 _lastGolden,\n    bytes calldata _deltas,\n    bytes calldata _signature\n  ) internal view returns (bool) {\n    if (allowlistSigningKey == address(0)) revert EIP712BECSigningKeyNotSet();\n\n    bytes32 digest = keccak256(\n      abi.encodePacked(\n        \"\\x19\\x01\",\n        EIP712_DOMAIN_SEPARATOR,\n        keccak256(abi.encode(GOLDEN_TYPEHASH, _lastGolden, keccak256(abi.encodePacked(_deltas)), msg.sender))\n      )\n    );\n\n    address recoveredAddress = digest.recover(_signature);\n    return recoveredAddress == allowlistSigningKey;\n  }\n\n  /**\n   * @notice Extracts a sequence of bits from a byte array starting at a specific bit position.\n   * @dev This function is used to decode values from the compact delta encoding used for golden creatures.\n   *      It supports extracting values of arbitrary bit lengths, useful for decoding the delta values stored in `deltas`.\n   * @param _data The byte array from which to extract bits.\n   * @param _start The starting bit position in the array.\n   * @param _length The number of bits to extract.\n   * @return uint256 The extracted bits as a uint256 value.\n   */\n  function extractBits(bytes memory _data, uint256 _start, uint256 _length) internal pure returns (uint256) {\n    if (_start + _length > _data.length * 8) revert BECIndexOutOfBounds();\n    uint256 result = 0;\n    for (uint256 i = 0; i < _length; i++) {\n      uint256 bitPosition = _start + i;\n      if ((uint8(_data[bitPosition / 8]) & (1 << (7 - (bitPosition % 8)))) != 0) {\n        if (_length - i == 1) {\n          result |= 1;\n        } else {\n          result |= (1 << (_length - 1 - i));\n        }\n      }\n    }\n    return result;\n  }\n\n  /**\n   * @dev See {BECDnaStrategy-getAttributes}.\n   */\n  function getAttributes(BECMetadata memory _metadata) internal view override returns (string memory) {\n    return string(abi.encodePacked(super.getAttributes(_metadata), ',{\"value\": \"Golden\"}'));\n  }\n\n  /**\n   * @dev See {BECDnaStrategy-getHEXBackgroundColor}.\n   */\n  function getHEXBackgroundColor(uint256 /* _dna */) internal pure override returns (string memory) {\n    return string(abi.encodePacked(\"#BD656E\"));\n  }\n\n  /**\n   * @dev See {BECDnaStrategy-getBackgroundColor}.\n   */\n  function getBackgroundColor(uint256 /* _dna */) internal pure override returns (string memory) {\n    return string(abi.encodePacked('{\"trait_type\": \"Background Color\", \"value\": \"Golden Matrix\"}'));\n  }\n\n  /**\n   * @dev See {BECDnaStrategy-getSkinColor}.\n   */\n  function getSkinColor(uint256 /* _dna */) internal pure override returns (string memory) {\n    return string(abi.encodePacked('{\"trait_type\": \"Skin Color\", \"value\": \"Golden Grass\"}'));\n  }\n\n  /**\n   * @dev See {BECDnaStrategy-getHairColor}.\n   */\n  function getHairColor(uint256 /* _dna */) internal pure override returns (string memory) {\n    return string(abi.encodePacked('{\"trait_type\": \"Hair Color\", \"value\": \"Fountain Blue\"}'));\n  }\n}\n"
      },
      "contracts/strategies/HuntDnaStrategy.sol": {
        "content": "// contracts/strategies/HuntDnaStrategy.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n   /3333333    /33333333    /333333 \n  | 33__  33  | 33_____/   /33__  33\n  | 33  \\ 33  | 33        | 33  \\__/\n  | 3333333   | 33333     | 33      \n  | 33__  33  | 33__/     | 33      \n  | 33  \\ 33  | 33        | 33    33\n  | 3333333/  | 33333333  |  333333/\n  |_______/   |________/   \\______/ \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {BECCore} from \"../BECCore.sol\";\nimport {BECDnaType0Strategy} from \"./BECDnaType0Strategy.sol\";\nimport {BECGenesisEngine} from \"../BECGenesisEngine.sol\";\nimport {EIP712} from \"../eip712/EIP712.sol\";\nimport {EIP712Allowlist} from \"../eip712/EIP712Allowlist.sol\";\nimport {IERC721} from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\nimport {Fate, FateLibrary} from \"../utils/Fate.sol\";\n\n/**\n * @title Hunt DNA Strategy\n * @dev Implements a hunting mechanism for creatures within the Black Eyed Creatures ecosystem. \n *      This contract allows users to \"hunt\" for new creatures by minting them directly to their wallet. \n * @notice Use this contract to participate in creature hunts within the Black Eyed Creatures universe.\n * @author https://42i.co\n */\ncontract HuntDnaStrategy is BECDnaType0Strategy, EIP712Allowlist {\n\n  /// @dev Using Fate Library\n  using FateLibrary for Fate;\n\n  /// @dev Max amount of mints per address.\n  uint256 private constant maxMints = 3;\n\n  /// @dev Available amount creatures to mint.\n  uint256 private constant huntSize = 333;\n\n  /// @dev A mapping that stores the amount of hunts done per address.\n  mapping(address caller => uint256 count) public huntsPerAddress;\n\n  /// @dev A mapping that stores the amount of hunts done per blcksphr.\n  mapping(uint256 blcksphrId => uint256 count) private huntsPerSphere;\n\n  /**\n   * @notice Initializes a new HuntDnaStrategy contract.\n   * @param _coreContractAddress Address of the BEC core contract.\n   * @param _genesisEngineContractAddress Address of the genesis engine contract.\n   * @param _labContractAddress Address of the lab contract.\n   * @param _blcksphrsAddress Address of the Blcksphr contract.\n   * @param _strategyId Unique ID for this strategy.\n   * @param _distributionId ID representing the distribution logic for creature creation.\n   */\n  constructor(\n    address _coreContractAddress,\n    address _genesisEngineContractAddress,\n    address _labContractAddress,\n    address _blcksphrsAddress,\n    uint256 _strategyId,\n    uint256 _distributionId\n  )\n    BECDnaType0Strategy(\n      _coreContractAddress,\n      _genesisEngineContractAddress,\n      _labContractAddress,\n      _blcksphrsAddress,\n      _strategyId,\n      _distributionId\n    )\n  {}\n\n  /**\n   * @notice Sets the address used for EIP712 allowlist signing.\n   * @param newSigningKey The new signing key address.\n   */\n  function setAllowlistSigningAddress(address newSigningKey) public onlyOwner {\n    _setAllowlistSigningAddress(newSigningKey);\n  }\n\n  /**\n   * @notice Initiates a hunt for creatures, minting a specified quantity for the sender.\n   * @param _quantity The number of creatures to hunt.\n   * @return creatureIds A uint256 array of newly minted creature IDs.\n   */\n  function hunt(uint256 _quantity) public payable returns (uint256[] memory creatureIds) {\n    if (!enabled) revert BECNotEnabled();\n    if (msg.value < _quantity * price) revert BECRitualPriceNotPaid(_quantity * price, msg.value);\n    if (huntsPerAddress[msg.sender] + _quantity > maxMints) revert BECMaxHuntsAllowed(maxMints, huntsPerAddress[msg.sender] + _quantity);\n    creatureIds = _hunt(_quantity);\n  }\n\n  /**\n   * @notice Initiates a hunt for creatures with allowlist verification, minting a specified quantity for the sender.\n   * @param _quantity The number of creatures to hunt.\n   * @param _signature The EIP712 signature for allowlist verification.\n   * @return creatureIds A uint256 array of newly minted creature IDs.\n   */\n  function huntAllowed(\n    uint256 _quantity,\n    bytes calldata _signature\n  ) public requiresAllowlist(_signature) returns (uint256[] memory creatureIds) {\n    if (!enabled) revert BECNotEnabled();\n    if (huntsPerAddress[msg.sender] + _quantity > maxMints) revert BECMaxHuntsAllowed(maxMints, huntsPerAddress[msg.sender] + _quantity);\n    creatureIds = _hunt(_quantity);\n  }\n\n  /**\n   * @notice Initiates a hunt for creatures, minting a specified quantity for the sender, associated with a specific Blcksphr.\n   * @param _quantity The number of creatures to hunt.\n   * @param _blcksphrId The ID of the Blcksphr used for the hunt.\n   * @return creatureIds A uint256 array of newly minted creature IDs.\n   */\n  function huntBlcksphr(uint256 _quantity, uint256 _blcksphrId) public returns (uint256[] memory creatureIds) {\n    if (!enabled) revert BECNotEnabled();\n    if (IERC721(blcksphrContractAddress).ownerOf(_blcksphrId) != msg.sender) revert BlackSphereInvalidOwner(msg.sender, _blcksphrId);\n    if (huntsPerSphere[_blcksphrId] + _quantity > 9) revert BECMaxHuntsAllowed(9, huntsPerSphere[_blcksphrId] + _quantity);\n    huntsPerSphere[_blcksphrId] += _quantity;\n    creatureIds = _hunt(_quantity);\n  }\n\n  /**\n   * @notice Hunts for new creatures and mints them for the caller.\n   * @param _quantity The number of creatures to hunt and mint.\n   * @return creatureIds An array of the creature IDs for the newly minted creatures.\n   */\n  function _hunt(uint256 _quantity) internal returns (uint256[] memory creatureIds) {\n    unchecked {\n      BECCore coreContract = BECCore(payable(coreContractAddress));\n\n      uint256 lastCreatureId = coreContract.nextTokenId() - 1;\n      if (lastCreatureId + _quantity > huntSize) revert BECHuntFinished();\n\n      bytes32 seedValue = keccak256(abi.encodePacked(address(this), block.number, lastCreatureId));\n\n      // Clear the first 10 bits of seedValue, Set type, strategy and generation of the new creature.\n      seedValue &= bytes32(~(uint256(0x3FF) << 246)); // 246 = 256-10\n      seedValue |= bytes32(uint256(strategyLogs & 0xFF) << 248);\n\n      huntsPerAddress[msg.sender] += _quantity;\n      creatureIds = coreContract.mintWithSeed(msg.sender, seedValue, _quantity);\n    }\n  }\n\n  /**\n   * @dev See {IBECDnaStrategy-getDna}.\n   */\n  function getDna(uint256 _creatureId) external view override returns (uint256 dna) {\n    BECCore coreContract = BECCore(payable(coreContractAddress));\n    BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineContractAddress));\n\n    bytes32 seed = coreContract.getSeed(_creatureId);\n    Fate memory prophecy = FateLibrary.initiate(keccak256(abi.encodePacked(seed, _creatureId)));\n\n    dna = 0;\n    for (uint256 phenotype = 0; phenotype < 6; phenotype++) {\n      // Obtains the phenotype tickets bitwise.\n      uint256 phenotypeTickets = (genesisEngineContract.getPhenotypeTickets(0) >> (phenotype * 32)) & 0xFFFFFFFF;\n      uint256 winnerTicket = prophecy.pathWithin(phenotypeTickets);\n      dna += getFamilyAndVariation(phenotype, winnerTicket, 0);\n    }\n    uint16[3] memory colors = [uint16(13), uint16(13), uint16(13)];\n    for (uint256 colorPhenotype = 0; colorPhenotype < 3; colorPhenotype++) {\n      // Gets the color traits.\n      dna += prophecy.pathWithin(colors[colorPhenotype]) << (8 + ((colorPhenotype + 6) * 16));\n    }\n\n    dna += 0 << 248; // set type to normal\n  }\n}\n"
      },
      "contracts/strategies/IBECDnaStrategy.sol": {
        "content": "// contracts/strategies/IBECDnaStrategy.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n    /3333333     /33333333     /333333    \n   | 33__  33   | 33_____/    /33__  33   \n   | 33  \\ 33   | 33         | 33  \\__/   \n   | 3333333    | 33333      | 33         \n   | 33__  33   | 33__/      | 33         \n   | 33  \\ 33   | 33         | 33    33   \n   | 3333333/   | 33333333   |  333333/   \n   |_______/    |________/    \\______/    \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\n/**\n * @title Black Eyed Creatures DNA Strategy\n * @notice The strategies are the contracts that mints and generates the metada for the BECs. \n *         This interface helps with the information the genesis engine needs for each creature type.\n * @dev The genesis engine (through different strategies) creates DNA based in different logis, \n *      but always creating DNA that are compliant with the following order (8b each):\n * 00: body_family\n * 01: body_variation\n * 02: head_family\n * 03: head_variation\n * 04: ears_family\n * 05: ears_variation\n * 06: face_family\n * 07: face_variation\n * 08: hair_family\n * 09: hair_variation\n * 10: eyes_family\n * 11: eyes_variation\n * 12: bg_color_family\n * 13: bg_color_variation\n * 14: skin_color_family\n * 15: skin_color_variation\n * 16: secondary_color_family\n * 17: secondary_color_variation\n * 18-30: unused\n * 31: type: normal|golden|ghost|others\n *\n * @author https://42i.co\n */\ninterface IBECDnaStrategy {\n  /**\n   * @notice Retrieves the DNA of a creature based on its id.\n   * @param _creatureId The id of the creature.\n   * @return uint256 The DNA of the specified creature.\n   */\n  function getDna(uint256 _creatureId) external view returns (uint256);\n\n  /**\n   * @notice Gets the metadata tokenURI for this creature.\n   * @param _creatureId The id of the creature.\n   * @return string memory The token uri.\n   */\n  function tokenURI(uint256 _creatureId) external view returns (string memory);\n\n  /**\n   * @notice Identifies the strategy ID.\n   * @return uint256 The ID of the strategy.\n   */\n  function getStrategyId() external view returns (uint256);\n\n  /**\n   * @notice Identifies the distribution ID associated with this strategy.\n   * @return uint256 The distribution ID.\n   */\n  function getDistributionId() external view returns (uint256);\n}"
      },
      "contracts/strategies/ReproduceDnaStrategy.sol": {
        "content": "// contracts/strategies/ReproduceDnaStrategy.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n   /3333333    /33333333    /333333 \n  | 33__  33  | 33_____/   /33__  33\n  | 33  \\ 33  | 33        | 33  \\__/\n  | 3333333   | 33333     | 33      \n  | 33__  33  | 33__/     | 33      \n  | 33  \\ 33  | 33        | 33    33\n  | 3333333/  | 33333333  |  333333/\n  |_______/   |________/   \\______/ \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\nimport {BECCore} from \"../BECCore.sol\";\nimport {BECDnaType0Strategy} from \"./BECDnaType0Strategy.sol\";\nimport {BECGenesisEngine} from \"../BECGenesisEngine.sol\";\nimport {BECLab} from \"../BECLab.sol\";\nimport {IERC721} from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\nimport {IERC721Receiver} from \"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol\";\nimport {CreaturePacking} from \"../utils/CreaturePacking.sol\";\nimport {Fate, FateLibrary} from \"../utils/Fate.sol\";\n\n/**\n * @title Reproduce DNA Strategy\n * @dev Implements a reproduction mechanism for creatures within the Black Eyed Creatures ecosystem.\n *      This contract allows users to \"reproduce\" new creatures by combining the DNA of three parent creatures.\n * @notice Use this contract to participate in creature reproduction within the Black Eyed Creatures universe.\n * @author https://42i.co\n */\ncontract ReproduceDnaStrategy is BECDnaType0Strategy, IERC721Receiver {\n\n  /// @dev Using Fate Library\n  using FateLibrary for Fate;\n\n  /// @dev Max amount of omegas per creature.\n  uint256 public constant MAX_OMEGAS = 3 * 3;\n\n  /// @dev Matrix of boosts for omegas. Is stored in 2b each in a matrix of phenotype vs alpha/beta/gamma.\n  uint256 internal constant MIX_MATRIX = uint256(13140993452142171);\n\n  /// @dev Mapping with the amount of omegas created using a specific blcksphr.\n  mapping(uint256 blcksphrId => uint256 omegas) omegasPerSphere;\n\n  /// @dev Mapping with the amount of omegas created by a specific address.\n  mapping(address caller => uint256 count) public reproductionsPerAddress;\n\n  /**\n   * @notice Initializes the ReproduceDnaStrategy contract, setting up essential addresses and IDs for creature reproduction.\n   * @dev Sets the core contract, genesis engine, lab contract, and Blcksphr addresses, alongside strategy and distribution IDs.\n   *      It also initializes the price for using BEC in reproduction.\n   * @param _coreContractAddress Address of the BEC core contract.\n   * @param _genesisEngineContractAddress Address of the genesis engine contract.\n   * @param _labContractAddress Address of the lab contract.\n   * @param _blcksphrContractAddress Address of the Blcksphr contract.\n   * @param _strategyId Unique ID for this strategy.\n   * @param _distributionId ID representing the distribution logic for creature creation.\n   */\n  constructor(\n    address _coreContractAddress,\n    address _genesisEngineContractAddress,\n    address _labContractAddress,\n    address _blcksphrContractAddress,\n    uint256 _strategyId,\n    uint256 _distributionId\n  )\n    BECDnaType0Strategy(\n      _coreContractAddress,\n      _genesisEngineContractAddress,\n      _labContractAddress,\n      _blcksphrContractAddress,\n      _strategyId,\n      _distributionId\n    ) {}\n\n  /**\n   * @notice Allows a user to reproduce new creatures using three parent creatures, paying the reproduction cost in native currency.\n   * @dev This function requires the contract to be enabled and the caller to own the parent creatures.\n   *      It checks for type compatibility and enforces a maximum reproduction limit per creature.\n   * @param _creatureIds An array of three creature IDs to be used as parents for reproduction.\n   * @param _quantity The number of new creatures to reproduce.\n   * @return ids  An uint256[] array of newly minted creature IDs.\n   */\n  function reproduce(uint256[3] calldata _creatureIds, uint256 _quantity) public payable returns (uint256[] memory ids) {\n    unchecked {\n      if (!enabled) revert BECNotEnabled();\n      ids = _reproduce(_creatureIds, _quantity);\n      BECCore coreContract = BECCore(payable(coreContractAddress));\n      bytes32 seed = coreContract.getSeed(ids[0]);\n      uint256 generation = ((uint256(seed) >> 246) & 0x3);\n      uint256 ritualPrice = _quantity * price;\n      if (generation > 1) {\n        ritualPrice *= 3 ** (generation - 1);\n      }\n      if (msg.value < ritualPrice) revert BECRitualPriceNotPaid(ritualPrice, msg.value);\n    }\n  }\n\n  /**\n   * @notice Enables creature reproduction using a specific Blcksphr as a catalyst, introducing unique traits or benefits.\n   * @dev Extends reproduction capabilities by incorporating Blcksphrs, potentially affecting the outcome or traits of the offspring.\n   *      Limits apply to reproduction attempts per Blcksphr.\n   * @param _creatureIds Array of parent creature IDs.\n   * @param _quantity Number of offspring to produce.\n   * @param _blcksphrId ID of the Blcksphr used in the reproduction process.\n   * @return uint256[] Newly created creature IDs as a result of the reproduction process.\n   */\n  function reproduceBlcksphr(uint256[3] calldata _creatureIds, uint256 _quantity, uint256 _blcksphrId) public returns (uint256[] memory) {\n    unchecked {\n      if (!enabled) revert BECNotEnabled();\n      if (IERC721(blcksphrContractAddress).ownerOf(_blcksphrId) != msg.sender) revert BlackSphereInvalidOwner(msg.sender, _blcksphrId);\n      if (omegasPerSphere[_blcksphrId] + _quantity > 33) revert BECMaxReproductionsAllowed(33, omegasPerSphere[_blcksphrId] + _quantity);\n      omegasPerSphere[_blcksphrId] += _quantity;\n      return _reproduce(_creatureIds, _quantity);\n    }\n  }\n\n  /**\n   * @dev Handles the reproduction process by combining the DNA of parent creatures to produce new offspring.\n   * @param _creatureIds An array of three parent creature IDs.\n   * @param _quantity Number of offspring to produce.\n   * @return uint256[] An array containing the IDs of the newly created creatures.\n   */\n  function _reproduce(uint256[3] calldata _creatureIds, uint256 _quantity) internal returns (uint256[] memory) {\n    unchecked {\n      BECCore coreContract = BECCore(payable(coreContractAddress));\n      uint256 maxParentsGen = 0;\n      reproductionsPerAddress[msg.sender] += _quantity;\n\n    \n      uint256[] memory ids = new uint256[](_creatureIds.length);\n      for (uint256 i = 0; i < _creatureIds.length; i++) {\n        ids[i] = _creatureIds[i];\n      }\n\n      bytes32[] memory seeds = coreContract.getSeeds(ids);\n\n      for (uint256 i = 0; i < _creatureIds.length; i++) {\n        if (coreContract.ownerOf(_creatureIds[i]) != msg.sender) revert BECInvalidOwner(msg.sender, _creatureIds[i]);\n        if ((uint8(seeds[i][0]) >> 5) & 0x7 != 0) revert BECNotType0Creature(_creatureIds[i]);\n\n        uint256 genSeed = (uint256(seeds[i]) >> 246) & 0x3;\n        if (genSeed > 2) revert BECFruitlessCreature(_creatureIds[i]);\n        maxParentsGen = genSeed > maxParentsGen ? genSeed : maxParentsGen;\n      }\n\n      BECLab labContract = BECLab(payable(labContractAddress));\n      for (uint256 i = 0; i < 3; i++) {\n        if (labContract.getOmegas(_creatureIds[i]) + _quantity > MAX_OMEGAS)\n          revert BECMaxCreatureReproductionsAllowed(_creatureIds[i], MAX_OMEGAS, labContract.getOmegas(_creatureIds[i]) + _quantity);\n        labContract.incrementOmegas(_creatureIds[i], _quantity);\n      }\n\n      BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineContractAddress));\n      genesisEngineContract.setGenesisStorage(\n        coreContract.nextTokenId(),\n        CreaturePacking.packCreatures(_creatureIds[0], _creatureIds[1], _creatureIds[2])\n      );\n\n      bytes32 seedValue = keccak256(abi.encodePacked(address(this), block.number, coreContract.totalSupply(), _creatureIds));\n\n      // Clear the first 10 bits of seedValue, Set type, strategy and generation of the new creature.\n      seedValue &= bytes32(~(uint256(0x3FF) << 246)); // 246 = 256-10\n      seedValue |= bytes32((strategyLogs & 0xFF) << 248);\n      seedValue |= bytes32(((maxParentsGen + 1) & 0x3) << 246);\n\n      return coreContract.mintWithSeed(msg.sender, seedValue, _quantity);\n    }\n  }\n\n  /**\n   * @dev See {IBECDnaStrategy-getDna}.\n   */\n  function getDna(uint256 _creatureId) external view override returns (uint256) {\n    uint256[3] memory dnas = getParents(_creatureId);\n\n    BECCore coreContract = BECCore(payable(coreContractAddress));\n    BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineContractAddress));\n\n    bytes32 seed = coreContract.getSeed(_creatureId);\n    Fate memory prophecy = FateLibrary.initiate(keccak256(abi.encodePacked(seed, _creatureId)));\n\n    uint256 dna = 0;\n\n    for (uint256 phenotype = 0; phenotype < 6; phenotype++) {\n      // Obtains the number of tickets for the current phenotype in the phenotypeTickets storage.\n      uint256 phenotypeTickets = (genesisEngineContract.getPhenotypeTickets(0) >> (phenotype * 32)) & 0xFFFFFFFF;\n\n      // Obtains the boosts of each parent in the mixMatrix storage.\n      uint8[3] memory phenotypeBoosts = [\n        uint8((MIX_MATRIX >> (phenotype * 6)) & 0x3),\n        uint8((MIX_MATRIX >> ((phenotype * 6) + 2)) & 0x3),\n        uint8((MIX_MATRIX >> ((phenotype * 6) + 4)) & 0x3)\n      ];\n\n      // Obtains the extra tickets and position of the family for each parent.\n      uint256[2][3] memory extraTicketsArray = [\n        getExtraTickets(phenotype, dnas[0], phenotypeBoosts[0]),\n        getExtraTickets(phenotype, dnas[1], phenotypeBoosts[1]),\n        getExtraTickets(phenotype, dnas[2], phenotypeBoosts[2])\n      ];\n\n      // Calculates the total possible tickets for this phenotype with this parents.\n      uint256 totalTickets = phenotypeTickets +\n        extraTicketsArray[0][0] +\n        extraTicketsArray[1][0] +\n        extraTicketsArray[2][0];\n\n      // Gets the winner ticket.\n      uint256 winnerTicket = prophecy.pathWithin(totalTickets);\n\n      // If the winner ticket is into the base phenotype tickets.\n      if (winnerTicket < phenotypeTickets) {\n        // The winner ticket is a possible mutation and gets the genes in a prophetic way.\n        dna += getFamilyAndVariation(phenotype, winnerTicket, 0);\n      } \n      else {\n        // The winner ticket is not a mutation.\n        // As is not in the common pool, we remove that amount of tickets to understand in which parent boost appears.\n        winnerTicket -= phenotypeTickets;\n\n        // For each parent.\n        for (uint256 i = 0; i < dnas.length; i++) {\n          // If the winner ticket is in the extra tickets for this parent.\n          if (winnerTicket < extraTicketsArray[i][0]) {\n            // If the winner ticket is the same as the parent variation.\n            if (winnerTicket < extraTicketsArray[i][1]) {\n              // Sets the traits as the same as the parent.\n              dna += ((dnas[i] >> (phenotype * 16)) & 0xFFFF) << (phenotype * 16);\n            } \n            else {\n              // Family\n              uint256 family = (dnas[i] >> (phenotype * 16)) & 0xFF;\n              // The winner ticket is in the family of the parent. So, removes the variation tickets.\n              // Removes the boost previously added by dividing by 2^boost.\n              // Thats the winner ticket inside the possible family tickets.\n              uint256 variationTicket = (winnerTicket - extraTicketsArray[i][1]) / (2 ** phenotypeBoosts[i]);\n              // Gets the phenotype traits.\n              dna += getFamilyVariation(phenotype, family, variationTicket, 0);\n            }\n            break;\n          } \n          else {\n            // The winner ticket is not in this parent. So we remove the tickets of this specific parent.\n            winnerTicket -= uint16(extraTicketsArray[i][0]);\n          }\n        }\n      }\n    }\n    uint16[3] memory colors = [uint16(13), uint16(13), uint16(13)];\n    for (uint256 colorPhenotype = 0; colorPhenotype < 3; colorPhenotype++) {\n      uint8[3] memory phenotypeBoosts = [\n        uint8((MIX_MATRIX >> ((colorPhenotype + 6) * 6)) & 0x3),\n        uint8((MIX_MATRIX >> (((colorPhenotype + 6) * 6) + 2)) & 0x3),\n        uint8((MIX_MATRIX >> (((colorPhenotype + 6) * 6) + 4)) & 0x3)\n      ];\n\n      uint256 winnerTicket = prophecy.pathWithin(\n        colors[colorPhenotype] + phenotypeBoosts[0] + phenotypeBoosts[1] + phenotypeBoosts[2]\n      );\n\n      if (winnerTicket < colors[colorPhenotype]) {\n        dna += winnerTicket << (8 + (colorPhenotype + 6) * 16);\n      } \n      else {\n        winnerTicket -= colors[colorPhenotype];\n        for (uint256 boost = 0; boost < 3; boost++) {\n          if (winnerTicket < phenotypeBoosts[boost]) {\n            dna += ((dnas[boost] >> ((colorPhenotype + 6) * 16)) & 0xFFFF) << ((colorPhenotype + 6) * 16);\n            break;\n          } \n          else {\n            winnerTicket -= phenotypeBoosts[boost];\n          }\n        }\n      }\n    }\n\n    dna += 0 << 248; // set type to normal\n\n    return dna;\n  }\n\n  /**\n   * @notice Retrieves the DNA of the parent creatures for a given omega creature.\n   * @dev Extracts the parent creature IDs from the genesis storage using the omega creature's ID,\n   *      then fetches their DNA from the Genesis Engine. This function is crucial for the reproduction process,\n   *      allowing the new creature's DNA to be influenced by its parents.\n   * @param _omegaId The unique identifier of the omega creature whose parents' DNA is to be retrieved.\n   * @return uint256[] An array containing the DNA of the three parent creatures.\n   *         The array structure is [alpha DNA, beta DNA, gamma DNA].\n   */\n  function getParents(uint256 _omegaId) internal view returns (uint256[3] memory) {\n    BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineContractAddress));\n\n    uint256 packedValue = 0;\n    for (uint256 i = 0; packedValue == 0; i++) {\n      packedValue = genesisEngineContract.getGenesisStorage(_omegaId - i);\n    }\n\n    uint256[3] memory parentIds = CreaturePacking.unpackCreatures(packedValue);\n    return [\n      genesisEngineContract.getDna(parentIds[0]),\n      genesisEngineContract.getDna(parentIds[1]),\n      genesisEngineContract.getDna(parentIds[2])\n    ];\n  }\n\n  /**\n   * @dev Obtains from the familyMeta the extra tickets for this parent, the detail of the amount of them\n   *      that are extra only for the variation, and the position of the family in the distribution storage.\n   * @param _phenotype The phenotype we need to obtain information about.\n   * @param _dna The dna is going to be boosted.\n   * @param _boost The amount of boost.\n   * @return extraTickets An array with the extra tickets and the position of the family.\n   */\n  function getExtraTickets(uint256 _phenotype, uint256 _dna, uint8 _boost) internal view returns (uint256[2] memory) {\n    BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineContractAddress));\n    uint256 family = (_dna >> (_phenotype * 16)) & 0xFF;\n    uint256 variation = (_dna >> ((_phenotype * 16) + 8)) & 0xFF;\n    uint256 boostedVariationTickets = genesisEngineContract.getVariationTickets(0, _phenotype, family, variation) \n                                    * (2 ** (_boost * 2));\n    uint256 boostedTickets = boostedVariationTickets \n                           + genesisEngineContract.getFamilyTickets(0, _phenotype, family) * (2 ** _boost);\n    return [boostedTickets, boostedVariationTickets];\n  }\n\n  function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) {\n    return this.onERC721Received.selector;\n  }\n}\n"
      },
      "contracts/utils/CreaturePacking.sol": {
        "content": "// contracts/utils/CreaturePacking.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n    /3333333     /33333333     /333333    \n   | 33__  33   | 33_____/    /33__  33   \n   | 33  \\ 33   | 33         | 33  \\__/   \n   | 3333333    | 33333      | 33         \n   | 33__  33   | 33__/      | 33         \n   | 33  \\ 33   | 33         | 33    33   \n   | 3333333/   | 33333333   |  333333/   \n   |_______/    |________/    \\______/    \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\n/**\n * @title A library for working with creature packing.\n * @dev A utility library designed for packing and unpacking creature IDs into single uint256 values for efficient storage. \n * @author https://42i.co\n */\nlibrary CreaturePacking {\n  /**\n   * @notice Combines three creature IDs into a single uint256 value, leaving the highest bit unused.\n   *\n   * @dev Packs the _alpha, _beta, and _gamma creature IDs into a single uint256 for storage optimization.\n   * Uses bitwise operations to achieve this:\n   * - The highest bit is reserved and remains unused.\n   * - The _alpha ID occupies the next 85 bits.\n   * - The _beta ID occupies the following 85 bits.\n   * - The _gamma ID occupies the lowest 85 bits.\n   * To unpack the values, use corresponding bit masks and bit shifting.\n   *\n   * @param _alpha ID of the first creature.\n   * @param _beta ID of the second creature.\n   * @param _gamma ID of the third creature.\n   *\n   * @return Returns a uint256 value representing the combined IDs of the three creatures with the highest bit unused.\n   */\n  function packCreatures(uint256 _alpha, uint256 _beta, uint256 _gamma) internal pure returns (uint256) {\n    unchecked {\n      return (_alpha << 170) + (_beta << 85) + _gamma;\n    }\n  }\n\n  /**\n   * @notice Extracts the three creature IDs packed into a single uint256 value.\n   *\n   * @dev This function is the inverse operation of the `mergeCreatures` function.\n   * It uses bitwise operations to extract:\n   * - The _alpha ID from the next highest 85 bits after the highest bit.\n   * - The _beta ID from the subsequent 85 bits.\n   * - The _gamma ID from the lowest 85 bits.\n   *\n   * @param _merged The combined uint256 value of the three creature IDs with the highest bit unused.\n   *\n   * @return Returns an array of three uint256 values, representing the original IDs of the creatures:\n   *         [_alpha, _beta, _gamma].\n   */\n  function unpackCreatures(uint256 _merged) internal pure returns (uint256[3] memory) {\n    unchecked {\n      uint256 mask = (1 << 85) - 1;\n      return [(_merged >> 170) & mask, (_merged >> 85) & mask, _merged & mask];\n    }\n  }\n}\n"
      },
      "contracts/utils/Fate.sol": {
        "content": "// contracts/utils/Fate.sol\n// SPDX-License-Identifier: MIT\n\n/**\n\n    /3333333     /33333333     /333333    \n   | 33__  33   | 33_____/    /33__  33   \n   | 33  \\ 33   | 33         | 33  \\__/   \n   | 3333333    | 33333      | 33         \n   | 33__  33   | 33__/      | 33         \n   | 33  \\ 33   | 33         | 33    33   \n   | 3333333/   | 33333333   |  333333/   \n   |_______/    |________/    \\______/    \n\n # https://blackeyedcreatures.com\n\n */\n\npragma solidity ^0.8.25;\n\n/**\n * @title A fate generator for creatures.\n * @dev In a deterministic universe, is there randomness, or is there just fate?\n * @author https://42i.co\n */\nstruct Fate {\n  bytes32 destiny;\n}\n\n/**\n * @title A library for working with the Fate struct.\n * @dev Fate cannot be a contract because then anyone could manipulate it.\n * @author https://42i.co\n */\nlibrary FateLibrary {\n  /**\n   * @notice Seeds the fate.\n   * @return Fate instance.\n   */\n  function initiate(bytes32 _seed) internal pure returns (Fate memory) {\n    return Fate(_seed);\n  }\n\n  /**\n   * @notice Unfolds the next fate step.\n   * @param self Fate instance.\n   * @return uint256 The next step.\n   */\n  function nextStep(Fate memory self) internal pure returns (uint256) {\n    self.destiny = keccak256(abi.encodePacked(self.destiny));\n    return uint256(self.destiny);\n  }\n\n  /**\n   * @dev Determines a path within fate's boundary.\n   * @param self Fate instance.\n   * @param _boundary Path's limit.\n   * @return uint256 A path within the boundary.\n   */\n  function pathWithin(Fate memory self, uint256 _boundary) internal pure returns (uint256) {\n    return nextStep(self) % _boundary;\n  }\n}\n"
      },
      "hardhat/console.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.22 <0.9.0;\n\nlibrary console {\n    address constant CONSOLE_ADDRESS =\n        0x000000000000000000636F6e736F6c652e6c6f67;\n\n    function _sendLogPayloadImplementation(bytes memory payload) internal view {\n        address consoleAddress = CONSOLE_ADDRESS;\n        /// @solidity memory-safe-assembly\n        assembly {\n            pop(\n                staticcall(\n                    gas(),\n                    consoleAddress,\n                    add(payload, 32),\n                    mload(payload),\n                    0,\n                    0\n                )\n            )\n        }\n    }\n\n    function _castToPure(\n      function(bytes memory) internal view fnIn\n    ) internal pure returns (function(bytes memory) pure fnOut) {\n        assembly {\n            fnOut := fnIn\n        }\n    }\n\n    function _sendLogPayload(bytes memory payload) internal pure {\n        _castToPure(_sendLogPayloadImplementation)(payload);\n    }\n\n    function log() internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log()\"));\n    }\n    function logInt(int256 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(int256)\", p0));\n    }\n\n    function logUint(uint256 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n    }\n\n    function logString(string memory p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n    }\n\n    function logBool(bool p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n    }\n\n    function logAddress(address p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n    }\n\n    function logBytes(bytes memory p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes)\", p0));\n    }\n\n    function logBytes1(bytes1 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes1)\", p0));\n    }\n\n    function logBytes2(bytes2 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes2)\", p0));\n    }\n\n    function logBytes3(bytes3 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes3)\", p0));\n    }\n\n    function logBytes4(bytes4 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes4)\", p0));\n    }\n\n    function logBytes5(bytes5 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes5)\", p0));\n    }\n\n    function logBytes6(bytes6 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes6)\", p0));\n    }\n\n    function logBytes7(bytes7 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes7)\", p0));\n    }\n\n    function logBytes8(bytes8 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes8)\", p0));\n    }\n\n    function logBytes9(bytes9 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes9)\", p0));\n    }\n\n    function logBytes10(bytes10 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes10)\", p0));\n    }\n\n    function logBytes11(bytes11 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes11)\", p0));\n    }\n\n    function logBytes12(bytes12 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes12)\", p0));\n    }\n\n    function logBytes13(bytes13 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes13)\", p0));\n    }\n\n    function logBytes14(bytes14 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes14)\", p0));\n    }\n\n    function logBytes15(bytes15 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes15)\", p0));\n    }\n\n    function logBytes16(bytes16 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes16)\", p0));\n    }\n\n    function logBytes17(bytes17 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes17)\", p0));\n    }\n\n    function logBytes18(bytes18 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes18)\", p0));\n    }\n\n    function logBytes19(bytes19 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes19)\", p0));\n    }\n\n    function logBytes20(bytes20 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes20)\", p0));\n    }\n\n    function logBytes21(bytes21 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes21)\", p0));\n    }\n\n    function logBytes22(bytes22 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes22)\", p0));\n    }\n\n    function logBytes23(bytes23 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes23)\", p0));\n    }\n\n    function logBytes24(bytes24 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes24)\", p0));\n    }\n\n    function logBytes25(bytes25 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes25)\", p0));\n    }\n\n    function logBytes26(bytes26 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes26)\", p0));\n    }\n\n    function logBytes27(bytes27 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes27)\", p0));\n    }\n\n    function logBytes28(bytes28 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes28)\", p0));\n    }\n\n    function logBytes29(bytes29 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes29)\", p0));\n    }\n\n    function logBytes30(bytes30 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes30)\", p0));\n    }\n\n    function logBytes31(bytes31 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes31)\", p0));\n    }\n\n    function logBytes32(bytes32 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes32)\", p0));\n    }\n\n    function log(uint256 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n    }\n\n    function log(string memory p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n    }\n\n    function log(bool p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n    }\n\n    function log(address p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n    }\n\n    function log(uint256 p0, uint256 p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256)\", p0, p1));\n    }\n\n    function log(uint256 p0, string memory p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string)\", p0, p1));\n    }\n\n    function log(uint256 p0, bool p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool)\", p0, p1));\n    }\n\n    function log(uint256 p0, address p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address)\", p0, p1));\n    }\n\n    function log(string memory p0, uint256 p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256)\", p0, p1));\n    }\n\n    function log(string memory p0, string memory p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string)\", p0, p1));\n    }\n\n    function log(string memory p0, bool p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool)\", p0, p1));\n    }\n\n    function log(string memory p0, address p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address)\", p0, p1));\n    }\n\n    function log(bool p0, uint256 p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256)\", p0, p1));\n    }\n\n    function log(bool p0, string memory p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string)\", p0, p1));\n    }\n\n    function log(bool p0, bool p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool)\", p0, p1));\n    }\n\n    function log(bool p0, address p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address)\", p0, p1));\n    }\n\n    function log(address p0, uint256 p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256)\", p0, p1));\n    }\n\n    function log(address p0, string memory p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string)\", p0, p1));\n    }\n\n    function log(address p0, bool p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool)\", p0, p1));\n    }\n\n    function log(address p0, address p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address)\", p0, p1));\n    }\n\n    function log(uint256 p0, uint256 p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, uint256 p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, uint256 p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, uint256 p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, string memory p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, string memory p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, string memory p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, string memory p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, bool p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, bool p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, bool p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, bool p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, address p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, address p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, address p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, address p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, uint256 p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, uint256 p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, uint256 p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, uint256 p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, string memory p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, string memory p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, string memory p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, string memory p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, bool p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, bool p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, bool p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, bool p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, address p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, address p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, address p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, address p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address)\", p0, p1, p2));\n    }\n\n    function log(bool p0, uint256 p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256)\", p0, p1, p2));\n    }\n\n    function log(bool p0, uint256 p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string)\", p0, p1, p2));\n    }\n\n    function log(bool p0, uint256 p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool)\", p0, p1, p2));\n    }\n\n    function log(bool p0, uint256 p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address)\", p0, p1, p2));\n    }\n\n    function log(bool p0, string memory p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256)\", p0, p1, p2));\n    }\n\n    function log(bool p0, string memory p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string)\", p0, p1, p2));\n    }\n\n    function log(bool p0, string memory p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool)\", p0, p1, p2));\n    }\n\n    function log(bool p0, string memory p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address)\", p0, p1, p2));\n    }\n\n    function log(bool p0, bool p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256)\", p0, p1, p2));\n    }\n\n    function log(bool p0, bool p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string)\", p0, p1, p2));\n    }\n\n    function log(bool p0, bool p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool)\", p0, p1, p2));\n    }\n\n    function log(bool p0, bool p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address)\", p0, p1, p2));\n    }\n\n    function log(bool p0, address p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256)\", p0, p1, p2));\n    }\n\n    function log(bool p0, address p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string)\", p0, p1, p2));\n    }\n\n    function log(bool p0, address p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool)\", p0, p1, p2));\n    }\n\n    function log(bool p0, address p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address)\", p0, p1, p2));\n    }\n\n    function log(address p0, uint256 p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256)\", p0, p1, p2));\n    }\n\n    function log(address p0, uint256 p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string)\", p0, p1, p2));\n    }\n\n    function log(address p0, uint256 p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool)\", p0, p1, p2));\n    }\n\n    function log(address p0, uint256 p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address)\", p0, p1, p2));\n    }\n\n    function log(address p0, string memory p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256)\", p0, p1, p2));\n    }\n\n    function log(address p0, string memory p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string)\", p0, p1, p2));\n    }\n\n    function log(address p0, string memory p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool)\", p0, p1, p2));\n    }\n\n    function log(address p0, string memory p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address)\", p0, p1, p2));\n    }\n\n    function log(address p0, bool p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256)\", p0, p1, p2));\n    }\n\n    function log(address p0, bool p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string)\", p0, p1, p2));\n    }\n\n    function log(address p0, bool p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool)\", p0, p1, p2));\n    }\n\n    function log(address p0, bool p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address)\", p0, p1, p2));\n    }\n\n    function log(address p0, address p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256)\", p0, p1, p2));\n    }\n\n    function log(address p0, address p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string)\", p0, p1, p2));\n    }\n\n    function log(address p0, address p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool)\", p0, p1, p2));\n    }\n\n    function log(address p0, address p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,address)\", p0, p1, p2, p3));\n    }\n\n}\n"
      },
      "solidity-bits/contracts/BitMaps.sol": {
        "content": "// SPDX-License-Identifier: MIT\n/**\n   _____       ___     ___ __           ____  _ __      \n  / ___/____  / (_)___/ (_) /___  __   / __ )(_) /______\n  \\__ \\/ __ \\/ / / __  / / __/ / / /  / __  / / __/ ___/\n ___/ / /_/ / / / /_/ / / /_/ /_/ /  / /_/ / / /_(__  ) \n/____/\\____/_/_/\\__,_/_/\\__/\\__, /  /_____/_/\\__/____/  \n                           /____/                        \n\n- npm: https://www.npmjs.com/package/solidity-bits\n- github: https://github.com/estarriolvetch/solidity-bits\n\n */\npragma solidity ^0.8.0;\n\nimport \"./BitScan.sol\";\nimport \"./Popcount.sol\";\n\n/**\n * @dev This Library is a modified version of Openzeppelin's BitMaps library with extra features.\n *\n * 1. Functions of finding the index of the closest set bit from a given index are added.\n *    The indexing of each bucket is modifed to count from the MSB to the LSB instead of from the LSB to the MSB.\n *    The modification of indexing makes finding the closest previous set bit more efficient in gas usage.\n * 2. Setting and unsetting the bitmap consecutively.\n * 3. Accounting number of set bits within a given range.   \n *\n*/\n\n/**\n * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential.\n * Largelly inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor].\n */\n\nlibrary BitMaps {\n    using BitScan for uint256;\n    uint256 private constant MASK_INDEX_ZERO = (1 << 255);\n    uint256 private constant MASK_FULL = type(uint256).max;\n\n    struct BitMap {\n        mapping(uint256 => uint256) _data;\n    }\n\n    /**\n     * @dev Returns whether the bit at `index` is set.\n     */\n    function get(BitMap storage bitmap, uint256 index) internal view returns (bool) {\n        uint256 bucket = index >> 8;\n        uint256 mask = MASK_INDEX_ZERO >> (index & 0xff);\n        return bitmap._data[bucket] & mask != 0;\n    }\n\n    /**\n     * @dev Sets the bit at `index` to the boolean `value`.\n     */\n    function setTo(\n        BitMap storage bitmap,\n        uint256 index,\n        bool value\n    ) internal {\n        if (value) {\n            set(bitmap, index);\n        } else {\n            unset(bitmap, index);\n        }\n    }\n\n    /**\n     * @dev Sets the bit at `index`.\n     */\n    function set(BitMap storage bitmap, uint256 index) internal {\n        uint256 bucket = index >> 8;\n        uint256 mask = MASK_INDEX_ZERO >> (index & 0xff);\n        bitmap._data[bucket] |= mask;\n    }\n\n    /**\n     * @dev Unsets the bit at `index`.\n     */\n    function unset(BitMap storage bitmap, uint256 index) internal {\n        uint256 bucket = index >> 8;\n        uint256 mask = MASK_INDEX_ZERO >> (index & 0xff);\n        bitmap._data[bucket] &= ~mask;\n    }\n\n\n    /**\n     * @dev Consecutively sets `amount` of bits starting from the bit at `startIndex`.\n     */    \n    function setBatch(BitMap storage bitmap, uint256 startIndex, uint256 amount) internal {\n        uint256 bucket = startIndex >> 8;\n\n        uint256 bucketStartIndex = (startIndex & 0xff);\n\n        unchecked {\n            if(bucketStartIndex + amount < 256) {\n                bitmap._data[bucket] |= MASK_FULL << (256 - amount) >> bucketStartIndex;\n            } else {\n                bitmap._data[bucket] |= MASK_FULL >> bucketStartIndex;\n                amount -= (256 - bucketStartIndex);\n                bucket++;\n\n                while(amount > 256) {\n                    bitmap._data[bucket] = MASK_FULL;\n                    amount -= 256;\n                    bucket++;\n                }\n\n                bitmap._data[bucket] |= MASK_FULL << (256 - amount);\n            }\n        }\n    }\n\n\n    /**\n     * @dev Consecutively unsets `amount` of bits starting from the bit at `startIndex`.\n     */    \n    function unsetBatch(BitMap storage bitmap, uint256 startIndex, uint256 amount) internal {\n        uint256 bucket = startIndex >> 8;\n\n        uint256 bucketStartIndex = (startIndex & 0xff);\n\n        unchecked {\n            if(bucketStartIndex + amount < 256) {\n                bitmap._data[bucket] &= ~(MASK_FULL << (256 - amount) >> bucketStartIndex);\n            } else {\n                bitmap._data[bucket] &= ~(MASK_FULL >> bucketStartIndex);\n                amount -= (256 - bucketStartIndex);\n                bucket++;\n\n                while(amount > 256) {\n                    bitmap._data[bucket] = 0;\n                    amount -= 256;\n                    bucket++;\n                }\n\n                bitmap._data[bucket] &= ~(MASK_FULL << (256 - amount));\n            }\n        }\n    }\n\n    /**\n     * @dev Returns number of set bits within a range.\n     */\n    function popcountA(BitMap storage bitmap, uint256 startIndex, uint256 amount) internal view returns(uint256 count) {\n        uint256 bucket = startIndex >> 8;\n\n        uint256 bucketStartIndex = (startIndex & 0xff);\n\n        unchecked {\n            if(bucketStartIndex + amount < 256) {\n                count +=  Popcount.popcount256A(\n                    bitmap._data[bucket] & (MASK_FULL << (256 - amount) >> bucketStartIndex)\n                );\n            } else {\n                count += Popcount.popcount256A(\n                    bitmap._data[bucket] & (MASK_FULL >> bucketStartIndex)\n                );\n                amount -= (256 - bucketStartIndex);\n                bucket++;\n\n                while(amount > 256) {\n                    count += Popcount.popcount256A(bitmap._data[bucket]);\n                    amount -= 256;\n                    bucket++;\n                }\n                count += Popcount.popcount256A(\n                    bitmap._data[bucket] & (MASK_FULL << (256 - amount))\n                );\n            }\n        }\n    }\n\n    /**\n     * @dev Returns number of set bits within a range.\n     */\n    function popcountB(BitMap storage bitmap, uint256 startIndex, uint256 amount) internal view returns(uint256 count) {\n        uint256 bucket = startIndex >> 8;\n\n        uint256 bucketStartIndex = (startIndex & 0xff);\n\n        unchecked {\n            if(bucketStartIndex + amount < 256) {\n                count +=  Popcount.popcount256B(\n                    bitmap._data[bucket] & (MASK_FULL << (256 - amount) >> bucketStartIndex)\n                );\n            } else {\n                count += Popcount.popcount256B(\n                    bitmap._data[bucket] & (MASK_FULL >> bucketStartIndex)\n                );\n                amount -= (256 - bucketStartIndex);\n                bucket++;\n\n                while(amount > 256) {\n                    count += Popcount.popcount256B(bitmap._data[bucket]);\n                    amount -= 256;\n                    bucket++;\n                }\n                count += Popcount.popcount256B(\n                    bitmap._data[bucket] & (MASK_FULL << (256 - amount))\n                );\n            }\n        }\n    }\n\n\n    /**\n     * @dev Find the closest index of the set bit before `index`.\n     */\n    function scanForward(BitMap storage bitmap, uint256 index) internal view returns (uint256 setBitIndex) {\n        uint256 bucket = index >> 8;\n\n        // index within the bucket\n        uint256 bucketIndex = (index & 0xff);\n\n        // load a bitboard from the bitmap.\n        uint256 bb = bitmap._data[bucket];\n\n        // offset the bitboard to scan from `bucketIndex`.\n        bb = bb >> (0xff ^ bucketIndex); // bb >> (255 - bucketIndex)\n        \n        if(bb > 0) {\n            unchecked {\n                setBitIndex = (bucket << 8) | (bucketIndex -  bb.bitScanForward256());    \n            }\n        } else {\n            while(true) {\n                require(bucket > 0, \"BitMaps: The set bit before the index doesn't exist.\");\n                unchecked {\n                    bucket--;\n                }\n                // No offset. Always scan from the least significiant bit now.\n                bb = bitmap._data[bucket];\n                \n                if(bb > 0) {\n                    unchecked {\n                        setBitIndex = (bucket << 8) | (255 -  bb.bitScanForward256());\n                        break;\n                    }\n                } \n            }\n        }\n    }\n\n    function getBucket(BitMap storage bitmap, uint256 bucket) internal view returns (uint256) {\n        return bitmap._data[bucket];\n    }\n}\n"
      },
      "solidity-bits/contracts/BitScan.sol": {
        "content": "// SPDX-License-Identifier: MIT\n/**\n   _____       ___     ___ __           ____  _ __      \n  / ___/____  / (_)___/ (_) /___  __   / __ )(_) /______\n  \\__ \\/ __ \\/ / / __  / / __/ / / /  / __  / / __/ ___/\n ___/ / /_/ / / / /_/ / / /_/ /_/ /  / /_/ / / /_(__  ) \n/____/\\____/_/_/\\__,_/_/\\__/\\__, /  /_____/_/\\__/____/  \n                           /____/                        \n\n- npm: https://www.npmjs.com/package/solidity-bits\n- github: https://github.com/estarriolvetch/solidity-bits\n\n */\n\npragma solidity ^0.8.0;\n\n\nlibrary BitScan {\n    uint256 constant private DEBRUIJN_256 = 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff;\n    bytes constant private LOOKUP_TABLE_256 = hex\"0001020903110a19042112290b311a3905412245134d2a550c5d32651b6d3a7506264262237d468514804e8d2b95569d0d495ea533a966b11c886eb93bc176c9071727374353637324837e9b47af86c7155181ad4fd18ed32c9096db57d59ee30e2e4a6a5f92a6be3498aae067ddb2eb1d5989b56fd7baf33ca0c2ee77e5caf7ff0810182028303840444c545c646c7425617c847f8c949c48a4a8b087b8c0c816365272829aaec650acd0d28fdad4e22d6991bd97dfdcea58b4d6f29fede4f6fe0f1f2f3f4b5b6b607b8b93a3a7b7bf357199c5abcfd9e168bcdee9b3f1ecf5fd1e3e5a7a8aa2b670c4ced8bbe8f0f4fc3d79a1c3cde7effb78cce6facbf9f8\";\n\n    /**\n        @dev Isolate the least significant set bit.\n     */ \n    function isolateLS1B256(uint256 bb) pure internal returns (uint256) {\n        require(bb > 0);\n        unchecked {\n            return bb & (0 - bb);\n        }\n    } \n\n    /**\n        @dev Isolate the most significant set bit.\n     */ \n    function isolateMS1B256(uint256 bb) pure internal returns (uint256) {\n        require(bb > 0);\n        unchecked {\n            bb |= bb >> 128;\n            bb |= bb >> 64;\n            bb |= bb >> 32;\n            bb |= bb >> 16;\n            bb |= bb >> 8;\n            bb |= bb >> 4;\n            bb |= bb >> 2;\n            bb |= bb >> 1;\n            \n            return (bb >> 1) + 1;\n        }\n    } \n\n    /**\n        @dev Find the index of the lest significant set bit. (trailing zero count)\n     */ \n    function bitScanForward256(uint256 bb) pure internal returns (uint8) {\n        unchecked {\n            return uint8(LOOKUP_TABLE_256[(isolateLS1B256(bb) * DEBRUIJN_256) >> 248]);\n        }   \n    }\n\n    /**\n        @dev Find the index of the most significant set bit.\n     */ \n    function bitScanReverse256(uint256 bb) pure internal returns (uint8) {\n        unchecked {\n            return 255 - uint8(LOOKUP_TABLE_256[((isolateMS1B256(bb) * DEBRUIJN_256) >> 248)]);\n        }   \n    }\n\n    function log2(uint256 bb) pure internal returns (uint8) {\n        unchecked {\n            return uint8(LOOKUP_TABLE_256[(isolateMS1B256(bb) * DEBRUIJN_256) >> 248]);\n        } \n    }\n}\n"
      },
      "solidity-bits/contracts/Popcount.sol": {
        "content": "// SPDX-License-Identifier: MIT\n/**\n   _____       ___     ___ __           ____  _ __      \n  / ___/____  / (_)___/ (_) /___  __   / __ )(_) /______\n  \\__ \\/ __ \\/ / / __  / / __/ / / /  / __  / / __/ ___/\n ___/ / /_/ / / / /_/ / / /_/ /_/ /  / /_/ / / /_(__  ) \n/____/\\____/_/_/\\__,_/_/\\__/\\__, /  /_____/_/\\__/____/  \n                           /____/                        \n\n- npm: https://www.npmjs.com/package/solidity-bits\n- github: https://github.com/estarriolvetch/solidity-bits\n\n */\n\npragma solidity ^0.8.0;\n\nlibrary Popcount {\n    uint256 private constant m1 = 0x5555555555555555555555555555555555555555555555555555555555555555;\n    uint256 private constant m2 = 0x3333333333333333333333333333333333333333333333333333333333333333;\n    uint256 private constant m4 = 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n    uint256 private constant h01 = 0x0101010101010101010101010101010101010101010101010101010101010101;\n\n    function popcount256A(uint256 x) internal pure returns (uint256 count) {\n        unchecked{\n            for (count=0; x!=0; count++)\n                x &= x - 1;\n        }\n    }\n\n    function popcount256B(uint256 x) internal pure returns (uint256) {\n        if (x == type(uint256).max) {\n            return 256;\n        }\n        unchecked {\n            x -= (x >> 1) & m1;             //put count of each 2 bits into those 2 bits\n            x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits \n            x = (x + (x >> 4)) & m4;        //put count of each 8 bits into those 8 bits \n            x = (x * h01) >> 248;  //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ... \n        }\n        return x;\n    }\n}"
      }
    },
    "settings": {
      "viaIR": true,
      "optimizer": {
        "enabled": true,
        "runs": 200,
        "details": {
          "yulDetails": {
            "optimizerSteps": "u"
          }
        }
      },
      "evmVersion": "paris",
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "abi"
          ]
        }
      },
      "metadata": {
        "useLiteralContent": true
      }
    }
  }}