creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721Upgradeable.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 IERC721MetadataUpgradeable is IERC721Upgradeable {\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-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\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 IERC721ReceiverUpgradeable {\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 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-upgradeable/token/ERC721/IERC721Upgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165Upgradeable.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721Upgradeable is IERC165Upgradeable {\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 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 {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 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 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     *\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-upgradeable/utils/introspection/IERC165Upgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\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 IERC165Upgradeable {\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/token/ERC20/extensions/IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\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 */\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    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 v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\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 amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` 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 amount) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/IERC20Permit.sol\";\nimport \"../../../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 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.encodeWithSelector(token.transfer.selector, 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.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(IERC20 token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 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        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n    }\n\n    /**\n     * @dev Decrease 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 safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\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.encodeWithSelector(token.approve.selector, spender, value);\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n     * Revert on invalid signature.\n     */\n    function safePermit(\n        IERC20Permit token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\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, \"SafeERC20: low-level call failed\");\n        require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\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\n            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     *\n     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\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, it is bubbled up by this\n     * function (like regular Solidity function calls).\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     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\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     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) 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(errorMessage);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/math/Math.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\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 up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\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 denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by 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; // 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                prod0 := mul(x, y)\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            require(denominator > prod1, \"Math: mulDiv overflow\");\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. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\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 works\n            // 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 (rounding == Rounding.Up && 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 down.\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 + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\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 + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\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 + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\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 + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n}\n"
      },
      "contracts/diamond/DiamondLib.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport { IAccessControl } from \"../interfaces/IAccessControl.sol\";\nimport { IDiamondCut } from \"../interfaces/diamond/IDiamondCut.sol\";\n\n/**\n * @title DiamondLib\n *\n * @notice Provides Diamond storage slot and supported interface checks.\n *\n * @notice Based on Nick Mudge's gas-optimized diamond-2 reference,\n * with modifications to support role-based access and management of\n * supported interfaces. Also added copious code comments throughout.\n *\n * Reference Implementation  : https://github.com/mudgen/diamond-2-hardhat\n * EIP-2535 Diamond Standard : https://eips.ethereum.org/EIPS/eip-2535\n *\n * N.B. Facet management functions from original `DiamondLib` were refactored/extracted\n * to JewelerLib, since business facets also use this library for access control and\n * managing supported interfaces.\n *\n * @author Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)\n * @author Cliff Hall <cliff@futurescale.com> (https://twitter.com/seaofarrows)\n */\nlibrary DiamondLib {\n    bytes32 internal constant DIAMOND_STORAGE_POSITION = keccak256(\"diamond.standard.diamond.storage\");\n\n    struct DiamondStorage {\n        // Maps function selectors to the facets that execute the functions\n        // and maps the selectors to their position in the selectorSlots array.\n        // func selector => address facet, selector position\n        mapping(bytes4 => bytes32) facets;\n        // Array of slots of function selectors.\n        // Each slot holds 8 function selectors.\n        mapping(uint256 => bytes32) selectorSlots;\n        // The number of function selectors in selectorSlots\n        uint16 selectorCount;\n        // Used to query if a contract implement is an interface.\n        // Used to implement ERC-165.\n        mapping(bytes4 => bool) supportedInterfaces;\n        // The Boson Protocol AccessController\n        IAccessControl accessController;\n    }\n\n    /**\n     * @notice Gets the Diamond storage slot.\n     *\n     * @return ds - Diamond storage slot cast to DiamondStorage\n     */\n    function diamondStorage() internal pure returns (DiamondStorage storage ds) {\n        bytes32 position = DIAMOND_STORAGE_POSITION;\n        assembly {\n            ds.slot := position\n        }\n    }\n\n    /**\n     * @notice Adds a supported interface to the Diamond.\n     *\n     * @param _interfaceId - the interface to add\n     */\n    function addSupportedInterface(bytes4 _interfaceId) internal {\n        // Get the DiamondStorage struct\n        DiamondStorage storage ds = diamondStorage();\n\n        // Flag the interfaces as supported\n        ds.supportedInterfaces[_interfaceId] = true;\n    }\n\n    /**\n     * @notice Removes a supported interface from the Diamond.\n     *\n     * @param _interfaceId - the interface to remove\n     */\n    function removeSupportedInterface(bytes4 _interfaceId) internal {\n        // Get the DiamondStorage struct\n        DiamondStorage storage ds = diamondStorage();\n\n        // Flag the interfaces as unsupported\n        ds.supportedInterfaces[_interfaceId] = false;\n    }\n\n    /**\n     * @notice Checks if a specific interface is supported.\n     * Implementation of ERC-165 interface detection standard.\n     *\n     * @param _interfaceId - the sighash of the given interface\n     * @return - whether or not the interface is supported\n     */\n    function supportsInterface(bytes4 _interfaceId) internal view returns (bool) {\n        // Get the DiamondStorage struct\n        DiamondStorage storage ds = diamondStorage();\n\n        // Return the value\n        return ds.supportedInterfaces[_interfaceId];\n    }\n}\n"
      },
      "contracts/domain/BosonConstants.sol": {
        "content": "import \"./BosonTypes.sol\";\n\n// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.22;\n\n// Access Control Roles\nbytes32 constant ADMIN = keccak256(\"ADMIN\"); // Role Admin\nbytes32 constant PAUSER = keccak256(\"PAUSER\"); // Role for pausing the protocol\nbytes32 constant PROTOCOL = keccak256(\"PROTOCOL\"); // Role for facets of the ProtocolDiamond\nbytes32 constant CLIENT = keccak256(\"CLIENT\"); // Role for clients of the ProtocolDiamond\nbytes32 constant UPGRADER = keccak256(\"UPGRADER\"); // Role for performing contract and config upgrades\nbytes32 constant FEE_COLLECTOR = keccak256(\"FEE_COLLECTOR\"); // Role for collecting fees from the protocol\n\n// Generic\nuint256 constant HUNDRED_PERCENT = 10000; // 100% in basis points\n\n// Pause Handler\nuint256 constant ALL_REGIONS_MASK = (1 << (uint256(type(BosonTypes.PausableRegion).max) + 1)) - 1;\n\n// Reentrancy guard\nuint256 constant NOT_ENTERED = 1;\nuint256 constant ENTERED = 2;\n\n// Twin handler\nuint256 constant SINGLE_TWIN_RESERVED_GAS = 160000;\nuint256 constant MINIMAL_RESIDUAL_GAS = 230000;\n\n// Config related\nbytes32 constant VOUCHER_PROXY_SALT = keccak256(abi.encodePacked(\"BosonVoucherProxy\"));\n\n// Funds related\nstring constant NATIVE_CURRENCY = \"Native currency\";\nstring constant TOKEN_NAME_UNSPECIFIED = \"Token name unavailable\";\n\n// EIP712Lib\nstring constant PROTOCOL_NAME = \"Boson Protocol\";\nstring constant PROTOCOL_VERSION = \"V2\";\nbytes32 constant EIP712_DOMAIN_TYPEHASH = keccak256(\n    bytes(\"EIP712Domain(string name,string version,address verifyingContract,bytes32 salt)\")\n);\n\n// BosonVoucher\nstring constant VOUCHER_NAME = \"Boson Voucher (rNFT)\";\nstring constant VOUCHER_SYMBOL = \"BOSON_VOUCHER_RNFT\";\n\n// Meta Transactions - Error\nstring constant FUNCTION_CALL_NOT_SUCCESSFUL = \"Function call not successful\";\n\n// External contracts errors\nstring constant OWNABLE_ZERO_ADDRESS = \"Ownable: new owner is the zero address\"; // exception message from OpenZeppelin Ownable\nstring constant ERC721_INVALID_TOKEN_ID = \"ERC721: invalid token ID\"; // exception message from OpenZeppelin ERC721\n\n// Meta Transactions - Structs\nbytes32 constant META_TRANSACTION_TYPEHASH = keccak256(\n    bytes(\n        \"MetaTransaction(uint256 nonce,address from,address contractAddress,string functionName,bytes functionSignature)\"\n    )\n);\nbytes32 constant OFFER_DETAILS_TYPEHASH = keccak256(\"MetaTxOfferDetails(address buyer,uint256 offerId)\");\nbytes32 constant META_TX_COMMIT_TO_OFFER_TYPEHASH = keccak256(\n    \"MetaTxCommitToOffer(uint256 nonce,address from,address contractAddress,string functionName,MetaTxOfferDetails offerDetails)MetaTxOfferDetails(address buyer,uint256 offerId)\"\n);\nbytes32 constant CONDITIONAL_OFFER_DETAILS_TYPEHASH = keccak256(\n    \"MetaTxConditionalOfferDetails(address buyer,uint256 offerId,uint256 tokenId)\"\n);\nbytes32 constant META_TX_COMMIT_TO_CONDITIONAL_OFFER_TYPEHASH = keccak256(\n    \"MetaTxCommitToConditionalOffer(uint256 nonce,address from,address contractAddress,string functionName,MetaTxConditionalOfferDetails offerDetails)MetaTxConditionalOfferDetails(address buyer,uint256 offerId,uint256 tokenId)\"\n);\nbytes32 constant EXCHANGE_DETAILS_TYPEHASH = keccak256(\"MetaTxExchangeDetails(uint256 exchangeId)\");\nbytes32 constant META_TX_EXCHANGE_TYPEHASH = keccak256(\n    \"MetaTxExchange(uint256 nonce,address from,address contractAddress,string functionName,MetaTxExchangeDetails exchangeDetails)MetaTxExchangeDetails(uint256 exchangeId)\"\n);\nbytes32 constant FUND_DETAILS_TYPEHASH = keccak256(\n    \"MetaTxFundDetails(uint256 entityId,address[] tokenList,uint256[] tokenAmounts)\"\n);\nbytes32 constant META_TX_FUNDS_TYPEHASH = keccak256(\n    \"MetaTxFund(uint256 nonce,address from,address contractAddress,string functionName,MetaTxFundDetails fundDetails)MetaTxFundDetails(uint256 entityId,address[] tokenList,uint256[] tokenAmounts)\"\n);\nbytes32 constant DISPUTE_RESOLUTION_DETAILS_TYPEHASH = keccak256(\n    \"MetaTxDisputeResolutionDetails(uint256 exchangeId,uint256 buyerPercentBasisPoints,bytes32 sigR,bytes32 sigS,uint8 sigV)\"\n);\nbytes32 constant META_TX_DISPUTE_RESOLUTIONS_TYPEHASH = keccak256(\n    \"MetaTxDisputeResolution(uint256 nonce,address from,address contractAddress,string functionName,MetaTxDisputeResolutionDetails disputeResolutionDetails)MetaTxDisputeResolutionDetails(uint256 exchangeId,uint256 buyerPercentBasisPoints,bytes32 sigR,bytes32 sigS,uint8 sigV)\"\n);\n\n// Function names\nstring constant COMMIT_TO_OFFER = \"commitToOffer(address,uint256)\";\nstring constant COMMIT_TO_CONDITIONAL_OFFER = \"commitToConditionalOffer(address,uint256,uint256)\";\nstring constant CANCEL_VOUCHER = \"cancelVoucher(uint256)\";\nstring constant REDEEM_VOUCHER = \"redeemVoucher(uint256)\";\nstring constant COMPLETE_EXCHANGE = \"completeExchange(uint256)\";\nstring constant WITHDRAW_FUNDS = \"withdrawFunds(uint256,address[],uint256[])\";\nstring constant RETRACT_DISPUTE = \"retractDispute(uint256)\";\nstring constant RAISE_DISPUTE = \"raiseDispute(uint256)\";\nstring constant ESCALATE_DISPUTE = \"escalateDispute(uint256)\";\nstring constant RESOLVE_DISPUTE = \"resolveDispute(uint256,uint256,bytes32,bytes32,uint8)\";\n"
      },
      "contracts/domain/BosonErrors.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.22;\n\nimport { BosonTypes } from \"./BosonTypes.sol\";\n\ninterface BosonErrors {\n    // Pause related\n    // Trying to unpause a protocol when it's not paused\n    error NotPaused();\n    // Whenever a region is paused, and a method from that region is called\n    error RegionPaused(BosonTypes.PausableRegion region);\n\n    // General\n    // Input parameter of type address is zero address\n    error InvalidAddress();\n    // Exchange or dispute is in different state than expected when certain action is called\n    error InvalidState();\n    // Two or more array parameters with different lengths\n    error ArrayLengthMismatch();\n\n    // Reentrancy guard\n    // Reentrancy guard is active and second call to protocol is made\n    error ReentrancyGuard();\n\n    // Protocol initialization related\n    // Trying to initialize the facet when it's already initialized\n    error AlreadyInitialized(); // ToDo consider adding the facet to the error message\n    // Initialization of some facet failed\n    error ProtocolInitializationFailed(); // ToDo consider adding the facet to the error message\n    // Trying to initialize the protocol with empty version\n    error VersionMustBeSet();\n    // Length of _addresses and _calldata arrays do not match\n    error AddressesAndCalldataLengthMismatch(); // ToDo consider reusing ArrayLengthMismatch\n    // The new protocol version is not subsequent to the current one\n    error WrongCurrentVersion();\n    // Initialization can be done only through proxy\n    error DirectInitializationNotAllowed();\n    // Initialization of v2.3.0 can be done only if not twin exists\n    error TwinsAlreadyExist();\n\n    // Access related\n    // ToDo consider having a single error, with a parameter for the role\n    // Caller is not authorized to call the method\n    error AccessDenied();\n    // Caller is not entitiy's assistant\n    error NotAssistant();\n    // Caller is not entitiy's admin\n    error NotAdmin();\n    // Caller is not entitiy's admin and assistant\n    error NotAdminAndAssistant();\n    // Caller is neither the buyer or the seller involved in the exchange\n    error NotBuyerOrSeller();\n    // Caller is not the owner of the voucher\n    error NotVoucherHolder();\n    // Caller is not the buyer\n    error NotBuyerWallet();\n    // Caller is not the agent\n    error NotAgentWallet();\n    // Caller is not dispute resolver assistant\n    error NotDisputeResolverAssistant();\n    // Supplied clerk is not zero address\n    error ClerkDeprecated();\n\n    // Account-related\n    // Entity must be active\n    error MustBeActive();\n    // Seller's address cannot be already used in another seller\n    error SellerAddressMustBeUnique();\n    // Buyer's address cannot be already used in another buyer\n    error BuyerAddressMustBeUnique();\n    // DR's address cannot be already used in another DR\n    error DisputeResolverAddressMustBeUnique();\n    // Agent's address cannot be already used in another agent\n    error AgentAddressMustBeUnique();\n    // Seller does not exist\n    error NoSuchSeller();\n    // Buyer does not exist\n    error NoSuchBuyer();\n    // Dispute resolver does not exist\n    error NoSuchDisputeResolver();\n    // Agent does not exist\n    error NoSuchAgent();\n    // Buyer is involved in an non-finalized exchange\n    error WalletOwnsVouchers();\n    // Escalation period is not greater than zero or is more than the max allowed\n    error InvalidEscalationPeriod();\n    // Action would remove the last supported fee from the DR (must always have at least one)\n    error InexistentDisputeResolverFees();\n    // Trying to add a fee that already exists\n    error DuplicateDisputeResolverFees();\n    // Trying to add a fee with non-zero amount\n    error FeeAmountNotYetSupported();\n    // Trying to remove a fee that does not exist\n    error DisputeResolverFeeNotFound();\n    // Trying to approve a seller that is already approved (list of sellers that DR will handle disputes for)\n    error SellerAlreadyApproved();\n    // Trying to assing a DR that had not approved the seller\n    error SellerNotApproved();\n    // Trying to add or removed 0 sellers\n    error InexistentAllowedSellersList();\n    // Custom auth token is not yet supported\n    error InvalidAuthTokenType();\n    // Seller must use either and address or auth token for authentication, but not both\n    error AdminOrAuthToken();\n    // A single auth token can only be used by one seller\n    error AuthTokenMustBeUnique();\n    // Sum of protocol and agent fee exceed the max allowed fee\n    error InvalidAgentFeePercentage();\n    // Trying to finalize the update, while it's not even started\n    error NoPendingUpdateForAccount();\n    // Only the account itself can finalize the update\n    error UnauthorizedCallerUpdate();\n    // Trying to update the account with the same values\n    error NoUpdateApplied();\n    // Creating a seller's collection failed\n    error CloneCreationFailed();\n    // Seller's salt is already used by another seller\n    error SellerSaltNotUnique();\n\n    // Offer related\n    // Offer does not exist\n    error NoSuchOffer();\n    // Offer finishes in the past or it starts after it finishes\n    error InvalidOfferPeriod();\n    // Buyer cancellation penalty is higher than the item price\n    error InvalidOfferPenalty();\n    // New offer must be actiove\n    error OfferMustBeActive();\n    // Offer can be added to same group only once\n    error OfferMustBeUnique();\n    // Offer has been voided\n    error OfferHasBeenVoided();\n    // Current timestamp is higher than offer's expiry timestamp\n    error OfferHasExpired();\n    // Current timestamp is lower than offer's start timestamp\n    error OfferNotAvailable();\n    // Offer's quantity available is zero\n    error OfferSoldOut();\n    // Buyer is not allowed to commit to the offer (does not meet the token gating requirements)\n    error CannotCommit();\n    // Bundle cannot be created since exchganes for offer exist already\n    error ExchangeForOfferExists();\n    // Voucher must have either a fixed expiry or a fixed redeemable period, not both\n    error AmbiguousVoucherExpiry();\n    // Redemption period starts after it ends or it ends before offer itself expires\n    error InvalidRedemptionPeriod();\n    // Dispute period is less than minimal dispute period allowed\n    error InvalidDisputePeriod();\n    // Resolution period is not within the allowed range or it's being misconfigured (minimal > maximal)\n    error InvalidResolutionPeriod();\n    // Dispute resolver does not exist or is not active\n    error InvalidDisputeResolver();\n    // Quantity available is zero\n    error InvalidQuantityAvailable();\n    // Chose DR does not support the fees in the chosen exchange token\n    error DRUnsupportedFee();\n    // Sum of protocol and agent fee exceeds the max allowed fee\n    error AgentFeeAmountTooHigh();\n    // Sum of protocol and agent fee exceeds the seller defined max fee\n    error TotalFeeExceedsLimit();\n    // Collection does not exist\n    error NoSuchCollection();\n    // Royalty recipient is not allow listed for the seller\n    error InvalidRoyaltyRecipient();\n    // Total royality fee exceeds the max allowed\n    error InvalidRoyaltyPercentage();\n    // Specified royalty recipient already added\n    error RecipientNotUnique();\n    // Trying to access an out of bounds royalty recipient\n    error InvalidRoyaltyRecipientId();\n    // Array of royalty recipients is not sorted by id\n    error RoyaltyRecipientIdsNotSorted();\n    // Trying to remove the default recipient (treasury)\n    error CannotRemoveDefaultRecipient();\n    // Supplying too many Royalty info structs\n    error InvalidRoyaltyInfo();\n    // Trying to change the default recipient address (treasury)\n    error WrongDefaultRecipient();\n    // Price discovery offer has non zero price\n    error InvalidPriceDiscoveryPrice();\n\n    // Group related\n    // Group does not exist\n    error NoSuchGroup();\n    // Offer is not in a group\n    error OfferNotInGroup();\n    // Group remains the same\n    error NothingUpdated();\n    // There is a logical error in the group's condition parameters or it's not supported yet\n    error InvalidConditionParameters();\n    // Group does not have a condition\n    error GroupHasNoCondition();\n    // Group has a condition\n    error GroupHasCondition();\n    // User exhaused the number of commits allowed for the group\n    error MaxCommitsReached();\n    // The supplied token id is outside the condition's range\n    error TokenIdNotInConditionRange();\n    // ERC20 and ERC721 require zero token id\n    error InvalidTokenId();\n\n    // Exchange related\n    // Exchange does not exist\n    error NoSuchExchange();\n    // Exchange cannot be completed yet\n    error DisputePeriodNotElapsed();\n    // Current timestamp is outside the voucher's redeemable period\n    error VoucherNotRedeemable();\n    // New expiration date is earlier than existing expiration date\n    error VoucherExtensionNotValid();\n    // Voucher cannot be expired yet\n    error VoucherStillValid();\n    // Voucher has expired and cannot be transferred anymore\n    error VoucherHasExpired();\n    // Exchange has not been finalized yet\n    error ExchangeIsNotInAFinalState();\n    // Exchange with the same id already exists\n    error ExchangeAlreadyExists();\n    // Range length is 0, is more than quantity available or it would cause an overflow\n    error InvalidRangeLength();\n    // Exchange is being finalized into an invalid state\n    error InvalidTargeExchangeState();\n\n    // Twin related\n    // Twin does not exist\n    error NoSuchTwin();\n    // Seller did not approve the twin transfer\n    error NoTransferApproved();\n    // Twin transfer failed\n    error TwinTransferUnsuccessful();\n    // Token address is 0 or it does not implement the required interface\n    error UnsupportedToken();\n    // Twin cannot be removed if it's in a bundle\n    error BundleForTwinExists();\n    // Supply available is zero\n    error InvalidSupplyAvailable();\n    // Twin is Fungible or Multitoken and amount was set\n    error InvalidAmount();\n    // Twin is NonFungible and amount was not set\n    error InvalidTwinProperty(); // ToDo consider replacing with InvalidAmount\n    // Token range overlap with another, starting token id is too high or end of range would overflow\n    error InvalidTwinTokenRange();\n    // Token does not support IERC721 interface\n    error InvalidTokenAddress();\n\n    // Bundle related\n    // Bundle does not exist\n    error NoSuchBundle();\n    // Twin is not in a bundle\n    error TwinNotInBundle();\n    // Offer is not in a bundle\n    error OfferNotInBundle();\n    // Offer can appear in a bundle only once\n    error BundleOfferMustBeUnique();\n    // Twin can appear in a bundle only once\n    error BundleTwinMustBeUnique();\n    // Twin supply does not covver all offers in the bundle\n    error InsufficientTwinSupplyToCoverBundleOffers();\n    // Bundle cannot be created without an offer or a twin\n    error BundleRequiresAtLeastOneTwinAndOneOffer();\n\n    // Funds related\n    // Native token must be represented with zero address\n    error NativeWrongAddress();\n    // Amount sent along (msg.value) does not match the expected amount\n    error NativeWrongAmount();\n    // Token list lenght does not match the amount list length\n    error TokenAmountMismatch(); // ToDo consider replacing with ArrayLengthMismatch\n    // Token list is empty\n    error NothingToWithdraw();\n    // Call is not allowed to transfer the funds\n    error NotAuthorized();\n    // Token transfer failed\n    error TokenTransferFailed();\n    // Received amount does not match the expected amount\n    error InsufficientValueReceived();\n    // Seller's pool does not have enough funds to encumber\n    error InsufficientAvailableFunds();\n    // Native token was sent when ERC20 was expected\n    error NativeNotAllowed();\n    // Trying to deposit zero amount\n    error ZeroDepositNotAllowed();\n\n    // Meta-Transactions related\n    // Meta-transaction nonce is invalid\n    error NonceUsedAlready();\n    // Signature does not match the signer\n    error SignerAndSignatureDoNotMatch();\n    // Function signature does not match it's name\n    error InvalidFunctionName();\n    // Signature has invalid parameters\n    error InvalidSignature();\n    // Function is not allowed to be executed as a meta-transaction\n    error FunctionNotAllowlisted();\n\n    // Dispute related\n    // Dispute cannot be raised since the period to do it has elapsed\n    error DisputePeriodHasElapsed();\n    // Dispute cannot be resolved anymore and must be finalized with expireDispute\n    error DisputeHasExpired();\n    // Buyer gets more than 100% of the total pot\n    error InvalidBuyerPercent();\n    // Dispute is still valid and cannot be expired yet\n    error DisputeStillValid();\n    // New dispute timeout is earlier than existing dispute timeout\n    error InvalidDisputeTimeout();\n    // Absolute zero offers cannot be escalated\n    error EscalationNotAllowed();\n    // Dispute is being finalized into an invalid state\n    error InvalidTargeDisputeState();\n\n    // Config related\n    // Percentage exceeds 100%\n    error InvalidFeePercentage();\n    // Zero config value is not allowed\n    error ValueZeroNotAllowed();\n\n    // BosonVoucher\n    // Trying to issue an voucher that is in a reseverd range\n    error ExchangeIdInReservedRange();\n    // Trying to premint vouchers for an offer that does not have a reserved range\n    error NoReservedRangeForOffer();\n    // Trying to reserve a range that is already reserved\n    error OfferRangeAlreadyReserved();\n    // Range start at 0 is not allowed\n    error InvalidRangeStart();\n    // Amount to premint exceeds the range length\n    error InvalidAmountToMint();\n    // Trying to silent mint vouchers not belonging to the range owner\n    error NoSilentMintAllowed();\n    // Trying to premint the voucher of already expired offer\n    error OfferExpiredOrVoided();\n    // Trying to burn preminted vouchers of still valid offer\n    error OfferStillValid();\n    // Trying to burn more vouchers than available\n    error AmountExceedsRangeOrNothingToBurn();\n    // Royalty fee exceeds the max allowed\n    error InvalidRoyaltyFee();\n    // Trying to assign the premined vouchers to the address that is neither the contract owner nor the contract itself\n    error InvalidToAddress();\n    // Call to an external contract was not successful\n    error ExternalCallFailed();\n    // Trying to interact with external contract in a way that could result in transferring assets from the contract\n    error InteractionNotAllowed();\n\n    // Price discovery related\n    // Price discovery returned a price that does not match the expected one\n    error PriceMismatch();\n    // Token id is mandatory for bid orders and wrappers\n    error TokenIdMandatory();\n    // Incoming token id does not match the expected one\n    error TokenIdMismatch();\n    // Using price discovery for non-price discovery offer or using ordinary commit for price discovery offer\n    error InvalidPriceType();\n    // Missing price discovery contract address or data\n    error InvalidPriceDiscovery();\n    // Trying to set incoming voucher when it's already set, indicating reentrancy\n    error IncomingVoucherAlreadySet();\n    // Conduit address must be zero ()\n    error InvalidConduitAddress();\n    // Protocol does not know what token id to use\n    error TokenIdNotSet();\n    // Transferring a preminted voucher to wrong recipient\n    error VoucherTransferNotAllowed();\n    // Price discovery contract returned a negative price\n    error NegativePriceNotAllowed();\n    // Price discovery did not send the voucher to the protocol\n    error VoucherNotReceived();\n    // Price discovery did not send the voucher from the protocol\n    error VoucherNotTransferred();\n    // Either token with wrong id received or wrong voucher contract made the transfer\n    error UnexpectedERC721Received();\n    // Royalty fee exceeds the price\n    error FeeAmountTooHigh();\n    // Price does not cover the cancellation penalty\n    error PriceDoesNotCoverPenalty();\n}\n"
      },
      "contracts/domain/BosonTypes.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.22;\n\n/**\n * @title BosonTypes\n *\n * @notice Enums and structs used by the Boson Protocol contract ecosystem.\n */\n\ncontract BosonTypes {\n    enum PausableRegion {\n        Offers,\n        Twins,\n        Bundles,\n        Groups,\n        Sellers,\n        Buyers,\n        DisputeResolvers,\n        Agents,\n        Exchanges,\n        Disputes,\n        Funds,\n        Orchestration,\n        MetaTransaction,\n        PriceDiscovery,\n        SequentialCommit\n    }\n\n    enum EvaluationMethod {\n        None, // None should always be at index 0. Never change this value.\n        Threshold,\n        SpecificToken\n    }\n\n    enum GatingType {\n        PerAddress,\n        PerTokenId\n    }\n\n    enum ExchangeState {\n        Committed,\n        Revoked,\n        Canceled,\n        Redeemed,\n        Completed,\n        Disputed\n    }\n\n    enum DisputeState {\n        Resolving,\n        Retracted,\n        Resolved,\n        Escalated,\n        Decided,\n        Refused\n    }\n\n    enum TokenType {\n        FungibleToken,\n        NonFungibleToken,\n        MultiToken\n    } // ERC20, ERC721, ERC1155\n\n    enum MetaTxInputType {\n        Generic,\n        CommitToOffer,\n        Exchange,\n        Funds,\n        CommitToConditionalOffer,\n        ResolveDispute\n    }\n\n    enum AuthTokenType {\n        None,\n        Custom, // For future use\n        Lens,\n        ENS\n    }\n\n    enum SellerUpdateFields {\n        Admin,\n        Assistant,\n        Clerk, // Deprecated.\n        AuthToken\n    }\n\n    enum DisputeResolverUpdateFields {\n        Admin,\n        Assistant,\n        Clerk // Deprecated.\n    }\n\n    enum PriceType {\n        Static, // Default should always be at index 0. Never change this value.\n        Discovery\n    }\n\n    struct AuthToken {\n        uint256 tokenId;\n        AuthTokenType tokenType;\n    }\n\n    struct Seller {\n        uint256 id;\n        address assistant;\n        address admin;\n        address clerk; // Deprecated. Kept for backwards compatibility.\n        address payable treasury;\n        bool active;\n        string metadataUri;\n    }\n\n    struct Buyer {\n        uint256 id;\n        address payable wallet;\n        bool active;\n    }\n\n    struct RoyaltyRecipient {\n        uint256 id;\n        address payable wallet;\n    }\n\n    struct DisputeResolver {\n        uint256 id;\n        uint256 escalationResponsePeriod;\n        address assistant;\n        address admin;\n        address clerk; // Deprecated. Kept for backwards compatibility.\n        address payable treasury;\n        string metadataUri;\n        bool active;\n    }\n\n    struct DisputeResolverFee {\n        address tokenAddress;\n        string tokenName;\n        uint256 feeAmount;\n    }\n\n    struct Agent {\n        uint256 id;\n        uint256 feePercentage;\n        address payable wallet;\n        bool active;\n    }\n\n    struct DisputeResolutionTerms {\n        uint256 disputeResolverId;\n        uint256 escalationResponsePeriod;\n        uint256 feeAmount;\n        uint256 buyerEscalationDeposit;\n    }\n\n    struct Offer {\n        uint256 id;\n        uint256 sellerId;\n        uint256 price;\n        uint256 sellerDeposit;\n        uint256 buyerCancelPenalty;\n        uint256 quantityAvailable;\n        address exchangeToken;\n        PriceType priceType;\n        string metadataUri;\n        string metadataHash;\n        bool voided;\n        uint256 collectionIndex;\n        RoyaltyInfo[] royaltyInfo;\n    }\n\n    struct OfferDates {\n        uint256 validFrom;\n        uint256 validUntil;\n        uint256 voucherRedeemableFrom;\n        uint256 voucherRedeemableUntil;\n    }\n\n    struct OfferDurations {\n        uint256 disputePeriod;\n        uint256 voucherValid;\n        uint256 resolutionPeriod;\n    }\n\n    struct Group {\n        uint256 id;\n        uint256 sellerId;\n        uint256[] offerIds;\n    }\n\n    struct Condition {\n        EvaluationMethod method;\n        TokenType tokenType;\n        address tokenAddress;\n        GatingType gating; // added in v2.3.0. All conditions created before that have a default value of \"PerAddress\"\n        uint256 minTokenId;\n        uint256 threshold;\n        uint256 maxCommits;\n        uint256 maxTokenId;\n    }\n\n    struct Exchange {\n        uint256 id;\n        uint256 offerId;\n        uint256 buyerId;\n        uint256 finalizedDate;\n        ExchangeState state;\n    }\n\n    struct ExchangeCosts {\n        uint256 resellerId;\n        uint256 price;\n        uint256 protocolFeeAmount;\n        uint256 royaltyAmount;\n        uint256 royaltyInfoIndex;\n    }\n\n    struct Voucher {\n        uint256 committedDate;\n        uint256 validUntilDate;\n        uint256 redeemedDate;\n        bool expired;\n    }\n\n    struct Dispute {\n        uint256 exchangeId;\n        uint256 buyerPercent;\n        DisputeState state;\n    }\n\n    struct DisputeDates {\n        uint256 disputed;\n        uint256 escalated;\n        uint256 finalized;\n        uint256 timeout;\n    }\n\n    struct Receipt {\n        uint256 exchangeId;\n        uint256 offerId;\n        uint256 buyerId;\n        uint256 sellerId;\n        uint256 price;\n        uint256 sellerDeposit;\n        uint256 buyerCancelPenalty;\n        OfferFees offerFees;\n        uint256 agentId;\n        address exchangeToken;\n        uint256 finalizedDate;\n        Condition condition;\n        uint256 committedDate;\n        uint256 redeemedDate;\n        bool voucherExpired;\n        uint256 disputeResolverId;\n        uint256 disputedDate;\n        uint256 escalatedDate;\n        DisputeState disputeState;\n        TwinReceipt[] twinReceipts;\n    }\n\n    struct TokenRange {\n        uint256 start;\n        uint256 end;\n        uint256 twinId;\n    }\n\n    struct Twin {\n        uint256 id;\n        uint256 sellerId;\n        uint256 amount; // ERC1155 / ERC20 (amount to be transferred to each buyer on redemption)\n        uint256 supplyAvailable; // all\n        uint256 tokenId; // ERC1155 / ERC721 (must be initialized with the initial pointer position of the ERC721 ids available range)\n        address tokenAddress; // all\n        TokenType tokenType;\n    }\n\n    struct TwinReceipt {\n        uint256 twinId;\n        uint256 tokenId; // only for ERC721 and ERC1155\n        uint256 amount; // only for ERC1155 and ERC20\n        address tokenAddress;\n        TokenType tokenType;\n    }\n\n    struct Bundle {\n        uint256 id;\n        uint256 sellerId;\n        uint256[] offerIds;\n        uint256[] twinIds;\n    }\n\n    struct Funds {\n        address tokenAddress;\n        string tokenName;\n        uint256 availableAmount;\n    }\n\n    struct MetaTransaction {\n        uint256 nonce;\n        address from;\n        address contractAddress;\n        string functionName;\n        bytes functionSignature;\n    }\n\n    struct HashInfo {\n        bytes32 typeHash;\n        function(bytes memory) internal pure returns (bytes32) hashFunction;\n    }\n\n    struct OfferFees {\n        uint256 protocolFee;\n        uint256 agentFee;\n    }\n\n    struct VoucherInitValues {\n        string contractURI;\n        uint256 royaltyPercentage;\n        bytes32 collectionSalt;\n    }\n\n    struct Collection {\n        address collectionAddress;\n        string externalId;\n    }\n\n    struct PriceDiscovery {\n        uint256 price;\n        Side side;\n        address priceDiscoveryContract;\n        address conduit;\n        bytes priceDiscoveryData;\n    }\n\n    enum Side {\n        Ask,\n        Bid,\n        Wrapper // Side is not relevant from the protocol perspective\n    }\n\n    struct RoyaltyInfo {\n        address payable[] recipients;\n        uint256[] bps;\n    }\n\n    struct RoyaltyRecipientInfo {\n        address payable wallet;\n        uint256 minRoyaltyPercentage;\n    }\n\n    struct PremintParameters {\n        uint256 reservedRangeLength;\n        address to;\n    }\n\n    struct Payoff {\n        uint256 seller;\n        uint256 buyer;\n        uint256 protocol;\n        uint256 agent;\n    }\n}\n"
      },
      "contracts/interfaces/clients/IBosonVoucher.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.22;\n\nimport { IERC721Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol\";\nimport { IERC721MetadataUpgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable.sol\";\nimport { IERC721ReceiverUpgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol\";\n\n/**\n * @title IBosonVoucher\n *\n * @notice This is the interface for the Boson Protocol ERC-721 Voucher contract.\n *\n * The ERC-165 identifier for this interface is: 0x6a474d2c\n */\ninterface IBosonVoucher is IERC721Upgradeable, IERC721MetadataUpgradeable, IERC721ReceiverUpgradeable {\n    event ContractURIChanged(string contractURI);\n    event VoucherInitialized(uint256 indexed sellerId, string indexed contractURI);\n    event RangeReserved(uint256 indexed offerId, Range range);\n    event VouchersPreMinted(uint256 indexed offerId, uint256 startId, uint256 endId);\n\n    // Describe a reserved range of token ids\n    struct Range {\n        uint256 start; // First token id of range\n        uint256 length; // Length of range\n        uint256 minted; // Amount pre-minted so far\n        uint256 lastBurnedTokenId; // Last burned token id\n        address owner; // The range owner\n    }\n\n    /**\n     * @notice Issues a voucher to a buyer.\n     *\n     * Minted voucher supply is sent to the buyer.\n     * Caller must have PROTOCOL role.\n     *\n     * @param _tokenId - voucher token id corresponds to <<uint128(offerId)>>.<<uint128(exchangeId)>>\n     * @param _buyer - the buyer address\n     */\n    function issueVoucher(uint256 _tokenId, address _buyer) external;\n\n    /**\n     * @notice Burns a voucher.\n     *\n     * Caller must have PROTOCOL role.\n     *\n     * @param _tokenId - voucher token id corresponds to <<uint128(offerId)>>.<<uint128(exchangeId)>>\n     */\n    function burnVoucher(uint256 _tokenId) external;\n\n    /**\n     * @notice Gets the seller id.\n     *\n     * @return the id for the Voucher seller\n     */\n    function getSellerId() external view returns (uint256);\n\n    /**\n     * @notice Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the protocol. Change is done by calling `updateSeller` on the protocol.\n     *\n     * @param newOwner - the address to which ownership of the voucher contract will be transferred\n     */\n    function transferOwnership(address newOwner) external;\n\n    /**\n     * @notice Returns storefront-level metadata used by OpenSea.\n     *\n     * @return Contract metadata URI\n     */\n    function contractURI() external view returns (string memory);\n\n    /**\n     * @notice Sets new contract URI.\n     * Can only be called by the owner or during the initialization.\n     *\n     * @param _newContractURI - new contract metadata URI\n     */\n    function setContractURI(string calldata _newContractURI) external;\n\n    /**\n     * @notice Provides royalty info.\n     * Called with the sale price to determine how much royalty is owed and to whom.\n     *\n     * @param _tokenId - the voucher queried for royalty information\n     * @param _salePrice - the sale price of the voucher specified by _tokenId\n     *\n     * @return receiver - address of who should be sent the royalty payment\n     * @return royaltyAmount - the royalty payment amount for the given sale price\n     */\n    function royaltyInfo(\n        uint256 _tokenId,\n        uint256 _salePrice\n    ) external view returns (address receiver, uint256 royaltyAmount);\n\n    /**\n     * @notice Reserves a range of vouchers to be associated with an offer\n     *\n     * Must happen prior to calling preMint\n     * Caller must have PROTOCOL role.\n     *\n     * Reverts if:\n     * - Start id is not greater than zero for the first range\n     * - Start id is not greater than the end id of the previous range for subsequent ranges\n     * - Range length is zero\n     * - Range length is too large, i.e., would cause an overflow\n     * - Offer id is already associated with a range\n     * - _to is not the contract address or the contract owner\n     *\n     * @param _offerId - the id of the offer\n     * @param _start - the first id of the token range\n     * @param _length - the length of the range\n     * @param _to - the address to send the pre-minted vouchers to (contract address or contract owner)\n     */\n    function reserveRange(uint256 _offerId, uint256 _start, uint256 _length, address _to) external;\n\n    /**\n     * @notice Pre-mints all or part of an offer's reserved vouchers.\n     *\n     * For small offer quantities, this method may only need to be\n     * called once.\n     *\n     * But, if the range is large, e.g., 10k vouchers, block gas limit\n     * could cause the transaction to fail. Thus, in order to support\n     * a batched approach to pre-minting an offer's vouchers,\n     * this method can be called multiple times, until the whole\n     * range is minted.\n     *\n     * A benefit to the batched approach is that the entire reserved\n     * range for an offer need not be pre-minted at one time. A seller\n     * could just mint batches periodically, controlling the amount\n     * that are available on the market at any given time, e.g.,\n     * creating a pre-minted offer with a validity period of one year,\n     * causing the token range to be reserved, but only pre-minting\n     * a certain amount monthly.\n     *\n     * Caller must be contract owner (seller assistant address).\n     *\n     * Reverts if:\n     * - Offer id is not associated with a range\n     * - Amount to mint is more than remaining un-minted in range\n     * - Too many to mint in a single transaction, given current block gas limit\n     *\n     * @param _offerId - the id of the offer\n     * @param _amount - the amount to mint\n     */\n    function preMint(uint256 _offerId, uint256 _amount) external;\n\n    /**\n     * @notice Burn all or part of an offer's preminted vouchers.\n     * If offer expires or it's voided, the seller can burn the preminted vouchers that were not transferred yet.\n     * This way they will not show in seller's wallet and marketplaces anymore.\n     *\n     * For small offer quantities, this method may only need to be\n     * called once.\n     *\n     * But, if the range is large, e.g., 10k vouchers, block gas limit\n     * could cause the transaction to fail. Thus, in order to support\n     * a batched approach to pre-minting an offer's vouchers,\n     * this method can be called multiple times, until the whole\n     * range is burned.\n     *\n     * Caller must be contract owner (seller assistant address).\n     *\n     * Reverts if:\n     * - Offer id is not associated with a range\n     * - Offer is not expired or voided\n     * - There is nothing to burn\n     *\n     * @param _offerId - the id of the offer\n     * @param _amount - amount to burn\n     */\n    function burnPremintedVouchers(uint256 _offerId, uint256 _amount) external;\n\n    /**\n     * @notice Gets the number of vouchers available to be pre-minted for an offer.\n     *\n     * @param _offerId - the id of the offer\n     * @return count - the count of vouchers in reserved range available to be pre-minted\n     */\n    function getAvailablePreMints(uint256 _offerId) external view returns (uint256 count);\n\n    /**\n     * @notice Gets the range for an offer.\n     *\n     * @param _offerId - the id of the offer\n     * @return range - range struct with information about range start, length and already minted tokens\n     */\n    function getRangeByOfferId(uint256 _offerId) external view returns (Range memory range);\n\n    /**\n     * @notice Make a call to an external contract.\n     *\n     * Reverts if:\n     * - _to is zero address\n     * - call to external contract fails\n     * - caller is not the owner\n     * - _to is a contract that represents some assets (all contracts that implement `balanceOf` method, including ERC20 and ERC721)\n     *\n     * @param _to - address of the contract to call\n     * @param _data - data to pass to the external contract\n     * @return result - result of the call\n     */\n    function callExternalContract(address _to, bytes memory _data) external payable returns (bytes memory);\n\n    /** @notice Set approval for all to the vouchers owned by this contract\n     *\n     * Reverts if:\n     * - _operator is zero address\n     * - caller is not the owner\n     * - _operator is this contract\n     *\n     * @param _operator - address of the operator to set approval for\n     * @param _approved - true to approve the operator in question, false to revoke approval\n     */\n    function setApprovalForAllToContract(address _operator, bool _approved) external;\n\n    /**\n     * @notice Withdraw funds from the contract to the protocol seller pool\n     *\n     * @param _tokenList - list of tokens to withdraw, including native token (address(0))\n     */\n    function withdrawToProtocol(address[] calldata _tokenList) external;\n}\n"
      },
      "contracts/interfaces/diamond/IDiamondCut.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\n/**\n * @title IDiamondCut\n *\n * @notice Manages Diamond Facets.\n *\n * Reference Implementation  : https://github.com/mudgen/diamond-2-hardhat\n * EIP-2535 Diamond Standard : https://eips.ethereum.org/EIPS/eip-2535\n *\n * The ERC-165 identifier for this interface is: 0x1f931c1c\n *\n * @author Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)\n */\ninterface IDiamondCut {\n    event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);\n\n    enum FacetCutAction {\n        Add,\n        Replace,\n        Remove\n    }\n\n    struct FacetCut {\n        address facetAddress;\n        FacetCutAction action;\n        bytes4[] functionSelectors;\n    }\n\n    /**\n     * @notice Cuts facets of the Diamond.\n     *\n     * Adds/replaces/removes any number of function selectors.\n     *\n     * If populated, _calldata is executed with delegatecall on _init\n     *\n     * Reverts if caller does not have UPGRADER role\n     *\n     * @param _facetCuts - contains the facet addresses and function selectors\n     * @param _init - the address of the contract or facet to execute _calldata\n     * @param _calldata - a function call, including function selector and arguments\n     */\n    function diamondCut(FacetCut[] calldata _facetCuts, address _init, bytes calldata _calldata) external;\n}\n"
      },
      "contracts/interfaces/events/IBosonAccountEvents.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.22;\n\nimport { BosonTypes } from \"../../domain/BosonTypes.sol\";\n\n/**\n * @title IBosonAccountEvents\n *\n * @notice Defines events related to management of accounts within the protocol.\n */\ninterface IBosonAccountEvents {\n    event SellerCreated(\n        uint256 indexed sellerId,\n        BosonTypes.Seller seller,\n        address voucherCloneAddress,\n        BosonTypes.AuthToken authToken,\n        address indexed executedBy\n    );\n    event SellerUpdatePending(\n        uint256 indexed sellerId,\n        BosonTypes.Seller pendingSeller,\n        BosonTypes.AuthToken pendingAuthToken,\n        address indexed executedBy\n    );\n    event SellerUpdateApplied(\n        uint256 indexed sellerId,\n        BosonTypes.Seller seller,\n        BosonTypes.Seller pendingSeller,\n        BosonTypes.AuthToken authToken,\n        BosonTypes.AuthToken pendingAuthToken,\n        address indexed executedBy\n    );\n    event RoyaltyRecipientsChanged(\n        uint256 indexed sellerId,\n        BosonTypes.RoyaltyRecipientInfo[] royaltyRecipients,\n        address indexed executedBy\n    );\n    event BuyerCreated(uint256 indexed buyerId, BosonTypes.Buyer buyer, address indexed executedBy);\n    event BuyerUpdated(uint256 indexed buyerId, BosonTypes.Buyer buyer, address indexed executedBy);\n    event AgentUpdated(uint256 indexed agentId, BosonTypes.Agent agent, address indexed executedBy);\n    event DisputeResolverCreated(\n        uint256 indexed disputeResolverId,\n        BosonTypes.DisputeResolver disputeResolver,\n        BosonTypes.DisputeResolverFee[] disputeResolverFees,\n        uint256[] sellerAllowList,\n        address indexed executedBy\n    );\n    event DisputeResolverUpdatePending(\n        uint256 indexed disputeResolverId,\n        BosonTypes.DisputeResolver pendingDisputeResolver,\n        address indexed executedBy\n    );\n    event DisputeResolverUpdateApplied(\n        uint256 indexed disputeResolverId,\n        BosonTypes.DisputeResolver disputeResolver,\n        BosonTypes.DisputeResolver pendingDisputeResolver,\n        address indexed executedBy\n    );\n    event DisputeResolverFeesAdded(\n        uint256 indexed disputeResolverId,\n        BosonTypes.DisputeResolverFee[] disputeResolverFees,\n        address indexed executedBy\n    );\n    event DisputeResolverFeesRemoved(\n        uint256 indexed disputeResolverId,\n        address[] feeTokensRemoved,\n        address indexed executedBy\n    );\n    event AllowedSellersAdded(uint256 indexed disputeResolverId, uint256[] addedSellers, address indexed executedBy);\n    event AllowedSellersRemoved(\n        uint256 indexed disputeResolverId,\n        uint256[] removedSellers,\n        address indexed executedBy\n    );\n    event AgentCreated(uint256 indexed agentId, BosonTypes.Agent agent, address indexed executedBy);\n    event CollectionCreated(\n        uint256 indexed sellerId,\n        uint256 collectionIndex,\n        address collectionAddress,\n        string indexed externalId,\n        address indexed executedBy\n    );\n}\n"
      },
      "contracts/interfaces/events/IBosonBundleEvents.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.22;\n\nimport { BosonTypes } from \"../../domain/BosonTypes.sol\";\n\n/**\n * @title IBosonBundleEvents\n *\n * @notice Defines events related to management of bundles within the protocol.\n */\ninterface IBosonBundleEvents {\n    event BundleCreated(\n        uint256 indexed bundleId,\n        uint256 indexed sellerId,\n        BosonTypes.Bundle bundle,\n        address indexed executedBy\n    );\n}\n"
      },
      "contracts/interfaces/events/IBosonDisputeEvents.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.22;\n\nimport { BosonTypes } from \"../../domain/BosonTypes.sol\";\n\n/**\n * @title IBosonDisputeEvents\n *\n * @notice Defines events related to disputes within the protocol.\n */\ninterface IBosonDisputeEvents {\n    event DisputeRaised(\n        uint256 indexed exchangeId,\n        uint256 indexed buyerId,\n        uint256 indexed sellerId,\n        address executedBy\n    );\n    event DisputeRetracted(uint256 indexed exchangeId, address indexed executedBy);\n    event DisputeResolved(uint256 indexed exchangeId, uint256 _buyerPercent, address indexed executedBy);\n    event DisputeExpired(uint256 indexed exchangeId, address indexed executedBy);\n    event DisputeDecided(uint256 indexed exchangeId, uint256 _buyerPercent, address indexed executedBy);\n    event DisputeTimeoutExtended(uint256 indexed exchangeId, uint256 newDisputeTimeout, address indexed executedBy);\n    event DisputeEscalated(uint256 indexed exchangeId, uint256 indexed disputeResolverId, address indexed executedBy);\n    event EscalatedDisputeExpired(uint256 indexed exchangeId, address indexed executedBy);\n    event EscalatedDisputeRefused(uint256 indexed exchangeId, address indexed executedBy);\n}\n"
      },
      "contracts/interfaces/events/IBosonFundsEvents.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.22;\n\nimport { BosonTypes } from \"../../domain/BosonTypes.sol\";\n\n/**\n * @title IBosonFundsEvents\n *\n * @notice Defines events related to management of funds within the protocol.\n */\ninterface IBosonFundsEvents {\n    event FundsDeposited(\n        uint256 indexed sellerId,\n        address indexed executedBy,\n        address indexed tokenAddress,\n        uint256 amount\n    );\n}\n\ninterface IBosonFundsLibEvents {\n    event FundsEncumbered(\n        uint256 indexed entityId,\n        address indexed exchangeToken,\n        uint256 amount,\n        address indexed executedBy\n    );\n    event FundsReleased(\n        uint256 indexed exchangeId,\n        uint256 indexed entityId,\n        address indexed exchangeToken,\n        uint256 amount,\n        address executedBy\n    );\n    event ProtocolFeeCollected(\n        uint256 indexed exchangeId,\n        address indexed exchangeToken,\n        uint256 amount,\n        address indexed executedBy\n    );\n    event FundsWithdrawn(\n        uint256 indexed sellerId,\n        address indexed withdrawnTo,\n        address indexed tokenAddress,\n        uint256 amount,\n        address executedBy\n    );\n}\n"
      },
      "contracts/interfaces/events/IBosonGroupEvents.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.22;\n\nimport { BosonTypes } from \"../../domain/BosonTypes.sol\";\n\n/**\n * @title IBosonGroupEvents\n *\n * @notice Defines events related to management of groups within the protocol.\n */\ninterface IBosonGroupEvents {\n    event GroupCreated(\n        uint256 indexed groupId,\n        uint256 indexed sellerId,\n        BosonTypes.Group group,\n        BosonTypes.Condition condition,\n        address indexed executedBy\n    );\n    event GroupUpdated(\n        uint256 indexed groupId,\n        uint256 indexed sellerId,\n        BosonTypes.Group group,\n        BosonTypes.Condition condition,\n        address indexed executedBy\n    );\n}\n"
      },
      "contracts/interfaces/events/IBosonOfferEvents.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.22;\n\nimport { BosonTypes } from \"../../domain/BosonTypes.sol\";\n\n/**\n * @title IBosonOfferEvents\n *\n * @notice Defines events related to management of offers within the protocol.\n */\ninterface IBosonOfferEvents {\n    event OfferCreated(\n        uint256 indexed offerId,\n        uint256 indexed sellerId,\n        BosonTypes.Offer offer,\n        BosonTypes.OfferDates offerDates,\n        BosonTypes.OfferDurations offerDurations,\n        BosonTypes.DisputeResolutionTerms disputeResolutionTerms,\n        BosonTypes.OfferFees offerFees,\n        uint256 indexed agentId,\n        address executedBy\n    );\n    event OfferExtended(\n        uint256 indexed offerId,\n        uint256 indexed sellerId,\n        uint256 validUntilDate,\n        address indexed executedBy\n    );\n    event OfferVoided(uint256 indexed offerId, uint256 indexed sellerId, address indexed executedBy);\n    event RangeReserved(\n        uint256 indexed offerId,\n        uint256 indexed sellerId,\n        uint256 startExchangeId,\n        uint256 endExchangeId,\n        address owner,\n        address indexed executedBy\n    );\n    event OfferRoyaltyInfoUpdated(\n        uint256 indexed offerId,\n        uint256 indexed sellerId,\n        BosonTypes.RoyaltyInfo royaltyInfo,\n        address indexed executedBy\n    );\n}\n"
      },
      "contracts/interfaces/events/IBosonTwinEvents.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.22;\n\nimport { BosonTypes } from \"../../domain/BosonTypes.sol\";\n\n/**\n * @title IBosonTwinEvents\n *\n * @notice Defines events related to management of twins within the protocol.\n */\ninterface IBosonTwinEvents {\n    event TwinCreated(\n        uint256 indexed twinId,\n        uint256 indexed sellerId,\n        BosonTypes.Twin twin,\n        address indexed executedBy\n    );\n    event TwinDeleted(uint256 indexed twinId, uint256 indexed sellerId, address indexed executedBy);\n    // Amount must be 0 if token type is TokenType.NonFungible\n    // tokenId must be 0 if token type is TokenType.Fungible\n    event TwinTransferred(\n        uint256 indexed twinId,\n        address indexed tokenAddress,\n        uint256 indexed exchangeId,\n        uint256 tokenId,\n        uint256 amount,\n        address executedBy\n    );\n    event TwinTransferFailed(\n        uint256 indexed twinId,\n        address indexed tokenAddress,\n        uint256 indexed exchangeId,\n        uint256 tokenId,\n        uint256 amount,\n        address executedBy\n    );\n    event TwinTransferSkipped(uint256 indexed exchangeId, uint256 twinCount, address indexed executedBy);\n}\n"
      },
      "contracts/interfaces/handlers/IBosonOrchestrationHandler.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.22;\n\nimport { BosonTypes } from \"../../domain/BosonTypes.sol\";\nimport { BosonErrors } from \"../../domain/BosonErrors.sol\";\nimport { IBosonAccountEvents } from \"../events/IBosonAccountEvents.sol\";\nimport { IBosonGroupEvents } from \"../events/IBosonGroupEvents.sol\";\nimport { IBosonOfferEvents } from \"../events/IBosonOfferEvents.sol\";\nimport { IBosonTwinEvents } from \"../events/IBosonTwinEvents.sol\";\nimport { IBosonBundleEvents } from \"../events/IBosonBundleEvents.sol\";\n\n/**\n * @title IBosonOrchestrationHandler\n *\n * @notice Combines creation of multiple entities (accounts, offers, groups, twins, bundles) in a single transaction\n *\n * The ERC-165 identifier for this interface is: 0x44eb95ca\n */\ninterface IBosonOrchestrationHandler is\n    IBosonAccountEvents,\n    IBosonGroupEvents,\n    IBosonOfferEvents,\n    IBosonTwinEvents,\n    IBosonBundleEvents,\n    BosonErrors\n{\n    /**\n     * @notice Raises a dispute and immediately escalates it.\n     *\n     * Caller must send (or for ERC20, approve the transfer of) the\n     * buyer escalation deposit percentage of the offer price, which\n     * will be added to the pot for resolution.\n     *\n     * Emits a DisputeRaised and a DisputeEscalated event if successful.\n     *\n     * Reverts if:\n     * - The disputes region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the buyer for the given exchange id\n     * - Exchange does not exist\n     * - Exchange is not in a Redeemed state\n     * - Dispute period has elapsed already\n     * - Dispute resolver is not specified (absolute zero offer)\n     * - Offer price is in native token and caller does not send enough\n     * - Offer price is in some ERC20 token and caller also sends native currency\n     * - If contract at token address does not support ERC20 function transferFrom\n     * - If calling transferFrom on token fails for some reason (e.g. protocol is not approved to transfer)\n     * - Received ERC20 token amount differs from the expected value\n     *\n     * @param _exchangeId - the id of the associated exchange\n     */\n    function raiseAndEscalateDispute(uint256 _exchangeId) external payable;\n\n    /**\n     * @notice Creates a seller (with optional auth token) and an offer in a single transaction.\n     *\n     * Limitations:\n     * 1. If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     * 2. Only the default royalty recipient can be used. Other royalty recipients can be added to seller later and next offers can use them.\n     *\n     * Emits a SellerCreated and an OfferCreated event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Caller is not the supplied assistant\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - Seller salt is not unique\n     * - Clone creation fails\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _seller - the fully populated seller struct\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndOffer(\n        BosonTypes.Seller calldata _seller,\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.AuthToken calldata _authToken,\n        BosonTypes.VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Creates a seller (with optional auth token), an offer and reserve range for preminting in a single transaction.\n     *\n     * Limitation of the method:\n     * If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     *\n     * Emits a SellerCreated, an OfferCreated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - Caller is not the supplied assistant\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - Seller salt is not unique\n     * - Clone creation fails\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _seller - the fully populated seller struct\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndPremintedOffer(\n        BosonTypes.Seller memory _seller,\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.PremintParameters calldata _premintParameters,\n        BosonTypes.AuthToken calldata _authToken,\n        BosonTypes.VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Takes an offer and a condition, creates an offer, then creates a group with that offer and the given condition.\n     *\n     * Emits an OfferCreated and a GroupCreated event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _condition - the fully populated condition struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createOfferWithCondition(\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.Condition memory _condition,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Takes an offer, range for preminting and a condition, creates an offer, then creates a group with that offer and the given condition and then reservers range for preminting.\n     *\n     * Emits an OfferCreated, a GroupCreated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _condition - the fully populated condition struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createPremintedOfferWithCondition(\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.PremintParameters calldata _premintParameters,\n        BosonTypes.Condition calldata _condition,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Takes an offer and group ID, creates an offer and adds it to the existing group with given id.\n     *\n     * Emits an OfferCreated and a GroupUpdated event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When adding to the group if:\n     *   - Group does not exists\n     *   - Caller is not the assistant of the group\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _groupId - id of the group, to which offer will be added\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createOfferAddToGroup(\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        uint256 _groupId,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Takes an offer, a range for preminting and group ID, creates an offer and adds it to the existing group with given id and reserves the range for preminting.\n     *\n     * Emits an OfferCreated, a GroupUpdated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When adding to the group if:\n     *   - Group does not exists\n     *   - Caller is not the assistant of the group\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _groupId - id of the group, to which offer will be added\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createPremintedOfferAddToGroup(\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.PremintParameters calldata _premintParameters,\n        uint256 _groupId,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Takes an offer and a twin, creates an offer, creates a twin, then creates a bundle with that offer and the given twin.\n     *\n     * Emits an OfferCreated, a TwinCreated and a BundleCreated event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _twin - the fully populated twin struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createOfferAndTwinWithBundle(\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.Twin memory _twin,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Takes an offer, a range for preminting and a twin, creates an offer, creates a twin, then creates a bundle with that offer and the given twin and reserves the range for preminting.\n     *\n     * Emits an OfferCreated, a TwinCreated and a BundleCreated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _twin - the fully populated twin struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createPremintedOfferAndTwinWithBundle(\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.PremintParameters calldata _premintParameters,\n        BosonTypes.Twin memory _twin,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Takes an offer, a condition and a twin, creates an offer, then creates a group with that offer and the given condition.\n     * It then creates a twin, then creates a bundle with that offer and the given twin.\n     *\n     * Emits an OfferCreated, a GroupCreated, a TwinCreated and a BundleCreated event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _condition - the fully populated condition struct\n     * @param _twin - the fully populated twin struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createOfferWithConditionAndTwinAndBundle(\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.Condition memory _condition,\n        BosonTypes.Twin memory _twin,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Takes an offer, a range for preminting, a condition and a twin, creates an offer, then creates a group with that offer and the given condition.\n     * It then creates a twin, then creates a bundle with that offer and the given twin and reserves the range for preminting.\n     *\n     * Emits an OfferCreated, a GroupCreated, a TwinCreated, a BundleCreated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _condition - the fully populated condition struct\n     * @param _twin - the fully populated twin struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createPremintedOfferWithConditionAndTwinAndBundle(\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.PremintParameters calldata _premintParameters,\n        BosonTypes.Condition calldata _condition,\n        BosonTypes.Twin memory _twin,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Takes a seller, an offer, a condition and an optional auth token. Creates a seller, creates an offer,\n     * then creates a group with that offer and the given condition.\n     *\n     * Limitation of the method:\n     * If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     *\n     * Emits a SellerCreated, an OfferCreated and a GroupCreated event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Caller is not the supplied assistant\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - Seller salt is not unique\n     * - Clone creation fails\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @param _seller - the fully populated seller struct\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _condition - the fully populated condition struct\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndOfferWithCondition(\n        BosonTypes.Seller memory _seller,\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.Condition memory _condition,\n        BosonTypes.AuthToken calldata _authToken,\n        BosonTypes.VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Takes a seller, an offer, a range for preminting, a condition and an optional auth token. Creates a seller, creates an offer,\n     * then creates a group with that offer and the given condition and reserves the range for preminting.\n     *\n     * Limitation of the method:\n     * If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     *\n     * Emits a SellerCreated, an OfferCreated, a GroupCreated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied assistant\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - Seller salt is not unique\n     * - Clone creation fails\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _seller - the fully populated seller struct\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _condition - the fully populated condition struct\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndPremintedOfferWithCondition(\n        BosonTypes.Seller memory _seller,\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.PremintParameters calldata _premintParameters,\n        BosonTypes.Condition calldata _condition,\n        BosonTypes.AuthToken calldata _authToken,\n        BosonTypes.VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Takes a seller, an offer, a twin, and an optional auth token. Creates a seller, creates an offer, creates a twin,\n     * then creates a bundle with that offer and the given twin.\n     *\n     * Limitation of the method:\n     * If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     *\n     * Emits a SellerCreated, an OfferCreated, a TwinCreated and a BundleCreated event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Caller is not the supplied assistant\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - Seller salt is not unique\n     * - Clone creation fails\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @param _seller - the fully populated seller struct\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _twin - the fully populated twin struct\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndOfferAndTwinWithBundle(\n        BosonTypes.Seller memory _seller,\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.Twin memory _twin,\n        BosonTypes.AuthToken calldata _authToken,\n        BosonTypes.VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Takes a seller, an offer, a range for preminting, a twin, and an optional auth token. Creates a seller, creates an offer, creates a twin,\n     * then creates a bundle with that offer and the given twin and reserves the range for preminting.\n     *\n     * Limitation of the method:\n     * If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     *\n     * Emits a SellerCreated, an OfferCreated, a TwinCreated, a BundleCreated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied assistant\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - Seller salt is not unique\n     * - Clone creation fails\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _seller - the fully populated seller struct\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _twin - the fully populated twin struct\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndPremintedOfferAndTwinWithBundle(\n        BosonTypes.Seller memory _seller,\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.PremintParameters calldata _premintParameters,\n        BosonTypes.Twin memory _twin,\n        BosonTypes.AuthToken calldata _authToken,\n        BosonTypes.VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Takes a seller, an offer, a condition and a twin, and an optional auth token. Creates a seller an offer,\n     * then creates a group with that offer and the given condition. It then creates a twin and a bundle with that offer and the given twin.\n     *\n     * Limitation of the method:\n     * If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     *\n     * Emits an SellerCreated, OfferCreated, a GroupCreated, a TwinCreated and a BundleCreated event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Caller is not the supplied assistant\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - Seller salt is not unique\n     * - Clone creation fails\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @param _seller - the fully populated seller struct\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _condition - the fully populated condition struct\n     * @param _twin - the fully populated twin struct\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndOfferWithConditionAndTwinAndBundle(\n        BosonTypes.Seller memory _seller,\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.Condition memory _condition,\n        BosonTypes.Twin memory _twin,\n        BosonTypes.AuthToken calldata _authToken,\n        BosonTypes.VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n\n    /**\n     * @notice Takes a seller, an offer, a range for preminting, a condition and a twin, and an optional auth token. Creates a seller an offer,\n     * then creates a group with that offer and the given condition. It then creates a twin and a bundle with that offer and the given twin\n     * and reserves a range for preminting.\n     *\n     * Limitation of the method:\n     * If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     *\n     * Emits an SellerCreated, OfferCreated, a GroupCreated, a TwinCreated, a BundleCreated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied assistant\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - Seller salt is not unique\n     * - Clone creation fails\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _seller - the fully populated seller struct\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _condition - the fully populated condition struct\n     * @param _twin - the fully populated twin struct\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndPremintedOfferWithConditionAndTwinAndBundle(\n        BosonTypes.Seller memory _seller,\n        BosonTypes.Offer memory _offer,\n        BosonTypes.OfferDates calldata _offerDates,\n        BosonTypes.OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        BosonTypes.PremintParameters calldata _premintParameters,\n        BosonTypes.Condition calldata _condition,\n        BosonTypes.Twin memory _twin,\n        BosonTypes.AuthToken calldata _authToken,\n        BosonTypes.VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external;\n}\n"
      },
      "contracts/interfaces/IAccessControl.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity 0.8.22;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\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     * _Available since v3.1._\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 `account`.\n     */\n    function renounceRole(bytes32 role, address account) external;\n}\n"
      },
      "contracts/interfaces/IERC1155.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\n\npragma solidity 0.8.22;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\n *\n * _Available since v3.1._\n */\ninterface IERC1155 is IERC165 {\n    /**\n     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\n     */\n    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\n\n    /**\n     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\n     * transfers.\n     */\n    event TransferBatch(\n        address indexed operator,\n        address indexed from,\n        address indexed to,\n        uint256[] ids,\n        uint256[] values\n    );\n\n    /**\n     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\n     * `approved`.\n     */\n    event ApprovalForAll(address indexed account, address indexed operator, bool approved);\n\n    /**\n     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\n     *\n     * If an {URI} event was emitted for `id`, the standard\n     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\n     * returned by {IERC1155MetadataURI-uri}.\n     */\n    event URI(string value, uint256 indexed id);\n\n    /**\n     * @dev Returns the amount of tokens of token type `id` owned by `account`.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function balanceOf(address account, uint256 id) external view returns (uint256);\n\n    /**\n     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\n     *\n     * Requirements:\n     *\n     * - `accounts` and `ids` must have the same length.\n     */\n    function balanceOfBatch(\n        address[] calldata accounts,\n        uint256[] calldata ids\n    ) external view returns (uint256[] memory);\n\n    /**\n     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\n     *\n     * Emits an {ApprovalForAll} event.\n     *\n     * Requirements:\n     *\n     * - `operator` cannot be the caller.\n     */\n    function setApprovalForAll(address operator, bool approved) external;\n\n    /**\n     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\n     *\n     * See {setApprovalForAll}.\n     */\n    function isApprovedForAll(address account, address operator) external view returns (bool);\n\n    /**\n     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\n     *\n     * Emits a {TransferSingle} event.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\n     * - `from` must have a balance of tokens of type `id` of at least `amount`.\n     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\n     * acceptance magic value.\n     */\n    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;\n\n    /**\n     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\n     *\n     * Emits a {TransferBatch} event.\n     *\n     * Requirements:\n     *\n     * - `ids` and `amounts` must have the same length.\n     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\n     * acceptance magic value.\n     */\n    function safeBatchTransferFrom(\n        address from,\n        address to,\n        uint256[] calldata ids,\n        uint256[] calldata amounts,\n        bytes calldata data\n    ) external;\n}\n"
      },
      "contracts/interfaces/IERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity 0.8.22;\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"
      },
      "contracts/interfaces/IERC721.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\n\npragma solidity 0.8.22;\n\nimport \"./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`, 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 be 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 Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\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 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 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 caller.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool _approved) external;\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    /**\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 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"
      },
      "contracts/interfaces/IInitializableVoucherClone.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport \"../domain/BosonTypes.sol\";\n\ninterface IInitializableVoucherClone {\n    /**\n     * @notice Initializes the contract with the address of the beacon contract.\n     *\n     * @param _beaconAddress - Address of the beacon contract.\n     */\n    function initialize(address _beaconAddress) external;\n\n    /**\n     * @notice Initializes a voucher with the given parameters.\n     *\n     * @param _sellerId - The ID of the seller.\n     * @param _collectionIndex - The index of the collection.\n     * @param _newOwner - The address of the new owner.\n     * @param _voucherInitValues - The voucher initialization values.\n     */\n    function initializeVoucher(\n        uint256 _sellerId,\n        uint256 _collectionIndex,\n        address _newOwner,\n        BosonTypes.VoucherInitValues calldata _voucherInitValues\n    ) external;\n}\n"
      },
      "contracts/interfaces/ITwinToken.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\n\npragma solidity 0.8.22;\n\nimport \"./IERC165.sol\";\n\n/**\n * @title ITwinToken\n *\n * @notice Provides the minimum interface a Twin token must expose to be supported by the Boson Protocol\n */\ninterface ITwinToken is IERC165 {\n    /**\n     * @notice Returns true if the `operator` is allowed to manage the assets of `owner`.\n     *\n     * @param _owner - the token owner address.\n     * @param _operator - the operator address.\n     * @return _isApproved - the approval was found.\n     */\n    function isApprovedForAll(address _owner, address _operator) external view returns (bool _isApproved);\n\n    /**\n     * @notice Returns the remaining number of tokens that `_operator` 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     * @param _owner - the owner address\n     * @param _operator - the operator address\n     * @return The remaining amount allowed\n     */\n    function allowance(address _owner, address _operator) external view returns (uint256);\n}\n"
      },
      "contracts/protocol/bases/BundleBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport \"./../../domain/BosonConstants.sol\";\nimport { IBosonBundleEvents } from \"../../interfaces/events/IBosonBundleEvents.sol\";\nimport { ProtocolBase } from \"./../bases/ProtocolBase.sol\";\nimport { ProtocolLib } from \"./../libs/ProtocolLib.sol\";\n\n/**\n * @title BundleBase\n *\n * @notice Provides methods for bundle creation that can be shared across facets\n */\ncontract BundleBase is ProtocolBase, IBosonBundleEvents {\n    /**\n     * @notice Creates a Bundle.\n     *\n     * Emits a BundleCreated event if successful.\n     *\n     * Reverts if:\n     * - The bundles region of protocol is paused\n     * - Seller does not exist\n     * - Either offerIds member or twinIds member is empty\n     * - Any of the offers belongs to different seller\n     * - Any of the offers does not exist\n     * - Offer exists in a different bundle\n     * - Any of the twins belongs to different seller\n     * - Any of the twins does not exist\n     * - Duplicate twins added in same bundle\n     * - Exchange already exists for the offer id in bundle\n     * - Offers' total quantity is greater than twin supply when token is nonfungible\n     * - Offers' total quantity multiplied by twin amount is greater than twin supply when token is fungible or multitoken\n     *\n     * @param _bundle - the fully populated struct with bundle id set to 0x0\n     */\n    function createBundleInternal(Bundle memory _bundle) internal {\n        // Cache protocol lookups and limits for reference\n        ProtocolLib.ProtocolLookups storage lookups = protocolLookups();\n\n        // get message sender\n        address sender = msgSender();\n\n        // get seller id, make sure it exists and store it to incoming struct\n        (bool exists, uint256 sellerId) = getSellerIdByAssistant(sender);\n        if (!exists) revert NotAssistant();\n\n        // validate that offer ids and twin ids are not empty\n        if (_bundle.offerIds.length == 0 || _bundle.twinIds.length == 0)\n            revert BundleRequiresAtLeastOneTwinAndOneOffer();\n\n        // Get the next bundle and increment the counter\n        uint256 bundleId = protocolCounters().nextBundleId++;\n        // Sum of offers quantity available\n        uint256 offersTotalQuantityAvailable;\n\n        for (uint256 i = 0; i < _bundle.offerIds.length; ) {\n            uint256 offerId = _bundle.offerIds[i];\n\n            // Calculate bundle offers total quantity available.\n            offersTotalQuantityAvailable = calculateOffersTotalQuantity(offersTotalQuantityAvailable, offerId);\n\n            (bool bundleByOfferExists, ) = fetchBundleIdByOffer(offerId);\n            if (bundleByOfferExists) revert BundleOfferMustBeUnique();\n\n            (bool exchangeIdsForOfferExists, ) = getExchangeIdsByOffer(offerId);\n            // make sure exchange does not already exist for this offer id.\n            if (exchangeIdsForOfferExists) revert ExchangeForOfferExists();\n\n            // Add to bundleIdByOffer mapping\n            lookups.bundleIdByOffer[offerId] = bundleId;\n\n            unchecked {\n                i++;\n            }\n        }\n\n        for (uint256 i = 0; i < _bundle.twinIds.length; ) {\n            uint256 twinId = _bundle.twinIds[i];\n\n            // A twin can't belong to multiple bundles\n            (bool bundleForTwinExist, ) = fetchBundleIdByTwin(twinId);\n            if (bundleForTwinExist) revert BundleTwinMustBeUnique();\n\n            bundleSupplyChecks(offersTotalQuantityAvailable, twinId);\n\n            // Push to bundleIdsByTwin mapping\n            lookups.bundleIdByTwin[_bundle.twinIds[i]] = bundleId;\n\n            unchecked {\n                i++;\n            }\n        }\n\n        // Get storage location for bundle\n        (, Bundle storage bundle) = fetchBundle(bundleId);\n\n        // Set bundle props individually since memory structs can't be copied to storage\n        bundle.id = _bundle.id = bundleId;\n        bundle.sellerId = _bundle.sellerId = sellerId;\n        bundle.offerIds = _bundle.offerIds;\n        bundle.twinIds = _bundle.twinIds;\n\n        // Notify watchers of state change\n        emit BundleCreated(bundleId, sellerId, _bundle, sender);\n    }\n\n    /**\n     * @notice Gets twin from protocol storage, makes sure it exist.\n     *\n     * Reverts if:\n     * - Twin does not exist\n     * - Caller is not the seller\n     *\n     *  @param _twinId - the id of the twin to check\n     */\n    function getValidTwin(uint256 _twinId) internal view returns (Twin storage twin) {\n        bool exists;\n        // Get twin\n        (exists, twin) = fetchTwin(_twinId);\n\n        // Twin must already exist\n        if (!exists) revert NoSuchTwin();\n\n        // Get seller id, we assume seller id exists if twin exists\n        (, uint256 sellerId) = getSellerIdByAssistant(msgSender());\n\n        // Caller's seller id must match twin seller id\n        if (sellerId != twin.sellerId) revert NotAssistant();\n    }\n\n    /**\n     * @notice Checks that twin has enough supply to cover all bundled offers.\n     *\n     * Reverts if:\n     * - Offers' total quantity is greater than twin supply when token is nonfungible\n     * - Offers' total quantity multiplied by twin amount is greater than twin supply when token is fungible or multitoken\n     *\n     * @param _offersTotalQuantity - sum of offers' total quantity available\n     * @param _twinId - twin id to compare\n     */\n    function bundleSupplyChecks(uint256 _offersTotalQuantity, uint256 _twinId) internal view {\n        // make sure twin exist and belong to the seller\n        Twin storage twin = getValidTwin(_twinId);\n\n        // twin is NonFungibleToken or bundle has an unlimited offer\n        if (twin.tokenType == TokenType.NonFungibleToken || _offersTotalQuantity == type(uint256).max) {\n            // the sum of all offers quantity should be less or equal twin supply\n            if (_offersTotalQuantity > twin.supplyAvailable) revert InsufficientTwinSupplyToCoverBundleOffers();\n        } else {\n            // twin is FungibleToken or MultiToken\n            // the sum of all offers quantity multiplied by twin amount should be less or equal twin supply\n            if (_offersTotalQuantity * twin.amount > twin.supplyAvailable) {\n                revert InsufficientTwinSupplyToCoverBundleOffers();\n            }\n        }\n    }\n\n    /**\n     *\n     * @notice Calculates bundled offers' total quantity available.\n     * @param _previousTotal - previous offers' total quantity or initial value\n     * @param _offerId - offer id to add to total quantity\n     * @return offersTotalQuantity - previous offers' total quantity plus the current offer quantityAvailable\n     */\n    function calculateOffersTotalQuantity(\n        uint256 _previousTotal,\n        uint256 _offerId\n    ) internal view returns (uint256 offersTotalQuantity) {\n        // make sure all offers exist and belong to the seller\n        Offer storage offer = getValidOfferWithSellerCheck(_offerId);\n\n        // Unchecked because we're handling overflow below\n        unchecked {\n            // Calculate the bundle offers total quantity available.\n            offersTotalQuantity = _previousTotal + offer.quantityAvailable;\n        }\n\n        // offersTotalQuantity should be max uint if overflow happens\n        if (offersTotalQuantity < offer.quantityAvailable) {\n            offersTotalQuantity = type(uint256).max;\n        }\n    }\n}\n"
      },
      "contracts/protocol/bases/DisputeBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport { IBosonDisputeEvents } from \"../../interfaces/events/IBosonDisputeEvents.sol\";\nimport { IBosonFundsLibEvents } from \"../../interfaces/events/IBosonFundsEvents.sol\";\nimport { ProtocolBase } from \"./../bases/ProtocolBase.sol\";\nimport { ProtocolLib } from \"./../libs/ProtocolLib.sol\";\nimport { FundsLib } from \"./../libs/FundsLib.sol\";\nimport \"../../domain/BosonConstants.sol\";\n\n/**\n *\n * @title DisputeBase\n * @notice Provides methods for dispute that can be shared across facets.\n */\ncontract DisputeBase is ProtocolBase, IBosonDisputeEvents, IBosonFundsLibEvents {\n    /**\n     * @notice Raises a dispute\n     *\n     * Reverts if:\n     * - Caller does not hold a voucher for the given exchange id\n     * - Exchange does not exist\n     * - Dispute period has elapsed already\n     *\n     * @param _exchange - the exchange\n     * @param _voucher - the associated voucher\n     * @param _sellerId - the seller id\n     */\n    function raiseDisputeInternal(Exchange storage _exchange, Voucher storage _voucher, uint256 _sellerId) internal {\n        // Fetch offer durations\n        OfferDurations storage offerDurations = fetchOfferDurations(_exchange.offerId);\n\n        // Make sure the dispute period has not elapsed\n        uint256 elapsed = block.timestamp - _voucher.redeemedDate;\n        if (elapsed >= offerDurations.disputePeriod) revert DisputePeriodHasElapsed();\n\n        // Make sure the caller is buyer associated with the exchange\n        checkBuyer(_exchange.buyerId);\n\n        // Set the exchange state to disputed\n        _exchange.state = ExchangeState.Disputed;\n\n        // Fetch the dispute and dispute dates\n        (, Dispute storage dispute, DisputeDates storage disputeDates) = fetchDispute(_exchange.id);\n\n        // Set the initial values\n        dispute.exchangeId = _exchange.id;\n        dispute.state = DisputeState.Resolving;\n\n        // Update the disputeDates\n        disputeDates.disputed = block.timestamp;\n        disputeDates.timeout = block.timestamp + offerDurations.resolutionPeriod;\n\n        // Notify watchers of state change\n        emit DisputeRaised(_exchange.id, _exchange.buyerId, _sellerId, msgSender());\n    }\n\n    /**\n     * @notice Puts the dispute into the Escalated state.\n     *\n     * Caller must send (or for ERC20, approve the transfer of) the\n     * buyer escalation deposit percentage of the offer price, which\n     * will be added to the pot for resolution.\n     *\n     * Emits a DisputeEscalated event if successful.\n     *\n     * Reverts if:\n     * - The disputes region of protocol is paused\n     * - Exchange does not exist\n     * - Exchange is not in a Disputed state\n     * - Caller is not the buyer\n     * - Dispute is already expired\n     * - Dispute is not in a Resolving state\n     * - Dispute resolver is not specified (absolute zero offer)\n     * - Offer price is in native token and caller does not send enough\n     * - Offer price is in some ERC20 token and caller also sends native currency\n     * - If contract at token address does not support ERC20 function transferFrom\n     * - If calling transferFrom on token fails for some reason (e.g. protocol is not approved to transfer)\n     * - Received ERC20 token amount differs from the expected value\n     *\n     * @param _exchangeId - the id of the associated exchange\n     */\n    function escalateDisputeInternal(uint256 _exchangeId) internal disputesNotPaused {\n        // Get the exchange, should be in disputed state\n        (Exchange storage exchange, ) = getValidExchange(_exchangeId, ExchangeState.Disputed);\n\n        // Make sure the caller is buyer associated with the exchange\n        uint256 buyerId = exchange.buyerId;\n        checkBuyer(buyerId);\n\n        // Fetch the dispute and dispute dates\n        (, Dispute storage dispute, DisputeDates storage disputeDates) = fetchDispute(_exchangeId);\n\n        // make sure the dispute not expired already\n        if (block.timestamp > disputeDates.timeout) revert DisputeHasExpired();\n\n        // Make sure the dispute is in the resolving state\n        if (dispute.state != DisputeState.Resolving) revert InvalidState();\n\n        // Fetch the dispute resolution terms from the storage\n        DisputeResolutionTerms storage disputeResolutionTerms = fetchDisputeResolutionTerms(exchange.offerId);\n\n        // absolute zero offers can be without DR. In that case we prevent escalation\n        if (disputeResolutionTerms.disputeResolverId == 0) revert EscalationNotAllowed();\n\n        // fetch offer to get info about dispute resolver id\n        (, Offer storage offer) = fetchOffer(exchange.offerId);\n\n        // make sure buyer sent enough funds to proceed\n        address exchangeToken = offer.exchangeToken;\n        uint256 buyerEscalationDeposit = disputeResolutionTerms.buyerEscalationDeposit;\n        FundsLib.validateIncomingPayment(exchangeToken, buyerEscalationDeposit);\n\n        // fetch the escalation period from the storage\n        uint256 escalationResponsePeriod = disputeResolutionTerms.escalationResponsePeriod;\n\n        // store the time of escalation\n        disputeDates.escalated = block.timestamp;\n        disputeDates.timeout = block.timestamp + escalationResponsePeriod;\n\n        // Set the dispute state\n        dispute.state = DisputeState.Escalated;\n\n        // Notify watchers of state change\n        address sender = msgSender();\n        emit FundsEncumbered(buyerId, exchangeToken, buyerEscalationDeposit, sender);\n        emit DisputeEscalated(_exchangeId, disputeResolutionTerms.disputeResolverId, sender);\n    }\n}\n"
      },
      "contracts/protocol/bases/GroupBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport \"./../../domain/BosonConstants.sol\";\nimport { IBosonGroupEvents } from \"../../interfaces/events/IBosonGroupEvents.sol\";\nimport { ProtocolBase } from \"./../bases/ProtocolBase.sol\";\nimport { ProtocolLib } from \"./../libs/ProtocolLib.sol\";\n\n/**\n * @title GroupBase\n *\n * @notice Provides methods for group creation that can be shared across facets\n */\ncontract GroupBase is ProtocolBase, IBosonGroupEvents {\n    /**\n     * @notice Creates a group.\n     *\n     * Emits a GroupCreated event if successful.\n     *\n     * Reverts if:\n     * - Caller is not an assistant\n     * - Any of offers belongs to different seller\n     * - Any of offers does not exist\n     * - Offer exists in a different group\n     * - Condition fields are invalid\n     *\n     * @param _group - the fully populated struct with group id set to 0x0\n     * @param _condition - the fully populated condition struct\n     */\n    function createGroupInternal(Group memory _group, Condition calldata _condition) internal {\n        // Cache protocol lookups for reference\n        ProtocolLib.ProtocolLookups storage lookups = protocolLookups();\n\n        // get message sender\n        address sender = msgSender();\n\n        // get seller id, make sure it exists and store it to incoming struct\n        (bool exists, uint256 sellerId) = getSellerIdByAssistant(sender);\n        if (!exists) revert NotAssistant();\n\n        // condition must be valid\n        if (!validateCondition(_condition)) revert InvalidConditionParameters();\n\n        // Get the next group and increment the counter\n        uint256 groupId = protocolCounters().nextGroupId++;\n\n        for (uint256 i = 0; i < _group.offerIds.length; ) {\n            // make sure offer exists and belongs to the seller\n            getValidOfferWithSellerCheck(_group.offerIds[i]);\n\n            // Offer should not belong to another group already\n            (bool exist, ) = getGroupIdByOffer(_group.offerIds[i]);\n            if (exist) revert OfferMustBeUnique();\n\n            // add to groupIdByOffer mapping\n            lookups.groupIdByOffer[_group.offerIds[i]] = groupId;\n\n            // Set index mapping. Should be index in offerIds + 1\n            lookups.offerIdIndexByGroup[groupId][_group.offerIds[i]] = i + 1;\n\n            unchecked {\n                i++;\n            }\n        }\n\n        // Get storage location for group\n        (, Group storage group) = fetchGroup(groupId);\n\n        // Set group props individually since memory structs can't be copied to storage\n        group.id = _group.id = groupId;\n        group.sellerId = _group.sellerId = sellerId;\n        group.offerIds = _group.offerIds;\n\n        // Store the condition\n        storeCondition(groupId, _condition);\n\n        // Notify watchers of state change\n        emit GroupCreated(groupId, sellerId, _group, _condition, sender);\n    }\n\n    /**\n     * @notice Store a condition struct associated with a given group id.\n     *\n     * @param _groupId - the group id\n     * @param _condition - the condition\n     */\n    function storeCondition(uint256 _groupId, Condition calldata _condition) internal {\n        // Get storage locations for condition\n        Condition storage condition = fetchCondition(_groupId);\n\n        // Set condition props individually since calldata structs can't be copied to storage\n        condition.method = _condition.method;\n        condition.tokenType = _condition.tokenType;\n        condition.tokenAddress = _condition.tokenAddress;\n        condition.gating = _condition.gating;\n        condition.minTokenId = _condition.minTokenId;\n        condition.threshold = _condition.threshold;\n        condition.maxCommits = _condition.maxCommits;\n        condition.maxTokenId = _condition.maxTokenId;\n    }\n\n    /**\n     * @notice Validates that condition parameters make sense.\n     *\n     * An invalid condition is one that fits any of the following criteria:\n     * - EvaluationMethod.None: any field different from zero\n     * - EvaluationMethod.Threshold:\n     *    - Token address, maxCommits, or threshold is zero.\n     *    - Min token id is greater than max token id.\n     *    - TokenType is FungibleToken or NonFungibleToken and\n     *       - Min token id is not 0\n     *       - Gating is not PerAddress\n     * - EvaluationMethod.SpecificToken:\n     *    - TokenType is FungibleToken or MultiToken\n     *    - Token address, maxCommits is zero.\n     *    - Threshold is not zero.\n     *    - Min token id is greater than max token id.\n     *\n     * @param _condition - fully populated condition struct\n     * @return valid - validity of condition\n     *\n     */\n    function validateCondition(Condition calldata _condition) internal pure returns (bool) {\n        if (_condition.method == EvaluationMethod.None) {\n            // bitwise OR of all fields should be zero\n            return\n                (uint8(_condition.tokenType) |\n                    uint160(_condition.tokenAddress) |\n                    uint8(_condition.gating) |\n                    _condition.minTokenId |\n                    _condition.threshold |\n                    _condition.maxCommits |\n                    _condition.maxTokenId) == 0;\n        }\n\n        // SpecificToken or Threshold\n        if (\n            _condition.maxCommits == 0 ||\n            _condition.tokenAddress == address(0) ||\n            _condition.minTokenId > _condition.maxTokenId\n        ) return false;\n\n        if (_condition.method == EvaluationMethod.Threshold) {\n            if (_condition.threshold == 0) return false;\n\n            // Fungible token and NonFungible token cannot have token id range or per token id gating\n            if (\n                _condition.tokenType != TokenType.MultiToken &&\n                (_condition.minTokenId != 0 || _condition.gating != GatingType.PerAddress)\n            ) return false;\n        } else {\n            // SpecificToken\n            // Only NonFungible is allowed\n            return (_condition.tokenType == TokenType.NonFungibleToken && _condition.threshold == 0);\n        }\n\n        return true;\n    }\n\n    /**\n     * @notice Adds offers to an existing group.\n     *\n     * Emits a GroupUpdated event if successful.\n     *\n     * Reverts if:\n     * - Caller is not the seller\n     * - Offer ids param is an empty list\n     * - Group does not exist\n     * - Any of offers belongs to different seller\n     * - Any of offers does not exist\n     * - Offer exists in a different group\n     * - Offer ids param contains duplicated offers\n     *\n     * @param _groupId  - the id of the group to be updated\n     * @param _offerIds - array of offer ids to be added to the group\n     */\n    function addOffersToGroupInternal(uint256 _groupId, uint256[] memory _offerIds) internal {\n        // Cache protocol lookups for reference\n        ProtocolLib.ProtocolLookups storage lookups = protocolLookups();\n\n        // check if group can be updated\n        (uint256 sellerId, Group storage group) = preUpdateChecks(_groupId, _offerIds);\n\n        for (uint256 i = 0; i < _offerIds.length; ) {\n            uint256 offerId = _offerIds[i];\n\n            getValidOfferWithSellerCheck(offerId);\n\n            // Offer should not belong to another group already\n            (bool exist, ) = getGroupIdByOffer(offerId);\n            if (exist) revert OfferMustBeUnique();\n\n            // add to groupIdByOffer mapping\n            lookups.groupIdByOffer[offerId] = _groupId;\n\n            // add to group struct\n            group.offerIds.push(offerId);\n\n            // Set index mapping. Should be index in offerIds + 1\n            lookups.offerIdIndexByGroup[_groupId][offerId] = group.offerIds.length;\n\n            unchecked {\n                i++;\n            }\n        }\n\n        // Get the condition\n        Condition storage condition = fetchCondition(_groupId);\n\n        // Notify watchers of state change\n        emit GroupUpdated(_groupId, sellerId, group, condition, msgSender());\n    }\n\n    /**\n     * @notice Checks that update can be done before performing an update\n     * and returns seller id and group storage pointer for further use.\n     *\n     * Reverts if:\n     * - Caller is not the seller\n     * - Offer ids param is an empty list\n     * - Group does not exist\n     *\n     * @param _groupId  - the id of the group to be updated\n     * @param _offerIds - array of offer ids to be added to or removed from the group\n     * @return sellerId  - the seller id\n     * @return group - the group details\n     */\n    function preUpdateChecks(\n        uint256 _groupId,\n        uint256[] memory _offerIds\n    ) internal view returns (uint256 sellerId, Group storage group) {\n        // make sure that at least something will be updated\n        if (_offerIds.length == 0) revert NothingUpdated();\n\n        // Get storage location for group\n        bool exists;\n        (exists, group) = fetchGroup(_groupId);\n\n        if (!exists) revert NoSuchGroup();\n\n        // Get seller id, we assume seller id exists if group exists\n        (, sellerId) = getSellerIdByAssistant(msgSender());\n\n        // Caller's seller id must match group seller id\n        if (sellerId != group.sellerId) revert NotAssistant();\n    }\n}\n"
      },
      "contracts/protocol/bases/OfferBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport { IBosonOfferEvents } from \"../../interfaces/events/IBosonOfferEvents.sol\";\nimport { ProtocolBase } from \"./../bases/ProtocolBase.sol\";\nimport { ProtocolLib } from \"./../libs/ProtocolLib.sol\";\nimport { IBosonVoucher } from \"../../interfaces/clients/IBosonVoucher.sol\";\nimport \"./../../domain/BosonConstants.sol\";\n\n/**\n * @title OfferBase\n *\n * @dev Provides methods for offer creation that can be shared across facets.\n */\ncontract OfferBase is ProtocolBase, IBosonOfferEvents {\n    /**\n     * @notice Creates offer. Can be reused among different facets.\n     *\n     * Emits an OfferCreated event if successful.\n     *\n     * Reverts if:\n     * - Caller is not an assistant\n     * - Valid from date is greater than valid until date\n     * - Valid until date is not in the future\n     * - Both voucher expiration date and voucher expiration period are defined\n     * - Neither of voucher expiration date and voucher expiration period are defined\n     * - Voucher redeemable period is fixed, but it ends before it starts\n     * - Voucher redeemable period is fixed, but it ends before offer expires\n     * - Dispute period is less than minimum dispute period\n     * - Resolution period is not between the minimum and the maximum resolution period\n     * - Voided is set to true\n     * - Available quantity is set to zero\n     * - Offer type is discovery and the price is not set to zero\n     * - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     * - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     * - Seller is not on dispute resolver's seller allow list\n     * - Dispute resolver does not accept fees in the exchange token\n     * - Buyer cancel penalty is greater than price\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - Royalty recipient is not on seller's allow list\n     * - Royalty percentage is less than the value decided by the admin\n     * - Total royalty percentage is more than max royalty percentage\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createOfferInternal(\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) internal {\n        // get seller id, make sure it exists and store it to incoming struct\n        (bool exists, uint256 sellerId) = getSellerIdByAssistant(msgSender());\n        if (!exists) revert NotAssistant();\n        _offer.sellerId = sellerId;\n        // Get the next offerId and increment the counter\n        uint256 offerId = protocolCounters().nextOfferId++;\n        _offer.id = offerId;\n\n        // Store the offer\n        storeOffer(_offer, _offerDates, _offerDurations, _disputeResolverId, _agentId, _feeLimit);\n    }\n\n    /**\n     * @notice Validates offer struct and store it to storage.\n     *\n     * @dev Rationale for the checks that are not obvious:\n     * 1. voucher expiration date is either\n     *   -  _offerDates.voucherRedeemableUntil  [fixed voucher expiration date]\n     *   - max([commitment time], _offerDates.voucherRedeemableFrom) + offerDurations.voucherValid [fixed voucher expiration duration]\n     * This is calculated during the commitToOffer. To avoid any ambiguity, we make sure that exactly one of _offerDates.voucherRedeemableUntil\n     * and offerDurations.voucherValid is defined.\n     * 2. Checks that include _offer.sellerDeposit, protocolFee, offer.buyerCancelPenalty and _offer.price\n     * Exchange can have one of multiple final states and different states have different seller and buyer payoffs. If offer parameters are\n     * not set appropriately, it's possible for some payoffs to become negative or unfair to some participant. By making the checks at the time\n     * of the offer creation we ensure that all payoffs are possible and fair.\n     *\n     *\n     * Reverts if:\n     * - Valid from date is greater than valid until date\n     * - Valid until date is not in the future\n     * - Both fixed voucher expiration date and voucher redemption duration are defined\n     * - Neither of fixed voucher expiration date and voucher redemption duration are defined\n     * - Voucher redeemable period is fixed, but it ends before it starts\n     * - Voucher redeemable period is fixed, but it ends before offer expires\n     * - Dispute period is less than minimum dispute period\n     * - Resolution period is not between the minimum and the maximum resolution period\n     * - Voided is set to true\n     * - Available quantity is set to zero\n     * - Offer type is discovery and the price is not set to zero\n     * - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     * - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     * - Seller is not on dispute resolver's seller allow list\n     * - Dispute resolver does not accept fees in the exchange token\n     * - Buyer cancel penalty is greater than price\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - Royalty recipient is not on seller's allow list\n     * - Royalty percentage is less than the value decided by the admin\n     * - Total royalty percentage is more than max royalty percentage\n     *\n     * @param _offer - the fully populated struct with offer id set to offer to be updated and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function storeOffer(\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) internal {\n        // validFrom date must be less than validUntil date\n        if (_offerDates.validFrom >= _offerDates.validUntil) revert InvalidOfferPeriod();\n\n        // validUntil date must be in the future\n        if (_offerDates.validUntil <= block.timestamp) revert InvalidOfferPeriod();\n\n        // exactly one of voucherRedeemableUntil and voucherValid must be zero\n        // if voucherRedeemableUntil exist, it must be greater than validUntil\n        if (_offerDates.voucherRedeemableUntil > 0) {\n            if (_offerDurations.voucherValid != 0) revert AmbiguousVoucherExpiry();\n            if (_offerDates.voucherRedeemableFrom >= _offerDates.voucherRedeemableUntil)\n                revert InvalidRedemptionPeriod();\n            if (_offerDates.voucherRedeemableUntil < _offerDates.validUntil) revert InvalidRedemptionPeriod();\n        } else {\n            if (_offerDurations.voucherValid == 0) revert AmbiguousVoucherExpiry();\n        }\n\n        // when creating offer, it cannot be set to voided\n        if (_offer.voided) revert OfferMustBeActive();\n\n        // quantity must be greater than zero\n        if (_offer.quantityAvailable == 0) revert InvalidQuantityAvailable();\n\n        // If offer is of the discovery type, price must be zero\n        if (_offer.priceType == PriceType.Discovery && _offer.price != 0) revert InvalidPriceDiscoveryPrice();\n\n        DisputeResolutionTerms memory disputeResolutionTerms;\n        OfferFees storage offerFees = fetchOfferFees(_offer.id);\n        {\n            // Cache protocol lookups for reference\n            ProtocolLib.ProtocolLookups storage lookups = protocolLookups();\n            ProtocolLib.ProtocolFees storage fees = protocolFees();\n\n            // Specified resolver must be registered and active, except for absolute zero offers with unspecified dispute resolver.\n            // If price and sellerDeposit are 0, seller is not obliged to choose dispute resolver, which is done by setting _disputeResolverId to 0.\n            // In this case, there is no need to check the validity of the dispute resolver. However, if one (or more) of {price, sellerDeposit, _disputeResolverId}\n            // is different from 0, it must be checked that dispute resolver exists, supports the exchange token and seller is allowed to choose them.\n            if (_offer.price != 0 || _offer.sellerDeposit != 0 || _disputeResolverId != 0) {\n                (\n                    bool exists,\n                    DisputeResolver storage disputeResolver,\n                    DisputeResolverFee[] storage disputeResolverFees\n                ) = fetchDisputeResolver(_disputeResolverId);\n                if (!exists || !disputeResolver.active) revert InvalidDisputeResolver();\n\n                // Operate in a block to avoid \"stack too deep\" error\n                {\n                    // check that seller is on the DR allow list\n                    if (lookups.allowedSellers[_disputeResolverId].length > 0) {\n                        // if length == 0, dispute resolver allows any seller\n                        // if length > 0, we check that it is on allow list\n                        if (lookups.allowedSellerIndex[_disputeResolverId][_offer.sellerId] == 0)\n                            revert SellerNotApproved();\n                    }\n\n                    // get the index of DisputeResolverFee and make sure DR supports the exchangeToken\n                    {\n                        uint256 feeIndex = lookups.disputeResolverFeeTokenIndex[_disputeResolverId][\n                            _offer.exchangeToken\n                        ];\n                        if (feeIndex == 0) revert DRUnsupportedFee();\n\n                        uint256 feeAmount = disputeResolverFees[feeIndex - 1].feeAmount;\n\n                        // store DR terms\n                        disputeResolutionTerms.disputeResolverId = _disputeResolverId;\n                        disputeResolutionTerms.escalationResponsePeriod = disputeResolver.escalationResponsePeriod;\n                        disputeResolutionTerms.feeAmount = feeAmount;\n                        disputeResolutionTerms.buyerEscalationDeposit =\n                            (feeAmount * fees.buyerEscalationDepositPercentage) /\n                            HUNDRED_PERCENT;\n                    }\n                    protocolEntities().disputeResolutionTerms[_offer.id] = disputeResolutionTerms;\n                }\n\n                // Collection must exist. Collections with index 0 exist by default.\n                if (_offer.collectionIndex > 0) {\n                    if (lookups.additionalCollections[_offer.sellerId].length < _offer.collectionIndex)\n                        revert NoSuchCollection();\n                }\n            }\n            // Cache protocol limits for reference\n            ProtocolLib.ProtocolLimits storage limits = protocolLimits();\n            // Operate in a block to avoid \"stack too deep\" error\n            {\n                // dispute period must be greater than or equal to the minimum dispute period\n                if (_offerDurations.disputePeriod < limits.minDisputePeriod) revert InvalidDisputePeriod();\n\n                // resolution period must be between the minimum and maximum resolution periods\n                if (\n                    _offerDurations.resolutionPeriod < limits.minResolutionPeriod ||\n                    _offerDurations.resolutionPeriod > limits.maxResolutionPeriod\n                ) {\n                    revert InvalidResolutionPeriod();\n                }\n            }\n\n            // Operate in a block to avoid \"stack too deep\" error\n            {\n                // Get the agent\n                (bool agentExists, Agent storage agent) = fetchAgent(_agentId);\n\n                // Make sure agent exists if _agentId is not zero.\n                if (_agentId != 0 && !agentExists) revert NoSuchAgent();\n\n                // Set variable to eliminate multiple SLOAD\n                uint256 offerPrice = _offer.price;\n\n                // condition for successful payout when exchange final state is canceled\n                if (_offer.buyerCancelPenalty > offerPrice) revert InvalidOfferPenalty();\n\n                // Calculate and set the protocol fee\n                uint256 protocolFee = getProtocolFee(_offer.exchangeToken, offerPrice);\n\n                // Calculate the agent fee amount\n                uint256 agentFeeAmount = (agent.feePercentage * offerPrice) / HUNDRED_PERCENT;\n\n                uint256 totalOfferFeeLimit = (limits.maxTotalOfferFeePercentage * offerPrice) / HUNDRED_PERCENT;\n\n                // Sum of agent fee amount and protocol fee amount should be <= offer fee limit and less that fee limit set by seller\n                uint256 totalFeeAmount = agentFeeAmount + protocolFee;\n                if (totalFeeAmount > totalOfferFeeLimit) revert AgentFeeAmountTooHigh();\n                if (totalFeeAmount > _feeLimit) revert TotalFeeExceedsLimit();\n\n                // Set offer fees props individually since calldata structs can't be copied to storage\n                offerFees.protocolFee = protocolFee;\n                offerFees.agentFee = agentFeeAmount;\n            }\n\n            // Store the agent id for the offer\n            lookups.agentIdByOffer[_offer.id] = _agentId;\n\n            // Make sure that supplied royalties ok\n            // Operate in a block to avoid \"stack too deep\" error\n            {\n                if (_offer.royaltyInfo.length != 1) revert InvalidRoyaltyInfo();\n                validateRoyaltyInfo(lookups, limits, _offer.sellerId, _offer.royaltyInfo[0]);\n            }\n        }\n        // Get storage location for offer\n\n        (, Offer storage offer) = fetchOffer(_offer.id);\n\n        // Set offer props individually since memory structs can't be copied to storage\n        offer.id = _offer.id;\n        offer.sellerId = _offer.sellerId;\n        offer.price = _offer.price;\n        offer.sellerDeposit = _offer.sellerDeposit;\n        offer.buyerCancelPenalty = _offer.buyerCancelPenalty;\n        offer.quantityAvailable = _offer.quantityAvailable;\n        offer.exchangeToken = _offer.exchangeToken;\n        offer.metadataUri = _offer.metadataUri;\n        offer.metadataHash = _offer.metadataHash;\n        offer.collectionIndex = _offer.collectionIndex;\n        offer.priceType = _offer.priceType;\n        offer.royaltyInfo.push(_offer.royaltyInfo[0]);\n\n        // Get storage location for offer dates\n        OfferDates storage offerDates = fetchOfferDates(_offer.id);\n\n        // Set offer dates props individually since calldata structs can't be copied to storage\n        offerDates.validFrom = _offerDates.validFrom;\n        offerDates.validUntil = _offerDates.validUntil;\n        offerDates.voucherRedeemableFrom = _offerDates.voucherRedeemableFrom;\n        offerDates.voucherRedeemableUntil = _offerDates.voucherRedeemableUntil;\n\n        // Get storage location for offer durations\n        OfferDurations storage offerDurations = fetchOfferDurations(_offer.id);\n\n        // Set offer durations props individually since calldata structs can't be copied to storage\n        offerDurations.disputePeriod = _offerDurations.disputePeriod;\n        offerDurations.voucherValid = _offerDurations.voucherValid;\n        offerDurations.resolutionPeriod = _offerDurations.resolutionPeriod;\n\n        // Notify watchers of state change\n        emit OfferCreated(\n            _offer.id,\n            _offer.sellerId,\n            _offer,\n            _offerDates,\n            _offerDurations,\n            disputeResolutionTerms,\n            offerFees,\n            _agentId,\n            msgSender()\n        );\n    }\n\n    /**\n     * @notice Reserves a range of vouchers to be associated with an offer\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - Offer does not exist\n     * - Offer already voided\n     * - Caller is not the seller\n     * - Range length is zero\n     * - Range length is greater than quantity available\n     * - Range length is greater than maximum allowed range length\n     * - Call to BosonVoucher.reserveRange() reverts\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @param _offerId - the id of the offer\n     * @param _length - the length of the range\n     * @param _to - the address to send the pre-minted vouchers to (contract address or contract owner)\n     */\n    function reserveRangeInternal(\n        uint256 _offerId,\n        uint256 _length,\n        address _to\n    ) internal offersNotPaused exchangesNotPaused {\n        // Get offer, make sure the caller is the assistant\n        Offer storage offer = getValidOfferWithSellerCheck(_offerId);\n\n        // Invalid ranges:\n        // - Empty range\n        // - Too large range, since it affects exchangeId\n        // - More than quantity available\n        if (_length == 0 || _length > type(uint64).max || offer.quantityAvailable < _length)\n            revert InvalidRangeLength();\n\n        // Get starting token id\n        ProtocolLib.ProtocolCounters storage pc = protocolCounters();\n        uint256 _startId = pc.nextExchangeId;\n\n        IBosonVoucher bosonVoucher = IBosonVoucher(\n            getCloneAddress(protocolLookups(), offer.sellerId, offer.collectionIndex)\n        );\n\n        address sender = msgSender();\n\n        // _to must be the contract address or the contract owner\n        if (_to != address(bosonVoucher) && _to != sender) revert InvalidToAddress();\n\n        // increase exchangeIds\n        pc.nextExchangeId = _startId + _length;\n\n        // decrease quantity available, unless offer is unlimited\n        if (offer.quantityAvailable != type(uint256).max) {\n            offer.quantityAvailable -= _length;\n        }\n\n        // Call reserveRange on voucher\n        bosonVoucher.reserveRange(_offerId, _startId, _length, _to);\n\n        // Notify external observers\n        emit RangeReserved(_offerId, offer.sellerId, _startId, _startId + _length - 1, _to, sender);\n    }\n\n    /**\n     * @notice Validates that royalty info struct contains valid data\n     *\n     * Reverts if:\n     * - Royalty recipient is not on seller's allow list\n     * - Royalty percentage is less than the value decided by the admin\n     * - Total royalty percentage is more than max royalty percentage\n     *\n     * @param _lookups -  the storage pointer to protocol lookups\n     * @param _limits - the storage pointer to protocol limits\n     * @param _sellerId - the id of the seller\n     * @param _royaltyInfo - the royalty info struct\n     */\n    function validateRoyaltyInfo(\n        ProtocolLib.ProtocolLookups storage _lookups,\n        ProtocolLib.ProtocolLimits storage _limits,\n        uint256 _sellerId,\n        RoyaltyInfo memory _royaltyInfo\n    ) internal view {\n        if (_royaltyInfo.recipients.length != _royaltyInfo.bps.length) revert ArrayLengthMismatch();\n\n        RoyaltyRecipientInfo[] storage royaltyRecipients = _lookups.royaltyRecipientsBySeller[_sellerId];\n\n        uint256 totalRoyalties;\n        for (uint256 i = 0; i < _royaltyInfo.recipients.length; ) {\n            uint256 royaltyRecipientId;\n\n            if (_royaltyInfo.recipients[i] == address(0)) {\n                royaltyRecipientId = 1;\n            } else {\n                royaltyRecipientId = _lookups.royaltyRecipientIndexBySellerAndRecipient[_sellerId][\n                    _royaltyInfo.recipients[i]\n                ];\n                if (royaltyRecipientId == 0) revert InvalidRoyaltyRecipient();\n            }\n\n            if (_royaltyInfo.bps[i] < royaltyRecipients[royaltyRecipientId - 1].minRoyaltyPercentage)\n                revert InvalidRoyaltyPercentage();\n\n            totalRoyalties += _royaltyInfo.bps[i];\n\n            unchecked {\n                i++;\n            }\n        }\n\n        if (totalRoyalties > _limits.maxRoyaltyPercentage) revert InvalidRoyaltyPercentage();\n    }\n}\n"
      },
      "contracts/protocol/bases/PausableBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport \"./../../domain/BosonConstants.sol\";\nimport { BosonErrors } from \"../../domain/BosonErrors.sol\";\nimport { ProtocolLib } from \"../libs/ProtocolLib.sol\";\nimport { BosonTypes } from \"../../domain/BosonTypes.sol\";\n\n/**\n * @title PausableBase\n *\n * @notice Provides modifiers for regional pausing\n */\ncontract PausableBase is BosonTypes {\n    /**\n     * @notice Modifier that checks the Offers region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier offersNotPaused() {\n        revertIfPaused(PausableRegion.Offers);\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks the Twins region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier twinsNotPaused() {\n        revertIfPaused(PausableRegion.Twins);\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks the Bundles region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier bundlesNotPaused() {\n        revertIfPaused(PausableRegion.Bundles);\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks the Groups region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier groupsNotPaused() {\n        revertIfPaused(PausableRegion.Groups);\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks the Sellers region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier sellersNotPaused() {\n        revertIfPaused(PausableRegion.Sellers);\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks the Buyers region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier buyersNotPaused() {\n        revertIfPaused(PausableRegion.Buyers);\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks the Agents region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier agentsNotPaused() {\n        revertIfPaused(PausableRegion.Agents);\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks the DisputeResolvers region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier disputeResolversNotPaused() {\n        revertIfPaused(PausableRegion.DisputeResolvers);\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks the Exchanges region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier exchangesNotPaused() {\n        revertIfPaused(PausableRegion.Exchanges);\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks the Disputes region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier disputesNotPaused() {\n        revertIfPaused(PausableRegion.Disputes);\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks the Funds region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier fundsNotPaused() {\n        revertIfPaused(PausableRegion.Funds);\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks the Orchestration region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier orchestrationNotPaused() {\n        revertIfPaused(PausableRegion.Orchestration);\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks the MetaTransaction region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier metaTransactionsNotPaused() {\n        revertIfPaused(PausableRegion.MetaTransaction);\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks the PriceDiscovery region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier priceDiscoveryNotPaused() {\n        revertIfPaused(PausableRegion.PriceDiscovery);\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks the SequentialCommit region is not paused\n     *\n     * Reverts if region is paused\n     *\n     * See: {BosonTypes.PausableRegion}\n     */\n    modifier sequentialCommitNotPaused() {\n        revertIfPaused(PausableRegion.SequentialCommit);\n        _;\n    }\n\n    /**\n     * @notice Checks if a region of the protocol is paused.\n     *\n     * Reverts if region is paused\n     *\n     * @param _region the region to check pause status for\n     */\n    function revertIfPaused(PausableRegion _region) internal view {\n        // Region enum value must be used as the exponent in a power of 2\n        uint256 powerOfTwo = 1 << uint256(_region);\n        if ((ProtocolLib.protocolStatus().pauseScenario & powerOfTwo) == powerOfTwo)\n            revert BosonErrors.RegionPaused(_region);\n    }\n}\n"
      },
      "contracts/protocol/bases/ProtocolBase.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.22;\n\nimport \"../../domain/BosonConstants.sol\";\nimport { BosonErrors } from \"../../domain/BosonErrors.sol\";\nimport { ProtocolLib } from \"../libs/ProtocolLib.sol\";\nimport { DiamondLib } from \"../../diamond/DiamondLib.sol\";\nimport { EIP712Lib } from \"../libs/EIP712Lib.sol\";\nimport { BosonTypes } from \"../../domain/BosonTypes.sol\";\nimport { PausableBase } from \"./PausableBase.sol\";\nimport { ReentrancyGuardBase } from \"./ReentrancyGuardBase.sol\";\n\n/**\n * @title ProtocolBase\n *\n * @notice Provides domain and common modifiers to Protocol facets\n */\nabstract contract ProtocolBase is PausableBase, ReentrancyGuardBase, BosonErrors {\n    /**\n     * @notice Modifier to protect initializer function from being invoked twice.\n     */\n    modifier onlyUninitialized(bytes4 interfaceId) {\n        ProtocolLib.ProtocolStatus storage ps = protocolStatus();\n        if (ps.initializedInterfaces[interfaceId]) revert AlreadyInitialized();\n        ps.initializedInterfaces[interfaceId] = true;\n        _;\n    }\n\n    /**\n     * @notice Modifier that checks that the caller has a specific role.\n     *\n     * Reverts if caller doesn't have role.\n     *\n     * See: {AccessController.hasRole}\n     *\n     * @param _role - the role to check\n     */\n    modifier onlyRole(bytes32 _role) {\n        DiamondLib.DiamondStorage storage ds = DiamondLib.diamondStorage();\n        if (!ds.accessController.hasRole(_role, msgSender())) revert AccessDenied();\n        _;\n    }\n\n    /**\n     * @notice Get the Protocol Addresses slot\n     *\n     * @return pa - the Protocol Addresses slot\n     */\n    function protocolAddresses() internal pure returns (ProtocolLib.ProtocolAddresses storage pa) {\n        pa = ProtocolLib.protocolAddresses();\n    }\n\n    /**\n     * @notice Get the Protocol Limits slot\n     *\n     * @return pl - the Protocol Limits slot\n     */\n    function protocolLimits() internal pure returns (ProtocolLib.ProtocolLimits storage pl) {\n        pl = ProtocolLib.protocolLimits();\n    }\n\n    /**\n     * @notice Get the Protocol Entities slot\n     *\n     * @return pe - the Protocol Entities slot\n     */\n    function protocolEntities() internal pure returns (ProtocolLib.ProtocolEntities storage pe) {\n        pe = ProtocolLib.protocolEntities();\n    }\n\n    /**\n     * @notice Get the Protocol Lookups slot\n     *\n     * @return pl - the Protocol Lookups slot\n     */\n    function protocolLookups() internal pure returns (ProtocolLib.ProtocolLookups storage pl) {\n        pl = ProtocolLib.protocolLookups();\n    }\n\n    /**\n     * @notice Get the Protocol Fees slot\n     *\n     * @return pf - the Protocol Fees slot\n     */\n    function protocolFees() internal pure returns (ProtocolLib.ProtocolFees storage pf) {\n        pf = ProtocolLib.protocolFees();\n    }\n\n    /**\n     * @notice Get the Protocol Counters slot\n     *\n     * @return pc the Protocol Counters slot\n     */\n    function protocolCounters() internal pure returns (ProtocolLib.ProtocolCounters storage pc) {\n        pc = ProtocolLib.protocolCounters();\n    }\n\n    /**\n     * @notice Get the Protocol meta-transactions storage slot\n     *\n     * @return pmti the Protocol meta-transactions storage slot\n     */\n    function protocolMetaTxInfo() internal pure returns (ProtocolLib.ProtocolMetaTxInfo storage pmti) {\n        pmti = ProtocolLib.protocolMetaTxInfo();\n    }\n\n    /**\n     * @notice Get the Protocol Status slot\n     *\n     * @return ps the Protocol Status slot\n     */\n    function protocolStatus() internal pure returns (ProtocolLib.ProtocolStatus storage ps) {\n        ps = ProtocolLib.protocolStatus();\n    }\n\n    /**\n     * @notice Gets a seller id from storage by assistant address\n     *\n     * @param _assistant - the assistant address of the seller\n     * @return exists - whether the seller id exists\n     * @return sellerId  - the seller id\n     */\n    function getSellerIdByAssistant(address _assistant) internal view returns (bool exists, uint256 sellerId) {\n        // Get the seller id\n        sellerId = protocolLookups().sellerIdByAssistant[_assistant];\n\n        // Determine existence\n        exists = (sellerId > 0);\n    }\n\n    /**\n     * @notice Gets a seller id from storage by admin address\n     *\n     * @param _admin - the admin address of the seller\n     * @return exists - whether the seller id exists\n     * @return sellerId  - the seller id\n     */\n    function getSellerIdByAdmin(address _admin) internal view returns (bool exists, uint256 sellerId) {\n        // Get the seller id\n        sellerId = protocolLookups().sellerIdByAdmin[_admin];\n\n        // Determine existence\n        exists = (sellerId > 0);\n    }\n\n    /**\n     * @notice Gets a seller id from storage by auth token.  A seller will have either an admin address or an auth token\n     *\n     * @param _authToken - the potential _authToken of the seller.\n     * @return exists - whether the seller id exists\n     * @return sellerId  - the seller id\n     */\n    function getSellerIdByAuthToken(\n        AuthToken calldata _authToken\n    ) internal view returns (bool exists, uint256 sellerId) {\n        // Get the seller id\n        sellerId = protocolLookups().sellerIdByAuthToken[_authToken.tokenType][_authToken.tokenId];\n\n        // Determine existence\n        exists = (sellerId > 0);\n    }\n\n    /**\n     * @notice Gets a buyer id from storage by wallet address\n     *\n     * @param _wallet - the wallet address of the buyer\n     * @return exists - whether the buyer id exists\n     * @return buyerId  - the buyer id\n     */\n    function getBuyerIdByWallet(address _wallet) internal view returns (bool exists, uint256 buyerId) {\n        // Get the buyer id\n        buyerId = protocolLookups().buyerIdByWallet[_wallet];\n\n        // Determine existence\n        exists = (buyerId > 0);\n    }\n\n    /**\n     * @notice Gets a agent id from storage by wallet address\n     *\n     * @param _wallet - the wallet address of the buyer\n     * @return exists - whether the buyer id exists\n     * @return agentId  - the buyer id\n     */\n    function getAgentIdByWallet(address _wallet) internal view returns (bool exists, uint256 agentId) {\n        // Get the buyer id\n        agentId = protocolLookups().agentIdByWallet[_wallet];\n\n        // Determine existence\n        exists = (agentId > 0);\n    }\n\n    /**\n     * @notice Gets a dispute resolver id from storage by assistant address\n     *\n     * @param _assistant - the assistant address of the dispute resolver\n     * @return exists - whether the dispute resolver id exists\n     * @return disputeResolverId  - the dispute resolver  id\n     */\n    function getDisputeResolverIdByAssistant(\n        address _assistant\n    ) internal view returns (bool exists, uint256 disputeResolverId) {\n        // Get the dispute resolver id\n        disputeResolverId = protocolLookups().disputeResolverIdByAssistant[_assistant];\n\n        // Determine existence\n        exists = (disputeResolverId > 0);\n    }\n\n    /**\n     * @notice Gets a dispute resolver id from storage by admin address\n     *\n     * @param _admin - the admin address of the dispute resolver\n     * @return exists - whether the dispute resolver id exists\n     * @return disputeResolverId  - the dispute resolver id\n     */\n    function getDisputeResolverIdByAdmin(\n        address _admin\n    ) internal view returns (bool exists, uint256 disputeResolverId) {\n        // Get the dispute resolver id\n        disputeResolverId = protocolLookups().disputeResolverIdByAdmin[_admin];\n\n        // Determine existence\n        exists = (disputeResolverId > 0);\n    }\n\n    /**\n     * @notice Gets a group id from storage by offer id\n     *\n     * @param _offerId - the offer id\n     * @return exists - whether the group id exists\n     * @return groupId  - the group id.\n     */\n    function getGroupIdByOffer(uint256 _offerId) internal view returns (bool exists, uint256 groupId) {\n        // Get the group id\n        groupId = protocolLookups().groupIdByOffer[_offerId];\n\n        // Determine existence\n        exists = (groupId > 0);\n    }\n\n    /**\n     * @notice Fetches a given seller from storage by id\n     *\n     * @param _sellerId - the id of the seller\n     * @return exists - whether the seller exists\n     * @return seller - the seller details. See {BosonTypes.Seller}\n     * @return authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the user can use to do admin functions\n     */\n    function fetchSeller(\n        uint256 _sellerId\n    ) internal view returns (bool exists, Seller storage seller, AuthToken storage authToken) {\n        // Cache protocol entities for reference\n        ProtocolLib.ProtocolEntities storage entities = protocolEntities();\n\n        // Get the seller's slot\n        seller = entities.sellers[_sellerId];\n\n        //Get the seller's auth token's slot\n        authToken = entities.authTokens[_sellerId];\n\n        // Determine existence\n        exists = (_sellerId > 0 && seller.id == _sellerId);\n    }\n\n    /**\n     * @notice Fetches a given buyer from storage by id\n     *\n     * @param _buyerId - the id of the buyer\n     * @return exists - whether the buyer exists\n     * @return buyer - the buyer details. See {BosonTypes.Buyer}\n     */\n    function fetchBuyer(uint256 _buyerId) internal view returns (bool exists, BosonTypes.Buyer storage buyer) {\n        // Get the buyer's slot\n        buyer = protocolEntities().buyers[_buyerId];\n\n        // Determine existence\n        exists = (_buyerId > 0 && buyer.id == _buyerId);\n    }\n\n    /**\n     * @notice Fetches a given dispute resolver from storage by id\n     *\n     * @param _disputeResolverId - the id of the dispute resolver\n     * @return exists - whether the dispute resolver exists\n     * @return disputeResolver - the dispute resolver details. See {BosonTypes.DisputeResolver}\n     * @return disputeResolverFees - list of fees dispute resolver charges per token type. Zero address is native currency. See {BosonTypes.DisputeResolverFee}\n     */\n    function fetchDisputeResolver(\n        uint256 _disputeResolverId\n    )\n        internal\n        view\n        returns (\n            bool exists,\n            BosonTypes.DisputeResolver storage disputeResolver,\n            BosonTypes.DisputeResolverFee[] storage disputeResolverFees\n        )\n    {\n        // Cache protocol entities for reference\n        ProtocolLib.ProtocolEntities storage entities = protocolEntities();\n\n        // Get the dispute resolver's slot\n        disputeResolver = entities.disputeResolvers[_disputeResolverId];\n\n        //Get dispute resolver's fee list slot\n        disputeResolverFees = entities.disputeResolverFees[_disputeResolverId];\n\n        // Determine existence\n        exists = (_disputeResolverId > 0 && disputeResolver.id == _disputeResolverId);\n    }\n\n    /**\n     * @notice Fetches a given agent from storage by id\n     *\n     * @param _agentId - the id of the agent\n     * @return exists - whether the agent exists\n     * @return agent - the agent details. See {BosonTypes.Agent}\n     */\n    function fetchAgent(uint256 _agentId) internal view returns (bool exists, BosonTypes.Agent storage agent) {\n        // Get the agent's slot\n        agent = protocolEntities().agents[_agentId];\n\n        // Determine existence\n        exists = (_agentId > 0 && agent.id == _agentId);\n    }\n\n    /**\n     * @notice Fetches a given offer from storage by id\n     *\n     * @param _offerId - the id of the offer\n     * @return exists - whether the offer exists\n     * @return offer - the offer details. See {BosonTypes.Offer}\n     */\n    function fetchOffer(uint256 _offerId) internal view returns (bool exists, Offer storage offer) {\n        // Get the offer's slot\n        offer = protocolEntities().offers[_offerId];\n\n        // Determine existence\n        exists = (_offerId > 0 && offer.id == _offerId);\n    }\n\n    /**\n     * @notice Fetches the offer dates from storage by offer id\n     *\n     * @param _offerId - the id of the offer\n     * @return offerDates - the offer dates details. See {BosonTypes.OfferDates}\n     */\n    function fetchOfferDates(uint256 _offerId) internal view returns (BosonTypes.OfferDates storage offerDates) {\n        // Get the offerDates slot\n        offerDates = protocolEntities().offerDates[_offerId];\n    }\n\n    /**\n     * @notice Fetches the offer durations from storage by offer id\n     *\n     * @param _offerId - the id of the offer\n     * @return offerDurations - the offer durations details. See {BosonTypes.OfferDurations}\n     */\n    function fetchOfferDurations(\n        uint256 _offerId\n    ) internal view returns (BosonTypes.OfferDurations storage offerDurations) {\n        // Get the offer's slot\n        offerDurations = protocolEntities().offerDurations[_offerId];\n    }\n\n    /**\n     * @notice Fetches the dispute resolution terms from storage by offer id\n     *\n     * @param _offerId - the id of the offer\n     * @return disputeResolutionTerms - the details about the dispute resolution terms. See {BosonTypes.DisputeResolutionTerms}\n     */\n    function fetchDisputeResolutionTerms(\n        uint256 _offerId\n    ) internal view returns (BosonTypes.DisputeResolutionTerms storage disputeResolutionTerms) {\n        // Get the disputeResolutionTerms slot\n        disputeResolutionTerms = protocolEntities().disputeResolutionTerms[_offerId];\n    }\n\n    /**\n     * @notice Fetches a given group from storage by id\n     *\n     * @param _groupId - the id of the group\n     * @return exists - whether the group exists\n     * @return group - the group details. See {BosonTypes.Group}\n     */\n    function fetchGroup(uint256 _groupId) internal view returns (bool exists, Group storage group) {\n        // Get the group's slot\n        group = protocolEntities().groups[_groupId];\n\n        // Determine existence\n        exists = (_groupId > 0 && group.id == _groupId);\n    }\n\n    /**\n     * @notice Fetches the Condition from storage by group id\n     *\n     * @param _groupId - the id of the group\n     * @return condition - the condition details. See {BosonTypes.Condition}\n     */\n    function fetchCondition(uint256 _groupId) internal view returns (BosonTypes.Condition storage condition) {\n        // Get the offerDates slot\n        condition = protocolEntities().conditions[_groupId];\n    }\n\n    /**\n     * @notice Fetches a given exchange from storage by id\n     *\n     * @param _exchangeId - the id of the exchange\n     * @return exists - whether the exchange exists\n     * @return exchange - the exchange details. See {BosonTypes.Exchange}\n     */\n    function fetchExchange(uint256 _exchangeId) internal view returns (bool exists, Exchange storage exchange) {\n        // Get the exchange's slot\n        exchange = protocolEntities().exchanges[_exchangeId];\n\n        // Determine existence\n        exists = (_exchangeId > 0 && exchange.id == _exchangeId);\n    }\n\n    /**\n     * @notice Fetches a given voucher from storage by exchange id\n     *\n     * @param _exchangeId - the id of the exchange associated with the voucher\n     * @return voucher - the voucher details. See {BosonTypes.Voucher}\n     */\n    function fetchVoucher(uint256 _exchangeId) internal view returns (Voucher storage voucher) {\n        // Get the voucher\n        voucher = protocolEntities().vouchers[_exchangeId];\n    }\n\n    /**\n     * @notice Fetches a given dispute from storage by exchange id\n     *\n     * @param _exchangeId - the id of the exchange associated with the dispute\n     * @return exists - whether the dispute exists\n     * @return dispute - the dispute details. See {BosonTypes.Dispute}\n     */\n    function fetchDispute(\n        uint256 _exchangeId\n    ) internal view returns (bool exists, Dispute storage dispute, DisputeDates storage disputeDates) {\n        // Cache protocol entities for reference\n        ProtocolLib.ProtocolEntities storage entities = protocolEntities();\n\n        // Get the dispute's slot\n        dispute = entities.disputes[_exchangeId];\n\n        // Get the disputeDates slot\n        disputeDates = entities.disputeDates[_exchangeId];\n\n        // Determine existence\n        exists = (_exchangeId > 0 && dispute.exchangeId == _exchangeId);\n    }\n\n    /**\n     * @notice Fetches a given twin from storage by id\n     *\n     * @param _twinId - the id of the twin\n     * @return exists - whether the twin exists\n     * @return twin - the twin details. See {BosonTypes.Twin}\n     */\n    function fetchTwin(uint256 _twinId) internal view returns (bool exists, Twin storage twin) {\n        // Get the twin's slot\n        twin = protocolEntities().twins[_twinId];\n\n        // Determine existence\n        exists = (_twinId > 0 && twin.id == _twinId);\n    }\n\n    /**\n     * @notice Fetches a given bundle from storage by id\n     *\n     * @param _bundleId - the id of the bundle\n     * @return exists - whether the bundle exists\n     * @return bundle - the bundle details. See {BosonTypes.Bundle}\n     */\n    function fetchBundle(uint256 _bundleId) internal view returns (bool exists, Bundle storage bundle) {\n        // Get the bundle's slot\n        bundle = protocolEntities().bundles[_bundleId];\n\n        // Determine existence\n        exists = (_bundleId > 0 && bundle.id == _bundleId);\n    }\n\n    /**\n     * @notice Gets offer from protocol storage, makes sure it exist and not voided\n     *\n     * Reverts if:\n     * - Offer does not exist\n     * - Offer already voided\n     *\n     *  @param _offerId - the id of the offer to check\n     */\n    function getValidOffer(uint256 _offerId) internal view returns (Offer storage offer) {\n        bool exists;\n\n        // Get offer\n        (exists, offer) = fetchOffer(_offerId);\n\n        // Offer must already exist\n        if (!exists) revert NoSuchOffer();\n\n        // Offer must not already be voided\n        if (offer.voided) revert OfferHasBeenVoided();\n    }\n\n    /**\n     * @notice Gets offer and seller from protocol storage\n     *\n     * Reverts if:\n     * - Offer does not exist\n     * - Offer already voided\n     * - Seller assistant is not the caller\n     *\n     *  @param _offerId - the id of the offer to check\n     *  @return offer - the offer details. See {BosonTypes.Offer}\n     */\n    function getValidOfferWithSellerCheck(uint256 _offerId) internal view returns (Offer storage offer) {\n        // Get offer\n        offer = getValidOffer(_offerId);\n\n        // Get seller, we assume seller exists if offer exists\n        (, Seller storage seller, ) = fetchSeller(offer.sellerId);\n\n        // Caller must be seller's assistant address\n        if (seller.assistant != msgSender()) revert NotAssistant();\n    }\n\n    /**\n     * @notice Gets the bundle id for a given offer id.\n     *\n     * @param _offerId - the offer id.\n     * @return exists - whether the bundle id exists\n     * @return bundleId  - the bundle id.\n     */\n    function fetchBundleIdByOffer(uint256 _offerId) internal view returns (bool exists, uint256 bundleId) {\n        // Get the bundle id\n        bundleId = protocolLookups().bundleIdByOffer[_offerId];\n\n        // Determine existence\n        exists = (bundleId > 0);\n    }\n\n    /**\n     * @notice Gets the bundle id for a given twin id.\n     *\n     * @param _twinId - the twin id.\n     * @return exists - whether the bundle id exist\n     * @return bundleId  - the bundle id.\n     */\n    function fetchBundleIdByTwin(uint256 _twinId) internal view returns (bool exists, uint256 bundleId) {\n        // Get the bundle id\n        bundleId = protocolLookups().bundleIdByTwin[_twinId];\n\n        // Determine existence\n        exists = (bundleId > 0);\n    }\n\n    /**\n     * @notice Gets the exchange ids for a given offer id.\n     *\n     * @param _offerId - the offer id.\n     * @return exists - whether the exchange Ids exist\n     * @return exchangeIds  - the exchange Ids.\n     */\n    function getExchangeIdsByOffer(\n        uint256 _offerId\n    ) internal view returns (bool exists, uint256[] storage exchangeIds) {\n        // Get the exchange Ids\n        exchangeIds = protocolLookups().exchangeIdsByOffer[_offerId];\n\n        // Determine existence\n        exists = (exchangeIds.length > 0);\n    }\n\n    /**\n     * @notice Make sure the caller is buyer associated with the exchange\n     *\n     * Reverts if\n     * - caller is not the buyer associated with exchange\n     *\n     * @param _currentBuyer - id of current buyer associated with the exchange\n     */\n    function checkBuyer(uint256 _currentBuyer) internal view {\n        // Get the caller's buyer account id\n        (, uint256 buyerId) = getBuyerIdByWallet(msgSender());\n\n        // Must be the buyer associated with the exchange (which is always voucher holder)\n        if (buyerId != _currentBuyer) revert NotVoucherHolder();\n    }\n\n    /**\n     * @notice Get a valid exchange and its associated voucher\n     *\n     * Reverts if\n     * - Exchange does not exist\n     * - Exchange is not in the expected state\n     *\n     * @param _exchangeId - the id of the exchange to complete\n     * @param _expectedState - the state the exchange should be in\n     * @return exchange - the exchange\n     * @return voucher - the voucher\n     */\n    function getValidExchange(\n        uint256 _exchangeId,\n        ExchangeState _expectedState\n    ) internal view returns (Exchange storage exchange, Voucher storage voucher) {\n        // Get the exchange\n        bool exchangeExists;\n        (exchangeExists, exchange) = fetchExchange(_exchangeId);\n\n        // Make sure the exchange exists\n        if (!exchangeExists) revert NoSuchExchange();\n\n        // Make sure the exchange is in expected state\n        if (exchange.state != _expectedState) revert InvalidState();\n\n        // Get the voucher\n        voucher = fetchVoucher(_exchangeId);\n    }\n\n    /**\n     * @notice Returns the current sender address.\n     */\n    function msgSender() internal view returns (address) {\n        return EIP712Lib.msgSender();\n    }\n\n    /**\n     * @notice Gets the agent id for a given offer id.\n     *\n     * @param _offerId - the offer id.\n     * @return exists - whether the exchange id exist\n     * @return agentId - the agent id.\n     */\n    function fetchAgentIdByOffer(uint256 _offerId) internal view returns (bool exists, uint256 agentId) {\n        // Get the agent id\n        agentId = protocolLookups().agentIdByOffer[_offerId];\n\n        // Determine existence\n        exists = (agentId > 0);\n    }\n\n    /**\n     * @notice Fetches the offer fees from storage by offer id\n     *\n     * @param _offerId - the id of the offer\n     * @return offerFees - the offer fees details. See {BosonTypes.OfferFees}\n     */\n    function fetchOfferFees(uint256 _offerId) internal view returns (BosonTypes.OfferFees storage offerFees) {\n        // Get the offerFees slot\n        offerFees = protocolEntities().offerFees[_offerId];\n    }\n\n    /**\n     * @notice Fetches a list of twin receipts from storage by exchange id\n     *\n     * @param _exchangeId - the id of the exchange\n     * @return exists - whether one or more twin receipt exists\n     * @return twinReceipts - the list of twin receipts. See {BosonTypes.TwinReceipt}\n     */\n    function fetchTwinReceipts(\n        uint256 _exchangeId\n    ) internal view returns (bool exists, TwinReceipt[] storage twinReceipts) {\n        // Get the twin receipts slot\n        twinReceipts = protocolLookups().twinReceiptsByExchange[_exchangeId];\n\n        // Determine existence\n        exists = (_exchangeId > 0 && twinReceipts.length > 0);\n    }\n\n    /**\n     * @notice Fetches a condition from storage by exchange id\n     *\n     * @param _exchangeId - the id of the exchange\n     * @return exists - whether one condition exists for the exchange\n     * @return condition - the condition. See {BosonTypes.Condition}\n     */\n    function fetchConditionByExchange(\n        uint256 _exchangeId\n    ) internal view returns (bool exists, Condition storage condition) {\n        // Get the condition slot\n        condition = protocolLookups().exchangeCondition[_exchangeId];\n\n        // Determine existence\n        exists = (_exchangeId > 0 && condition.method != EvaluationMethod.None);\n    }\n\n    /**\n     * @notice calculate the protocol fee for a given exchange\n     *\n     * @param _exchangeToken - the token used for the exchange\n     * @param _price - the price of the exchange\n     * @return protocolFee - the protocol fee\n     */\n    function getProtocolFee(address _exchangeToken, uint256 _price) internal view returns (uint256 protocolFee) {\n        // Calculate and set the protocol fee\n        return\n            _exchangeToken == protocolAddresses().token\n                ? protocolFees().flatBoson\n                : (protocolFees().percentage * _price) / HUNDRED_PERCENT;\n    }\n\n    /**\n     * @notice Fetches a clone address from storage by seller id and collection index\n     * If the collection index is 0, the clone address is the seller's main collection,\n     * otherwise it is the clone address of the additional collection at the given index.\n     *\n     * @param _lookups - storage slot for protocol lookups\n     * @param _sellerId - the id of the seller\n     * @param _collectionIndex - the index of the collection\n     * @return cloneAddress - the clone address\n     */\n    function getCloneAddress(\n        ProtocolLib.ProtocolLookups storage _lookups,\n        uint256 _sellerId,\n        uint256 _collectionIndex\n    ) internal view returns (address cloneAddress) {\n        return\n            _collectionIndex == 0\n                ? _lookups.cloneAddress[_sellerId]\n                : _lookups.additionalCollections[_sellerId][_collectionIndex - 1].collectionAddress;\n    }\n\n    /**\n     * @notice Internal helper to get royalty information and seller for a chosen exchange.\n     *\n     * Reverts if exchange does not exist.\n     *\n     * @param _queryId - offer id or exchange id\n     * @param _isExchangeId - indicates if the query represents the exchange id\n     * @return royaltyInfo - list of royalty recipients and corresponding bps\n     * @return royaltyInfoIndex - index of the royalty info\n     * @return treasury - the seller's treasury address\n     */\n    function fetchRoyalties(\n        uint256 _queryId,\n        bool _isExchangeId\n    ) internal view returns (RoyaltyInfo storage royaltyInfo, uint256 royaltyInfoIndex, address treasury) {\n        RoyaltyInfo[] storage royaltyInfoAll;\n        if (_isExchangeId) {\n            (bool exists, Exchange storage exchange) = fetchExchange(_queryId);\n            if (!exists) revert NoSuchExchange();\n            _queryId = exchange.offerId;\n        }\n\n        // not using fetchOffer to reduce gas costs (limitation of royalty registry)\n        ProtocolLib.ProtocolEntities storage pe = protocolEntities();\n        Offer storage offer = pe.offers[_queryId];\n        treasury = pe.sellers[offer.sellerId].treasury;\n        royaltyInfoAll = pe.offers[_queryId].royaltyInfo;\n\n        uint256 royaltyInfoLength = royaltyInfoAll.length;\n        if (royaltyInfoLength == 0) revert NoSuchOffer();\n        royaltyInfoIndex = royaltyInfoLength - 1;\n        // get the last royalty info\n        return (royaltyInfoAll[royaltyInfoIndex], royaltyInfoIndex, treasury);\n    }\n\n    /**\n     * @notice Helper function that calculates the total royalty percentage for a given exchange\n     *\n     * @param _bps - storage slot for array of royalty percentages\n     * @return totalBps - the total royalty percentage\n     */\n    function getTotalRoyaltyPercentage(uint256[] storage _bps) internal view returns (uint256 totalBps) {\n        uint256 bpsLength = _bps.length;\n        for (uint256 i = 0; i < bpsLength; ) {\n            totalBps += _bps[i];\n\n            unchecked {\n                i++;\n            }\n        }\n    }\n}\n"
      },
      "contracts/protocol/bases/ReentrancyGuardBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\nimport \"../../domain/BosonConstants.sol\";\nimport { BosonErrors } from \"../../domain/BosonErrors.sol\";\nimport { ProtocolLib } from \"../libs/ProtocolLib.sol\";\n\npragma solidity 0.8.22;\n\n/**\n * @notice Contract module that helps prevent reentrant calls to a function.\n *\n * The majority of code, comments and general idea is taken from OpenZeppelin implementation.\n * Code was adjusted to work with the storage layout used in the protocol.\n * Reference implementation: OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * @dev Because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardBase {\n    /**\n     * @notice Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        ProtocolLib.ProtocolStatus storage ps = ProtocolLib.protocolStatus();\n        // On the first call to nonReentrant, ps.reentrancyStatus will be NOT_ENTERED\n        if (ps.reentrancyStatus == ENTERED) revert BosonErrors.ReentrancyGuard();\n\n        // Any calls to nonReentrant after this point will fail\n        ps.reentrancyStatus = ENTERED;\n\n        _;\n\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        ps.reentrancyStatus = NOT_ENTERED;\n    }\n}\n"
      },
      "contracts/protocol/bases/SellerBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport \"./../../domain/BosonConstants.sol\";\nimport { IBosonAccountEvents } from \"../../interfaces/events/IBosonAccountEvents.sol\";\nimport { ProtocolBase } from \"./ProtocolBase.sol\";\nimport { ProtocolLib } from \"./../libs/ProtocolLib.sol\";\nimport { BosonTypes } from \"../../domain/BosonTypes.sol\";\nimport { IInitializableVoucherClone } from \"../../interfaces/IInitializableVoucherClone.sol\";\nimport { IERC721 } from \"../../interfaces/IERC721.sol\";\n\n/**\n * @title SellerBase\n *\n * @dev Provides methods for seller creation that can be shared across facets\n */\ncontract SellerBase is ProtocolBase, IBosonAccountEvents {\n    /**\n     * @notice Creates a seller.\n     *\n     * Emits a SellerCreated event if successful.\n     *\n     * Reverts if:\n     * - Caller is not the supplied assistant\n     * - Supplied clerk is not a zero address\n     * - The sellers region of protocol is paused\n     * - Address values are zero address\n     * - Addresses are not unique to this seller\n     * - Caller is not the admin address of the stored seller\n     * - Caller is not the address of the owner of the stored AuthToken\n     * - Seller is not active (if active == false)\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - AuthTokenType is Custom\n     * - Seller salt is not unique\n     * - Clone creation fails\n     *\n     * @param _seller - the fully populated struct with seller id set to 0x0\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     */\n    function createSellerInternal(\n        Seller memory _seller,\n        AuthToken calldata _authToken,\n        VoucherInitValues calldata _voucherInitValues\n    ) internal {\n        // Check active is not set to false\n        if (!_seller.active) revert MustBeActive();\n\n        // Check for zero address\n        if (_seller.assistant == address(0) || _seller.treasury == address(0)) revert InvalidAddress();\n\n        // Admin address or AuthToken data must be present. A seller can have one or the other\n        if (\n            (_seller.admin == address(0) && _authToken.tokenType == AuthTokenType.None) ||\n            (_seller.admin != address(0) && _authToken.tokenType != AuthTokenType.None)\n        ) revert AdminOrAuthToken();\n\n        // Cache protocol lookups for reference\n        ProtocolLib.ProtocolLookups storage lookups = protocolLookups();\n\n        // Get message sender\n        address sender = msgSender();\n\n        // Check that caller is the supplied assistant\n        if (_seller.assistant != sender) revert NotAssistant();\n        if (_seller.clerk != address(0)) revert ClerkDeprecated();\n\n        // Do caller and uniqueness checks based on auth type\n        if (_authToken.tokenType != AuthTokenType.None) {\n            if (_authToken.tokenType == AuthTokenType.Custom) revert InvalidAuthTokenType();\n\n            // Check that caller owns the auth token\n            address authTokenContract = lookups.authTokenContracts[_authToken.tokenType];\n            address tokenIdOwner = IERC721(authTokenContract).ownerOf(_authToken.tokenId);\n            if (tokenIdOwner != sender) revert NotAdmin();\n\n            // Check that auth token is unique to this seller\n            if (lookups.sellerIdByAuthToken[_authToken.tokenType][_authToken.tokenId] != 0)\n                revert AuthTokenMustBeUnique();\n        } else {\n            // Check that caller is supplied admin\n            if (_seller.admin != sender) revert NotAdmin();\n        }\n\n        // Check that the sender address is unique to one seller id, across all roles\n        if (lookups.sellerIdByAdmin[sender] != 0 || lookups.sellerIdByAssistant[sender] != 0)\n            revert SellerAddressMustBeUnique();\n\n        // Get the next account id and increment the counter\n        uint256 sellerId = protocolCounters().nextAccountId++;\n        _seller.id = sellerId;\n        storeSeller(_seller, _authToken, lookups);\n\n        // Set treasury as the default royalty recipient\n        if (_voucherInitValues.royaltyPercentage > protocolLimits().maxRoyaltyPercentage)\n            revert InvalidRoyaltyPercentage();\n        RoyaltyRecipientInfo[] storage royaltyRecipients = lookups.royaltyRecipientsBySeller[sellerId];\n        RoyaltyRecipientInfo storage defaultRoyaltyRecipient = royaltyRecipients.push();\n        // We don't store the defaultRoyaltyRecipient.wallet, since it's always the trasury\n        defaultRoyaltyRecipient.minRoyaltyPercentage = _voucherInitValues.royaltyPercentage;\n\n        // Calculate seller salt and check that it is unique\n        bytes32 sellerSalt = keccak256(abi.encodePacked(sender, _voucherInitValues.collectionSalt));\n        if (lookups.isUsedSellerSalt[sellerSalt]) revert SellerSaltNotUnique();\n        lookups.sellerSalt[sellerId] = sellerSalt;\n        lookups.isUsedSellerSalt[sellerSalt] = true;\n\n        // Create clone and store its address cloneAddress\n        address voucherCloneAddress = cloneBosonVoucher(sellerId, 0, sellerSalt, _seller.assistant, _voucherInitValues);\n        lookups.cloneAddress[sellerId] = voucherCloneAddress;\n\n        // Notify watchers of state change\n        emit SellerCreated(sellerId, _seller, voucherCloneAddress, _authToken, sender);\n        emit RoyaltyRecipientsChanged(sellerId, fetchRoyaltyRecipients(sellerId), sender);\n    }\n\n    /**\n     * @notice Validates seller struct and stores it to storage, along with auth token if present.\n     *\n     * @param _seller - the fully populated struct with seller id set\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _lookups - ProtocolLib.ProtocolLookups struct\n     */\n    function storeSeller(\n        Seller memory _seller,\n        AuthToken calldata _authToken,\n        ProtocolLib.ProtocolLookups storage _lookups\n    ) internal {\n        // Get storage location for seller\n        (, Seller storage seller, AuthToken storage authToken) = fetchSeller(_seller.id);\n\n        // Set seller props individually since memory structs can't be copied to storage\n        seller.id = _seller.id;\n        seller.assistant = _seller.assistant;\n        seller.admin = _seller.admin;\n        seller.treasury = _seller.treasury;\n        seller.active = _seller.active;\n        seller.metadataUri = _seller.metadataUri;\n\n        // Auth token passed in\n        if (_authToken.tokenType != AuthTokenType.None) {\n            // Store auth token\n            authToken.tokenId = _authToken.tokenId;\n            authToken.tokenType = _authToken.tokenType;\n\n            // Store seller by auth token reference\n            _lookups.sellerIdByAuthToken[_authToken.tokenType][_authToken.tokenId] = _seller.id;\n        } else {\n            // Empty auth token passed in\n            // Store admin address reference\n            _lookups.sellerIdByAdmin[_seller.admin] = _seller.id;\n        }\n\n        // Map the seller's other addresses to the seller id. It's not necessary to map the treasury address, as it only receives funds\n        _lookups.sellerIdByAssistant[_seller.assistant] = _seller.id;\n    }\n\n    /**\n     * @notice Creates a minimal clone of the Boson Voucher Contract.\n     *\n     * Reverts if clone creation fails.\n     *\n     * @param _sellerId - id of the seller\n     * @param _collectionIndex - index of the collection.\n     * @param _sellerSalt - seller dependent salt, used to create the clone address\n     * @param _assistant - address of the assistant\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @return cloneAddress - the address of newly created clone\n     */\n    function cloneBosonVoucher(\n        uint256 _sellerId,\n        uint256 _collectionIndex,\n        bytes32 _sellerSalt,\n        address _assistant,\n        VoucherInitValues calldata _voucherInitValues\n    ) internal returns (address cloneAddress) {\n        // Pointer to stored addresses\n        ProtocolLib.ProtocolAddresses storage pa = protocolAddresses();\n\n        // Load beacon proxy contract address\n        bytes20 targetBytes = bytes20(pa.beaconProxy);\n        bytes32 collectionSalt = keccak256(abi.encodePacked(_sellerSalt, _voucherInitValues.collectionSalt));\n\n        // create a minimal clone\n        assembly {\n            let clone := mload(0x40)\n            mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n            mstore(add(clone, 0x14), targetBytes)\n            mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n            cloneAddress := create2(0, clone, 0x37, collectionSalt)\n        }\n\n        if (cloneAddress == address(0)) revert CloneCreationFailed();\n\n        // Initialize the clone\n        IInitializableVoucherClone(cloneAddress).initialize(pa.voucherBeacon);\n        IInitializableVoucherClone(cloneAddress).initializeVoucher(\n            _sellerId,\n            _collectionIndex,\n            _assistant,\n            _voucherInitValues\n        );\n    }\n\n    /**\n     * @notice Fetches a given seller pending update from storage by id\n     *\n     * @param _sellerId - the id of the seller\n     * @return exists - whether the seller or auth token pending update exists\n     * @return sellerPendingUpdate - the seller pending update details. See {BosonTypes.Seller}\n     * @return authTokenPendingUpdate - auth token pending update details\n     */\n    function fetchSellerPendingUpdate(\n        uint256 _sellerId\n    )\n        internal\n        view\n        returns (bool exists, Seller storage sellerPendingUpdate, AuthToken storage authTokenPendingUpdate)\n    {\n        // Cache protocol entities for reference\n        ProtocolLib.ProtocolLookups storage lookups = protocolLookups();\n\n        // Get the seller pending update slot\n        sellerPendingUpdate = lookups.pendingAddressUpdatesBySeller[_sellerId];\n\n        //Get the seller auth token pending update slot\n        authTokenPendingUpdate = lookups.pendingAuthTokenUpdatesBySeller[_sellerId];\n\n        // Determine existence\n        exists =\n            sellerPendingUpdate.admin != address(0) ||\n            sellerPendingUpdate.assistant != address(0) ||\n            authTokenPendingUpdate.tokenType != AuthTokenType.None;\n    }\n\n    /**\n     * @notice Gets seller's royalty recipients.\n     *\n     * @param _sellerId - seller id\n     * @return royaltyRecipients - list of royalty recipients\n     */\n    function fetchRoyaltyRecipients(\n        uint256 _sellerId\n    ) internal view returns (RoyaltyRecipientInfo[] memory royaltyRecipients) {\n        return protocolLookups().royaltyRecipientsBySeller[_sellerId];\n    }\n}\n"
      },
      "contracts/protocol/bases/TwinBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport \"../../domain/BosonConstants.sol\";\nimport { IBosonTwinEvents } from \"../../interfaces/events/IBosonTwinEvents.sol\";\nimport { ITwinToken } from \"../../interfaces/ITwinToken.sol\";\nimport { ProtocolBase } from \"./../bases/ProtocolBase.sol\";\nimport { ProtocolLib } from \"./../libs/ProtocolLib.sol\";\nimport { IERC721 } from \"../../interfaces/IERC721.sol\";\nimport { IERC1155 } from \"../../interfaces/IERC1155.sol\";\n\n/**\n * @title TwinBase\n *\n * @notice Provides functions for twin creation that can be shared across facets\n */\ncontract TwinBase is ProtocolBase, IBosonTwinEvents {\n    /**\n     * @notice Creates a Twin.\n     *\n     * Emits a TwinCreated event if successful.\n     *\n     * Reverts if:\n     * - Seller does not exist\n     * - Protocol is not approved to transfer the seller's token\n     * - Twin supplyAvailable is zero\n     * - Twin is NonFungibleToken and amount was set\n     * - Twin is NonFungibleToken and end of range would overflow\n     * - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     * - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     * - Twin is FungibleToken or MultiToken and amount was not set\n     * - Twin is FungibleToken or MultiToken and amount is greater than supply available\n     *\n     * @param _twin - the fully populated struct with twin id set to 0x0\n     */\n    function createTwinInternal(Twin memory _twin) internal {\n        // Cache protocol lookups for reference\n        ProtocolLib.ProtocolLookups storage lookups = protocolLookups();\n\n        // get message sender\n        address sender = msgSender();\n\n        // get seller id, make sure it exists and store it to incoming struct\n        (bool exists, uint256 sellerId) = getSellerIdByAssistant(sender);\n        if (!exists) revert NotAssistant();\n\n        // Protocol must be approved to transfer seller’s tokens\n        if (!isProtocolApproved(_twin.tokenAddress, sender, address(this))) revert NoTransferApproved();\n\n        // Twin supply must exist and can't be zero\n        if (_twin.supplyAvailable == 0) revert InvalidSupplyAvailable();\n\n        // Get the next twinId and increment the counter\n        uint256 twinId = protocolCounters().nextTwinId++;\n        _twin.id = twinId;\n\n        if (_twin.tokenType == TokenType.NonFungibleToken) {\n            // Check if the token supports IERC721 interface\n            if (!contractSupportsInterface(_twin.tokenAddress, type(IERC721).interfaceId)) revert InvalidTokenAddress();\n\n            // If token is NonFungible amount should be zero\n            if (_twin.amount != 0) revert InvalidTwinProperty();\n\n            // Calculate new twin range [tokenId...lastTokenId]\n            uint256 lastTokenId;\n            uint256 tokenId = _twin.tokenId;\n            if (_twin.supplyAvailable == type(uint256).max) {\n                if (tokenId > (1 << 255)) revert InvalidTwinTokenRange(); // if supply is \"unlimited\", starting index can be at most 2*255\n                lastTokenId = type(uint256).max;\n            } else {\n                if (type(uint256).max - _twin.supplyAvailable < tokenId) revert InvalidTwinTokenRange();\n                lastTokenId = tokenId + _twin.supplyAvailable - 1;\n            }\n\n            // Get all ranges of twins that belong to the seller and to the same token address of the new twin to validate if range is available\n            TokenRange[] storage twinRanges = lookups.twinRangesBySeller[sellerId][_twin.tokenAddress];\n\n            uint256 twinRangesLength = twinRanges.length;\n            // Checks if token range isn't being used in any other twin of seller\n            for (uint256 i = 0; i < twinRangesLength; ) {\n                // A valid range has:\n                // - the first id of range greater than the last token id (tokenId + initialSupply - 1) of the looped twin or\n                // - the last id of range lower than the looped twin tokenId (beginning of range)\n                if (lastTokenId >= twinRanges[i].start && tokenId <= twinRanges[i].end) revert InvalidTwinTokenRange();\n\n                unchecked {\n                    i++;\n                }\n            }\n\n            // Add range to twinRangesBySeller mapping\n            TokenRange storage tokenRange = twinRanges.push();\n            tokenRange.start = tokenId;\n            tokenRange.end = lastTokenId;\n            tokenRange.twinId = twinId;\n\n            lookups.rangeIdByTwin[twinId] = ++twinRangesLength;\n        } else if (_twin.tokenType == TokenType.MultiToken) {\n            // If token is Fungible or MultiToken amount should not be zero\n            // Also, the amount of tokens should not be more than the available token supply.\n            if (_twin.amount == 0 || _twin.amount > _twin.supplyAvailable) revert InvalidAmount();\n\n            // Not every ERC20 has supportsInterface method so we can't check interface support if token type is NonFungible\n            // Check if the token supports IERC1155 interface\n            if (!contractSupportsInterface(_twin.tokenAddress, type(IERC1155).interfaceId))\n                revert InvalidTokenAddress();\n        } else {\n            // If token is Fungible or MultiToken amount should not be zero\n            // Also, the amount of tokens should not be more than the available token supply.\n            if (_twin.amount == 0 || _twin.amount > _twin.supplyAvailable) revert InvalidAmount();\n        }\n\n        // Get storage location for twin\n        (, Twin storage twin) = fetchTwin(twinId);\n\n        // Set twin props individually since memory structs can't be copied to storage\n        twin.id = twinId;\n        twin.sellerId = _twin.sellerId = sellerId;\n        twin.supplyAvailable = _twin.supplyAvailable;\n        twin.amount = _twin.amount;\n        twin.tokenId = _twin.tokenId;\n        twin.tokenAddress = _twin.tokenAddress;\n        twin.tokenType = _twin.tokenType;\n\n        // Notify watchers of state change\n        emit TwinCreated(twinId, sellerId, _twin, sender);\n    }\n\n    /**\n     * @notice Checks if the contract supports the correct interface for the selected token type.\n     *\n     * @param _tokenAddress - the address of the token to check\n     * @param _interfaceId - the interface to check for\n     * @return true if the contract supports the interface, false otherwise\n     */\n    function contractSupportsInterface(address _tokenAddress, bytes4 _interfaceId) internal view returns (bool) {\n        try ITwinToken(_tokenAddress).supportsInterface(_interfaceId) returns (bool supported) {\n            return supported;\n        } catch {\n            return false;\n        }\n    }\n\n    /**\n     * @notice Checks if protocol is approved to transfer the tokens.\n     *\n     * @param _tokenAddress - the address of the seller's twin token contract\n     * @param _assistant - the seller's assistant address\n     * @param _protocol - the protocol address\n     * @return _approved - the approve status\n     */\n    function isProtocolApproved(\n        address _tokenAddress,\n        address _assistant,\n        address _protocol\n    ) internal view returns (bool _approved) {\n        if (_tokenAddress == address(0)) revert UnsupportedToken();\n\n        try ITwinToken(_tokenAddress).allowance(_assistant, _protocol) returns (uint256 _allowance) {\n            if (_allowance > 0) {\n                _approved = true;\n            }\n        } catch {\n            try ITwinToken(_tokenAddress).isApprovedForAll(_assistant, _protocol) returns (bool _isApproved) {\n                _approved = _isApproved;\n            } catch {\n                revert UnsupportedToken();\n            }\n        }\n    }\n}\n"
      },
      "contracts/protocol/facets/OrchestrationHandlerFacet1.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.22;\n\nimport \"../../domain/BosonConstants.sol\";\nimport { IBosonOrchestrationHandler } from \"../../interfaces/handlers/IBosonOrchestrationHandler.sol\";\nimport { DiamondLib } from \"../../diamond/DiamondLib.sol\";\nimport { SellerBase } from \"../bases/SellerBase.sol\";\nimport { GroupBase } from \"../bases/GroupBase.sol\";\nimport { OfferBase } from \"../bases/OfferBase.sol\";\nimport { TwinBase } from \"../bases/TwinBase.sol\";\nimport { BundleBase } from \"../bases/BundleBase.sol\";\nimport { PausableBase } from \"../bases/PausableBase.sol\";\nimport { DisputeBase } from \"../bases/DisputeBase.sol\";\n\n/**\n * @title OrchestrationHandlerFacet1\n *\n * @notice Combines creation of multiple entities (accounts, offers, groups, twins, bundles) in a single transaction.\n */\ncontract OrchestrationHandlerFacet1 is PausableBase, SellerBase, OfferBase, GroupBase, TwinBase, BundleBase {\n    /**\n     * @notice Initializes facet.\n     * This function is callable only once.\n     */\n    function initialize() public onlyUninitialized(type(IBosonOrchestrationHandler).interfaceId) {\n        DiamondLib.addSupportedInterface(type(IBosonOrchestrationHandler).interfaceId);\n    }\n\n    /**\n     * @notice Creates a seller (with optional auth token) and an offer in a single transaction.\n     *\n     * Limitations:\n     * 1. If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     * 2. Only the default royalty recipient can be used. Other royalty recipients can be added to seller later and next offers can use them.\n     *\n     * Emits a SellerCreated and an OfferCreated event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied assistant\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _seller - the fully populated seller struct\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndOffer(\n        Seller memory _seller,\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        AuthToken calldata _authToken,\n        VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) public sellersNotPaused offersNotPaused orchestrationNotPaused nonReentrant {\n        createSellerInternal(_seller, _authToken, _voucherInitValues);\n        createOfferInternal(_offer, _offerDates, _offerDurations, _disputeResolverId, _agentId, _feeLimit);\n    }\n\n    /**\n     * @notice Creates a seller (with optional auth token), an offer and reserve range for preminting in a single transaction.\n     *\n     * Limitation of the method:\n     * If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     *\n     * Emits a SellerCreated, an OfferCreated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied assistant\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _seller - the fully populated seller struct\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndPremintedOffer(\n        Seller memory _seller,\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        PremintParameters calldata _premintParameters,\n        AuthToken calldata _authToken,\n        VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external {\n        createSellerAndOffer(\n            _seller,\n            _offer,\n            _offerDates,\n            _offerDurations,\n            _disputeResolverId,\n            _authToken,\n            _voucherInitValues,\n            _agentId,\n            _feeLimit\n        );\n        reserveRangeInternal(_offer.id, _premintParameters.reservedRangeLength, _premintParameters.to);\n    }\n\n    /**\n     * @notice Takes an offer and a condition, creates an offer, then creates a group with that offer and the given condition.\n     *\n     * Emits an OfferCreated and a GroupCreated event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _condition - the fully populated condition struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createOfferWithCondition(\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        Condition calldata _condition,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) public offersNotPaused groupsNotPaused orchestrationNotPaused nonReentrant {\n        // Create offer and update structs values to represent true state\n        createOfferInternal(_offer, _offerDates, _offerDurations, _disputeResolverId, _agentId, _feeLimit);\n\n        // Construct new group\n        // - group id is 0, and it is ignored\n        // - note that _offer fields are updated during createOfferInternal, so they represent correct values\n        Group memory _group;\n        _group.sellerId = _offer.sellerId;\n        _group.offerIds = new uint256[](1);\n        _group.offerIds[0] = _offer.id;\n\n        // Create group and update structs values to represent true state\n        createGroupInternal(_group, _condition);\n    }\n\n    /**\n     * @notice Takes an offer, range for preminting and a condition, creates an offer, then creates a group with that offer and the given condition and then reservers range for preminting.\n     *\n     * Emits an OfferCreated, a GroupCreated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _condition - the fully populated condition struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createPremintedOfferWithCondition(\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        PremintParameters calldata _premintParameters,\n        Condition calldata _condition,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) public {\n        createOfferWithCondition(\n            _offer,\n            _offerDates,\n            _offerDurations,\n            _disputeResolverId,\n            _condition,\n            _agentId,\n            _feeLimit\n        );\n        reserveRangeInternal(_offer.id, _premintParameters.reservedRangeLength, _premintParameters.to);\n    }\n\n    /**\n     * @notice Takes an offer and group ID, creates an offer and adds it to the existing group with given id.\n     *\n     * Emits an OfferCreated and a GroupUpdated event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When adding to the group if:\n     *   - Group does not exists\n     *   - Caller is not the assistant of the group\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _groupId - id of the group, to which offer will be added\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createOfferAddToGroup(\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        uint256 _groupId,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) public offersNotPaused groupsNotPaused orchestrationNotPaused nonReentrant {\n        // Create offer and update structs values to represent true state\n        createOfferInternal(_offer, _offerDates, _offerDurations, _disputeResolverId, _agentId, _feeLimit);\n\n        // Create an array with offer ids and add it to the group\n        uint256[] memory _offerIds = new uint256[](1);\n        _offerIds[0] = _offer.id;\n        addOffersToGroupInternal(_groupId, _offerIds);\n    }\n\n    /**\n     * @notice Takes an offer, a range for preminting and group ID, creates an offer and adds it to the existing group with given id and reserves the range for preminting.\n     *\n     * Emits an OfferCreated, a GroupUpdated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When adding to the group if:\n     *   - Group does not exists\n     *   - Caller is not the assistant of the group\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _groupId - id of the group, to which offer will be added\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createPremintedOfferAddToGroup(\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        PremintParameters calldata _premintParameters,\n        uint256 _groupId,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external {\n        createOfferAddToGroup(_offer, _offerDates, _offerDurations, _disputeResolverId, _groupId, _agentId, _feeLimit);\n        reserveRangeInternal(_offer.id, _premintParameters.reservedRangeLength, _premintParameters.to);\n    }\n\n    /**\n     * @notice Takes an offer and a twin, creates an offer, creates a twin, then creates a bundle with that offer and the given twin.\n     *\n     * Emits an OfferCreated, a TwinCreated and a BundleCreated event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _twin - the fully populated twin struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createOfferAndTwinWithBundle(\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        Twin memory _twin,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) public offersNotPaused twinsNotPaused bundlesNotPaused orchestrationNotPaused nonReentrant {\n        // Create offer and update structs values to represent true state\n        createOfferInternal(_offer, _offerDates, _offerDurations, _disputeResolverId, _agentId, _feeLimit);\n\n        // Create twin and pack everything into a bundle\n        createTwinAndBundleAfterOffer(_twin, _offer.id, _offer.sellerId);\n    }\n\n    /**\n     * @notice Takes an offer, a range for preminting and a twin, creates an offer, creates a twin, then creates a bundle with that offer and the given twin and reserves the range for preminting.\n     *\n     * Emits an OfferCreated, a TwinCreated and a BundleCreated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _twin - the fully populated twin struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createPremintedOfferAndTwinWithBundle(\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        PremintParameters calldata _premintParameters,\n        Twin memory _twin,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) public {\n        createOfferAndTwinWithBundle(\n            _offer,\n            _offerDates,\n            _offerDurations,\n            _disputeResolverId,\n            _twin,\n            _agentId,\n            _feeLimit\n        );\n        reserveRangeInternal(_offer.id, _premintParameters.reservedRangeLength, _premintParameters.to);\n    }\n\n    /**\n     * @notice Takes an offer, a condition and a twin, creates an offer, then creates a group with that offer and the given condition.\n     * It then creates a twin, then creates a bundle with that offer and the given twin.\n     *\n     * Emits an OfferCreated, a GroupCreated, a TwinCreated and a BundleCreated event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _condition - the fully populated condition struct\n     * @param _twin - the fully populated twin struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createOfferWithConditionAndTwinAndBundle(\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        Condition calldata _condition,\n        Twin memory _twin,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) public twinsNotPaused bundlesNotPaused {\n        // Create offer with condition first\n        createOfferWithCondition(\n            _offer,\n            _offerDates,\n            _offerDurations,\n            _disputeResolverId,\n            _condition,\n            _agentId,\n            _feeLimit\n        );\n        // Create twin and pack everything into a bundle\n        createTwinAndBundleAfterOffer(_twin, _offer.id, _offer.sellerId);\n    }\n\n    /**\n     * @notice Takes an offer, a range for preminting, a condition and a twin, creates an offer, then creates a group with that offer and the given condition.\n     * It then creates a twin, then creates a bundle with that offer and the given twin and reserves the range for preminting.\n     *\n     * Emits an OfferCreated, a GroupCreated, a TwinCreated, a BundleCreated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _condition - the fully populated condition struct\n     * @param _twin - the fully populated twin struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createPremintedOfferWithConditionAndTwinAndBundle(\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        PremintParameters calldata _premintParameters,\n        Condition calldata _condition,\n        Twin memory _twin,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) public {\n        createOfferWithConditionAndTwinAndBundle(\n            _offer,\n            _offerDates,\n            _offerDurations,\n            _disputeResolverId,\n            _condition,\n            _twin,\n            _agentId,\n            _feeLimit\n        );\n        reserveRangeInternal(_offer.id, _premintParameters.reservedRangeLength, _premintParameters.to);\n    }\n\n    /**\n     * @notice Takes a seller, an offer, a condition and an optional auth token. Creates a seller, creates an offer,\n     * then creates a group with that offer and the given condition.\n     *\n     * Limitation of the method:\n     * If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     *\n     * Emits a SellerCreated, an OfferCreated and a GroupCreated event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied assistant\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _seller - the fully populated seller struct\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _condition - the fully populated condition struct\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndOfferWithCondition(\n        Seller memory _seller,\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        Condition calldata _condition,\n        AuthToken calldata _authToken,\n        VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) public sellersNotPaused {\n        createSellerInternal(_seller, _authToken, _voucherInitValues);\n        createOfferWithCondition(\n            _offer,\n            _offerDates,\n            _offerDurations,\n            _disputeResolverId,\n            _condition,\n            _agentId,\n            _feeLimit\n        );\n    }\n\n    /**\n     * @notice Takes a seller, an offer, a range for preminting, a condition and an optional auth token. Creates a seller, creates an offer,\n     * then creates a group with that offer and the given condition and reserves the range for preminting.\n     *\n     * Limitation of the method:\n     * If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     *\n     * Emits a SellerCreated, an OfferCreated, a GroupCreated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied assistant\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _seller - the fully populated seller struct\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _condition - the fully populated condition struct\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndPremintedOfferWithCondition(\n        Seller memory _seller,\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        PremintParameters calldata _premintParameters,\n        Condition calldata _condition,\n        AuthToken calldata _authToken,\n        VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external {\n        createSellerAndOfferWithCondition(\n            _seller,\n            _offer,\n            _offerDates,\n            _offerDurations,\n            _disputeResolverId,\n            _condition,\n            _authToken,\n            _voucherInitValues,\n            _agentId,\n            _feeLimit\n        );\n        reserveRangeInternal(_offer.id, _premintParameters.reservedRangeLength, _premintParameters.to);\n    }\n\n    /**\n     * @notice Takes a seller, an offer, a twin, and an optional auth token. Creates a seller, creates an offer, creates a twin,\n     * then creates a bundle with that offer and the given twin.\n     *\n     * Limitation of the method:\n     * If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     *\n     * Emits a SellerCreated, an OfferCreated, a TwinCreated and a BundleCreated event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied assistant\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _seller - the fully populated seller struct\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _twin - the fully populated twin struct\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndOfferAndTwinWithBundle(\n        Seller memory _seller,\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        Twin memory _twin,\n        AuthToken calldata _authToken,\n        VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) public sellersNotPaused {\n        createSellerInternal(_seller, _authToken, _voucherInitValues);\n        createOfferAndTwinWithBundle(\n            _offer,\n            _offerDates,\n            _offerDurations,\n            _disputeResolverId,\n            _twin,\n            _agentId,\n            _feeLimit\n        );\n    }\n\n    /**\n     * @notice Takes a seller, an offer, a range for preminting, a twin, and an optional auth token. Creates a seller, creates an offer, creates a twin,\n     * then creates a bundle with that offer and the given twin and reserves the range for preminting.\n     *\n     * Limitation of the method:\n     * If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     *\n     * Emits a SellerCreated, an OfferCreated, a TwinCreated, a BundleCreated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied assistant\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _seller - the fully populated seller struct\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _twin - the fully populated twin struct\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndPremintedOfferAndTwinWithBundle(\n        Seller memory _seller,\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        PremintParameters calldata _premintParameters,\n        Twin memory _twin,\n        AuthToken calldata _authToken,\n        VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external {\n        createSellerAndOfferAndTwinWithBundle(\n            _seller,\n            _offer,\n            _offerDates,\n            _offerDurations,\n            _disputeResolverId,\n            _twin,\n            _authToken,\n            _voucherInitValues,\n            _agentId,\n            _feeLimit\n        );\n        reserveRangeInternal(_offer.id, _premintParameters.reservedRangeLength, _premintParameters.to);\n    }\n\n    /**\n     * @notice Takes a seller, an offer, a condition and a twin, and an optional auth token. Creates a seller an offer,\n     * then creates a group with that offer and the given condition. It then creates a twin and a bundle with that offer and the given twin.\n     *\n     * Limitation of the method:\n     * If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     *\n     * Emits an SellerCreated, OfferCreated, a GroupCreated, a TwinCreated and a BundleCreated event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied assistant\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _seller - the fully populated seller struct\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _condition - the fully populated condition struct\n     * @param _twin - the fully populated twin struct\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndOfferWithConditionAndTwinAndBundle(\n        Seller memory _seller,\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        Condition calldata _condition,\n        Twin memory _twin,\n        AuthToken calldata _authToken,\n        VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) public sellersNotPaused {\n        createSellerInternal(_seller, _authToken, _voucherInitValues);\n        createOfferWithConditionAndTwinAndBundle(\n            _offer,\n            _offerDates,\n            _offerDurations,\n            _disputeResolverId,\n            _condition,\n            _twin,\n            _agentId,\n            _feeLimit\n        );\n    }\n\n    /**\n     * @notice Takes a seller, an offer, a range for preminting, a condition and a twin, and an optional auth token. Creates a seller an offer,\n     * then creates a group with that offer and the given condition. It then creates a twin and a bundle with that offer and the given twin\n     * and reserves a range for preminting.\n     *\n     * Limitation of the method:\n     * If chosen dispute resolver has seller allow list, this method will not succeed, since seller that will be created\n     * cannot be on that list. To avoid the failure you can\n     * - Choose a dispute resolver without seller allow list\n     * - Make an absolute zero offer without any dispute resolver specified\n     * - First create a seller {AccountHandler.createSeller}, make sure that dispute resolver adds seller to its allow list\n     *   and then continue with the offer creation\n     *\n     * Emits an SellerCreated, OfferCreated, a GroupCreated, a TwinCreated, a BundleCreated and a RangeReserved event if successful.\n     *\n     * Reverts if:\n     * - The sellers region of protocol is paused\n     * - The offers region of protocol is paused\n     * - The groups region of protocol is paused\n     * - The twins region of protocol is paused\n     * - The bundles region of protocol is paused\n     * - The exchanges region of protocol is paused\n     * - The orchestration region of protocol is paused\n     * - Caller is not the supplied assistant\n     * - Caller is not the supplied admin or does not own supplied auth token\n     * - Supplied clerk is not a zero address\n     * - Admin address is zero address and AuthTokenType == None\n     * - AuthTokenType is not unique to this seller\n     * - Reserved range length is zero\n     * - Reserved range length is greater than quantity available\n     * - Reserved range length is greater than maximum allowed range length\n     * - In seller struct:\n     *   - Address values are zero address\n     *   - Addresses are not unique to this seller\n     *   - Seller is not active (if active == false)\n     * - In offer struct:\n     *   - Caller is not an assistant\n     *   - Valid from date is greater than valid until date\n     *   - Valid until date is not in the future\n     *   - Both voucher expiration date and voucher expiration period are defined\n     *   - Neither voucher expiration date nor voucher expiration period are defined\n     *   - Voucher redeemable period is fixed, but it ends before it starts\n     *   - Voucher redeemable period is fixed, but it ends before offer expires\n     *   - Dispute period is less than minimum dispute period\n     *   - Resolution period is not between the minimum and the maximum resolution period\n     *   - Voided is set to true\n     *   - Available quantity is set to zero\n     *   - Offer type is discovery and the price is not set to zero\n     *   - Dispute resolver wallet is not registered, except for absolute zero offers with unspecified dispute resolver\n     *   - Dispute resolver is not active, except for absolute zero offers with unspecified dispute resolver\n     *   - Seller is not on dispute resolver's seller allow list\n     *   - Dispute resolver does not accept fees in the exchange token\n     *   - Buyer cancel penalty is greater than price\n     *   - Royalty recipient is not on seller's allow list\n     *   - Royalty percentage is less than the value decided by the admin\n     *   - Total royalty percentage is more than max royalty percentage\n     *   - Collection does not exist\n     * - Condition includes invalid combination of parameters\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     * - When agent id is non zero:\n     *   - If Agent does not exist\n     * - If the sum of agent fee amount and protocol fee amount is greater than the offer fee limit determined by the protocol\n     * - If the sum of agent fee amount and protocol fee amount is greater than fee limit set by seller\n     * - _to is not the BosonVoucher contract address or the BosonVoucher contract owner\n     *\n     * @dev No reentrancy guard here since already implemented by called functions. If added here, they would clash.\n     *\n     * @param _seller - the fully populated seller struct\n     * @param _offer - the fully populated struct with offer id set to 0x0 and voided set to false\n     * @param _offerDates - the fully populated offer dates struct\n     * @param _offerDurations - the fully populated offer durations struct\n     * @param _disputeResolverId - the id of chosen dispute resolver (can be 0)\n     * @param _premintParameters - struct containing the amount of tokens to be reserved for preminting and the address to send the pre-minted vouchers to (contract address or contract owner)\n     * @param _condition - the fully populated condition struct\n     * @param _twin - the fully populated twin struct\n     * @param _authToken - optional AuthToken struct that specifies an AuthToken type and tokenId that the seller can use to do admin functions\n     * @param _voucherInitValues - the fully populated BosonTypes.VoucherInitValues struct\n     * @param _agentId - the id of agent\n     * @param _feeLimit - the maximum fee that seller is willing to pay per exchange (for static offers)\n     */\n    function createSellerAndPremintedOfferWithConditionAndTwinAndBundle(\n        Seller memory _seller,\n        Offer memory _offer,\n        OfferDates calldata _offerDates,\n        OfferDurations calldata _offerDurations,\n        uint256 _disputeResolverId,\n        PremintParameters calldata _premintParameters,\n        Condition calldata _condition,\n        Twin memory _twin,\n        AuthToken calldata _authToken,\n        VoucherInitValues calldata _voucherInitValues,\n        uint256 _agentId,\n        uint256 _feeLimit\n    ) external {\n        createSellerAndOfferWithConditionAndTwinAndBundle(\n            _seller,\n            _offer,\n            _offerDates,\n            _offerDurations,\n            _disputeResolverId,\n            _condition,\n            _twin,\n            _authToken,\n            _voucherInitValues,\n            _agentId,\n            _feeLimit\n        );\n        reserveRangeInternal(_offer.id, _premintParameters.reservedRangeLength, _premintParameters.to);\n    }\n\n    /**\n     * @notice Takes a twin, an offerId and a sellerId. Creates a twin, then creates a bundle with that offer and the given twin.\n     *\n     * Emits a TwinCreated and a BundleCreated event if successful.\n     *\n     * Reverts if:\n     * - Condition includes invalid combination of parameters\n     * - When creating twin if\n     *   - Not approved to transfer the seller's token\n     *   - SupplyAvailable is zero\n     *   - Twin is NonFungibleToken and amount was set\n     *   - Twin is NonFungibleToken and end of range would overflow\n     *   - Twin is NonFungibleToken with unlimited supply and starting token id is too high\n     *   - Twin is NonFungibleToken and range is already being used in another twin of the seller\n     *   - Twin is FungibleToken or MultiToken and amount was not set\n     *\n     * @param _twin - the fully populated twin struct\n     * @param _offerId - offerid, obtained in previous steps\n     * @param _sellerId - sellerId, obtained in previous steps\n     */\n    function createTwinAndBundleAfterOffer(Twin memory _twin, uint256 _offerId, uint256 _sellerId) internal {\n        // Create twin and update structs values to represent true state\n        createTwinInternal(_twin);\n\n        // Construct new bundle\n        // - bundle id is 0, and it is ignored\n        // - note that _twin fields are updated during createTwinInternal, so they represent correct values\n        Bundle memory _bundle;\n        _bundle.sellerId = _sellerId;\n        _bundle.offerIds = new uint256[](1);\n        _bundle.offerIds[0] = _offerId;\n        _bundle.twinIds = new uint256[](1);\n        _bundle.twinIds[0] = _twin.id;\n\n        // create bundle and update structs values to represent true state\n        createBundleInternal(_bundle);\n    }\n}\n"
      },
      "contracts/protocol/libs/EIP712Lib.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport \"../../domain/BosonConstants.sol\";\nimport { BosonErrors } from \"../../domain/BosonErrors.sol\";\nimport { ProtocolLib } from \"../libs/ProtocolLib.sol\";\n\n/**\n * @title EIP712Lib\n *\n * @dev Provides the domain separator and chain id.\n */\nlibrary EIP712Lib {\n    /**\n     * @notice Generates the domain separator hash.\n     * @dev Using the chainId as the salt enables the client to be active on one chain\n     * while a metatx is signed for a contract on another chain. That could happen if the client is,\n     * for instance, a metaverse scene that runs on one chain while the contracts it interacts with are deployed on another chain.\n     *\n     * @param _name - the name of the protocol\n     * @param _version -  The version of the protocol\n     * @return the domain separator hash\n     */\n    function buildDomainSeparator(string memory _name, string memory _version) internal view returns (bytes32) {\n        return\n            keccak256(\n                abi.encode(\n                    EIP712_DOMAIN_TYPEHASH,\n                    keccak256(bytes(_name)),\n                    keccak256(bytes(_version)),\n                    address(this),\n                    block.chainid\n                )\n            );\n    }\n\n    /**\n     * @notice Recovers the Signer from the Signature components.\n     *\n     * Reverts if:\n     * - Signer is the zero address\n     *\n     * @param _user  - the sender of the transaction\n     * @param _hashedMetaTx - hashed meta transaction\n     * @param _sigR - r part of the signer's signature\n     * @param _sigS - s part of the signer's signature\n     * @param _sigV - v part of the signer's signature\n     * @return true if signer is same as _user parameter\n     */\n    function verify(\n        address _user,\n        bytes32 _hashedMetaTx,\n        bytes32 _sigR,\n        bytes32 _sigS,\n        uint8 _sigV\n    ) internal returns (bool) {\n        // Ensure signature is unique\n        // See https://github.com/OpenZeppelin/openzeppelin-contracts/blob/04695aecbd4d17dddfd55de766d10e3805d6f42f/contracts/cryptography/ECDSA.sol#63\n        if (\n            uint256(_sigS) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 ||\n            (_sigV != 27 && _sigV != 28)\n        ) revert BosonErrors.InvalidSignature();\n\n        address signer = ecrecover(toTypedMessageHash(_hashedMetaTx), _sigV, _sigR, _sigS);\n        if (signer == address(0)) revert BosonErrors.InvalidSignature();\n        return signer == _user;\n    }\n\n    /**\n     * @notice Gets the domain separator from storage if matches with the chain id and diamond address, else, build new domain separator.\n     *\n     * @return the domain separator\n     */\n    function getDomainSeparator() private returns (bytes32) {\n        ProtocolLib.ProtocolMetaTxInfo storage pmti = ProtocolLib.protocolMetaTxInfo();\n        uint256 cachedChainId = pmti.cachedChainId;\n\n        if (block.chainid == cachedChainId) {\n            return pmti.domainSeparator;\n        } else {\n            bytes32 domainSeparator = buildDomainSeparator(PROTOCOL_NAME, PROTOCOL_VERSION);\n            pmti.domainSeparator = domainSeparator;\n            pmti.cachedChainId = block.chainid;\n\n            return domainSeparator;\n        }\n    }\n\n    /**\n     * @notice Generates EIP712 compatible message hash.\n     *\n     * @dev Accepts message hash and returns hash message in EIP712 compatible form\n     * so that it can be used to recover signer from signature signed using EIP712 formatted data\n     * https://eips.ethereum.org/EIPS/eip-712\n     * \"\\\\x19\" makes the encoding deterministic\n     * \"\\\\x01\" is the version byte to make it compatible to EIP-191\n     *\n     * @param _messageHash  - the message hash\n     * @return the EIP712 compatible message hash\n     */\n    function toTypedMessageHash(bytes32 _messageHash) internal returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", getDomainSeparator(), _messageHash));\n    }\n\n    /**\n     * @notice Gets the current message sender address from storage.\n     *\n     * @return the the current message sender address from storage\n     */\n    function getCurrentSenderAddress() internal view returns (address) {\n        return ProtocolLib.protocolMetaTxInfo().currentSenderAddress;\n    }\n\n    /**\n     * @notice Returns the message sender address.\n     *\n     * @dev Could be msg.sender or the message sender address from storage (in case of meta transaction).\n     *\n     * @return the message sender address\n     */\n    function msgSender() internal view returns (address) {\n        bool isItAMetaTransaction = ProtocolLib.protocolMetaTxInfo().isMetaTransaction;\n\n        // Get sender from the storage if this is a meta transaction\n        if (isItAMetaTransaction) {\n            address sender = getCurrentSenderAddress();\n            if (sender == address(0)) revert BosonErrors.InvalidAddress();\n\n            return sender;\n        } else {\n            return msg.sender;\n        }\n    }\n}\n"
      },
      "contracts/protocol/libs/FundsLib.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport \"../../domain/BosonConstants.sol\";\nimport { BosonErrors } from \"../../domain/BosonErrors.sol\";\nimport { BosonTypes } from \"../../domain/BosonTypes.sol\";\nimport { EIP712Lib } from \"../libs/EIP712Lib.sol\";\nimport { ProtocolLib } from \"../libs/ProtocolLib.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IBosonFundsLibEvents } from \"../../interfaces/events/IBosonFundsEvents.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\n/**\n * @title FundsLib\n *\n * @dev\n */\nlibrary FundsLib {\n    using SafeERC20 for IERC20;\n\n    /**\n     * @notice Takes in the offer id and buyer id and encumbers buyer's and seller's funds during the commitToOffer.\n     * If offer is preminted, caller's funds are not encumbered, but the price is covered from the seller's funds.\n     *\n     * Emits FundsEncumbered event if successful.\n     *\n     * Reverts if:\n     * - Offer price is in native token and caller does not send enough\n     * - Offer price is in some ERC20 token and caller also sends native currency\n     * - Contract at token address does not support ERC20 function transferFrom\n     * - Calling transferFrom on token fails for some reason (e.g. protocol is not approved to transfer)\n     * - Seller has less funds available than sellerDeposit for non preminted offers\n     * - Seller has less funds available than sellerDeposit and price for preminted offers\n     * - Received ERC20 token amount differs from the expected value\n     *\n     * @param _offerId - id of the offer with the details\n     * @param _buyerId - id of the buyer\n     * @param _price - the price, either price discovered externally or set on offer creation\n     * @param _isPreminted - flag indicating if the offer is preminted\n     * @param _priceType - price type, either static or discovery\n     */\n    function encumberFunds(\n        uint256 _offerId,\n        uint256 _buyerId,\n        uint256 _price,\n        bool _isPreminted,\n        BosonTypes.PriceType _priceType\n    ) internal {\n        // Load protocol entities storage\n        ProtocolLib.ProtocolEntities storage pe = ProtocolLib.protocolEntities();\n\n        // get message sender\n        address sender = EIP712Lib.msgSender();\n\n        // fetch offer to get the exchange token, price and seller\n        // this will be called only from commitToOffer so we expect that exchange actually exist\n        BosonTypes.Offer storage offer = pe.offers[_offerId];\n        address exchangeToken = offer.exchangeToken;\n\n        // if offer is non-preminted, validate incoming payment\n        if (!_isPreminted) {\n            validateIncomingPayment(exchangeToken, _price);\n            emit IBosonFundsLibEvents.FundsEncumbered(_buyerId, exchangeToken, _price, sender);\n        }\n\n        bool isPriceDiscovery = _priceType == BosonTypes.PriceType.Discovery;\n\n        // decrease available funds\n        uint256 sellerId = offer.sellerId;\n        uint256 sellerFundsEncumbered = offer.sellerDeposit + (_isPreminted && !isPriceDiscovery ? _price : 0); // for preminted offer and price type is static, encumber also price from seller's available funds\n        decreaseAvailableFunds(sellerId, exchangeToken, sellerFundsEncumbered);\n\n        // notify external observers\n        emit IBosonFundsLibEvents.FundsEncumbered(sellerId, exchangeToken, sellerFundsEncumbered, sender);\n    }\n\n    /**\n     * @notice Validates that incoming payments matches expectation. If token is a native currency, it makes sure\n     * msg.value is correct. If token is ERC20, it transfers the value from the sender to the protocol.\n     *\n     * Emits ERC20 Transfer event in call stack if successful.\n     *\n     * Reverts if:\n     * - Offer price is in native token and caller does not send enough\n     * - Offer price is in some ERC20 token and caller also sends native currency\n     * - Contract at token address does not support ERC20 function transferFrom\n     * - Calling transferFrom on token fails for some reason (e.g. protocol is not approved to transfer)\n     * - Received ERC20 token amount differs from the expected value\n     *\n     * @param _exchangeToken - address of the token (0x for native currency)\n     * @param _value - value expected to receive\n     */\n    function validateIncomingPayment(address _exchangeToken, uint256 _value) internal {\n        if (_exchangeToken == address(0)) {\n            // if transfer is in the native currency, msg.value must match offer price\n            if (msg.value != _value) revert BosonErrors.InsufficientValueReceived();\n        } else {\n            // when price is in an erc20 token, transferring the native currency is not allowed\n            if (msg.value != 0) revert BosonErrors.NativeNotAllowed();\n\n            // if transfer is in ERC20 token, try to transfer the amount from buyer to the protocol\n            transferFundsToProtocol(_exchangeToken, _value);\n        }\n    }\n\n    /**\n     * @notice Takes in the exchange id and releases the funds to buyer and seller, depending on the state of the exchange.\n     * It is called only from finalizeExchange and finalizeDispute.\n     *\n     * Emits FundsReleased and/or ProtocolFeeCollected event if payoffs are warranted and transaction is successful.\n     *\n     * @param _exchangeId - exchange id\n     */\n    function releaseFunds(uint256 _exchangeId) internal {\n        // Load protocol entities storage\n        ProtocolLib.ProtocolEntities storage pe = ProtocolLib.protocolEntities();\n\n        // Get the exchange and its state\n        // Since this should be called only from certain functions from exchangeHandler and disputeHandler\n        // exchange must exist and be in a completed state, so that's not checked explicitly\n        BosonTypes.Exchange storage exchange = pe.exchanges[_exchangeId];\n\n        // Get offer from storage to get the details about sellerDeposit, price, sellerId, exchangeToken and buyerCancelPenalty\n        BosonTypes.Offer storage offer = pe.offers[exchange.offerId];\n\n        // calculate the payoffs depending on state exchange is in\n        BosonTypes.Payoff memory payoff;\n\n        BosonTypes.OfferFees storage offerFee = pe.offerFees[exchange.offerId];\n        uint256 offerPrice = offer.price;\n        BosonTypes.ExchangeCosts[] storage exchangeCosts = pe.exchangeCosts[_exchangeId];\n        uint256 lastPrice = exchangeCosts.length == 0 ? offerPrice : exchangeCosts[exchangeCosts.length - 1].price;\n        {\n            // scope to avoid stack too deep errors\n            BosonTypes.ExchangeState exchangeState = exchange.state;\n            uint256 sellerDeposit = offer.sellerDeposit;\n\n            if (exchangeState == BosonTypes.ExchangeState.Completed) {\n                // COMPLETED\n                payoff.protocol = offerFee.protocolFee;\n                // buyerPayoff is 0\n                payoff.agent = offerFee.agentFee;\n                payoff.seller = offerPrice + sellerDeposit - payoff.protocol - payoff.agent;\n            } else if (exchangeState == BosonTypes.ExchangeState.Revoked) {\n                // REVOKED\n                // sellerPayoff is 0\n                payoff.buyer = lastPrice + sellerDeposit;\n            } else if (exchangeState == BosonTypes.ExchangeState.Canceled) {\n                // CANCELED\n                uint256 buyerCancelPenalty = offer.buyerCancelPenalty;\n                payoff.seller = sellerDeposit + buyerCancelPenalty;\n                payoff.buyer = lastPrice - buyerCancelPenalty;\n            } else if (exchangeState == BosonTypes.ExchangeState.Disputed) {\n                // DISPUTED\n                // determine if buyerEscalationDeposit was encumbered or not\n                // if dispute was escalated, disputeDates.escalated is populated\n                uint256 buyerEscalationDeposit = pe.disputeDates[_exchangeId].escalated > 0\n                    ? pe.disputeResolutionTerms[exchange.offerId].buyerEscalationDeposit\n                    : 0;\n\n                // get the information about the dispute, which must exist\n                BosonTypes.Dispute storage dispute = pe.disputes[_exchangeId];\n                BosonTypes.DisputeState disputeState = dispute.state;\n\n                if (disputeState == BosonTypes.DisputeState.Retracted) {\n                    // RETRACTED - same as \"COMPLETED\"\n                    payoff.protocol = offerFee.protocolFee;\n                    payoff.agent = offerFee.agentFee;\n                    // buyerPayoff is 0\n                    payoff.seller =\n                        offerPrice +\n                        sellerDeposit -\n                        payoff.protocol -\n                        payoff.agent +\n                        buyerEscalationDeposit;\n                } else if (disputeState == BosonTypes.DisputeState.Refused) {\n                    // REFUSED\n                    payoff.seller = sellerDeposit;\n                    payoff.buyer = lastPrice + buyerEscalationDeposit;\n                } else {\n                    // RESOLVED or DECIDED\n                    uint256 commonPot = sellerDeposit + buyerEscalationDeposit;\n                    payoff.buyer = applyPercent(commonPot, dispute.buyerPercent);\n                    payoff.seller = commonPot - payoff.buyer;\n\n                    payoff.buyer = payoff.buyer + applyPercent(lastPrice, dispute.buyerPercent);\n                    payoff.seller = payoff.seller + offerPrice - applyPercent(offerPrice, dispute.buyerPercent);\n                }\n            }\n        }\n\n        address exchangeToken = offer.exchangeToken;\n\n        // Original seller and last buyer are done\n        // Release funds to intermediate sellers (if they exist)\n        // and add the protocol fee to the total\n        {\n            (uint256 sequentialProtocolFee, uint256 sequentialRoyalties) = releaseFundsToIntermediateSellers(\n                _exchangeId,\n                exchange.state,\n                offerPrice,\n                exchangeToken,\n                offer\n            );\n            payoff.seller += sequentialRoyalties;\n            payoff.protocol += sequentialProtocolFee;\n        }\n\n        // Store payoffs to availablefunds and notify the external observers\n        address sender = EIP712Lib.msgSender();\n        if (payoff.seller > 0) {\n            increaseAvailableFundsAndEmitEvent(_exchangeId, offer.sellerId, exchangeToken, payoff.seller, sender);\n        }\n        if (payoff.buyer > 0) {\n            increaseAvailableFundsAndEmitEvent(_exchangeId, exchange.buyerId, exchangeToken, payoff.buyer, sender);\n        }\n\n        if (payoff.protocol > 0) {\n            increaseAvailableFunds(0, exchangeToken, payoff.protocol);\n            emit IBosonFundsLibEvents.ProtocolFeeCollected(_exchangeId, exchangeToken, payoff.protocol, sender);\n        }\n        if (payoff.agent > 0) {\n            // Get the agent for offer\n            uint256 agentId = ProtocolLib.protocolLookups().agentIdByOffer[exchange.offerId];\n            increaseAvailableFundsAndEmitEvent(_exchangeId, agentId, exchangeToken, payoff.agent, sender);\n        }\n    }\n\n    /**\n     * @notice Takes the exchange id and releases the funds to original seller if offer.priceType is Discovery\n     * and to all intermediate resellers in case of sequential commit, depending on the state of the exchange.\n     * It is called only from releaseFunds. Protocol fee and royalties are calculated and returned to releaseFunds, where they are added to the total.\n     *\n     * Emits FundsReleased events for non zero payoffs.\n     *\n     * @param _exchangeId - exchange id\n     * @param _exchangeState - state of the exchange\n     * @param _initialPrice - initial price of the offer\n     * @param _exchangeToken - address of the token used for the exchange\n     * @param _offer - offer struct\n     * @return protocolFee - protocol fee from secondary sales\n     * @return sellerRoyalties - royalties from secondary sales collected for the seller\n     */\n    function releaseFundsToIntermediateSellers(\n        uint256 _exchangeId,\n        BosonTypes.ExchangeState _exchangeState,\n        uint256 _initialPrice,\n        address _exchangeToken,\n        BosonTypes.Offer storage _offer\n    ) internal returns (uint256 protocolFee, uint256 sellerRoyalties) {\n        BosonTypes.ExchangeCosts[] storage exchangeCosts;\n\n        // calculate effective price multiplier\n        uint256 effectivePriceMultiplier;\n        {\n            ProtocolLib.ProtocolEntities storage pe = ProtocolLib.protocolEntities();\n\n            exchangeCosts = pe.exchangeCosts[_exchangeId];\n\n            // if price type was static and no sequential commit happened, just return\n            if (exchangeCosts.length == 0) {\n                return (0, 0);\n            }\n\n            {\n                if (_exchangeState == BosonTypes.ExchangeState.Completed) {\n                    // COMPLETED, buyer pays full price\n                    effectivePriceMultiplier = HUNDRED_PERCENT;\n                } else if (\n                    _exchangeState == BosonTypes.ExchangeState.Revoked ||\n                    _exchangeState == BosonTypes.ExchangeState.Canceled\n                ) {\n                    // REVOKED or CANCELED, buyer pays nothing (buyerCancelPenalty is not considered payment)\n                    effectivePriceMultiplier = 0;\n                } else if (_exchangeState == BosonTypes.ExchangeState.Disputed) {\n                    // DISPUTED\n                    // get the information about the dispute, which must exist\n                    BosonTypes.Dispute storage dispute = pe.disputes[_exchangeId];\n                    BosonTypes.DisputeState disputeState = dispute.state;\n\n                    if (disputeState == BosonTypes.DisputeState.Retracted) {\n                        // RETRACTED - same as \"COMPLETED\"\n                        effectivePriceMultiplier = HUNDRED_PERCENT;\n                    } else if (disputeState == BosonTypes.DisputeState.Refused) {\n                        // REFUSED, buyer pays nothing\n                        effectivePriceMultiplier = 0;\n                    } else {\n                        // RESOLVED or DECIDED\n                        effectivePriceMultiplier = HUNDRED_PERCENT - dispute.buyerPercent;\n                    }\n                }\n            }\n        }\n\n        uint256 resellerBuyPrice = _initialPrice; // the price that reseller paid for the voucher\n        address msgSender = EIP712Lib.msgSender();\n        uint256 len = exchangeCosts.length;\n        for (uint256 i = 0; i < len; ) {\n            // Since all elements of exchangeCosts[i] are used it makes sense to copy them to memory\n            BosonTypes.ExchangeCosts memory secondaryCommit = exchangeCosts[i];\n\n            // amount to be released\n            uint256 currentResellerAmount;\n\n            // inside the scope to avoid stack too deep error\n            {\n                if (effectivePriceMultiplier > 0) {\n                    protocolFee =\n                        protocolFee +\n                        applyPercent(secondaryCommit.protocolFeeAmount, effectivePriceMultiplier);\n                    sellerRoyalties += distributeRoyalties(\n                        _exchangeId,\n                        _offer,\n                        secondaryCommit,\n                        effectivePriceMultiplier\n                    );\n                }\n\n                // secondary price without protocol fee and royalties\n                uint256 reducedSecondaryPrice = secondaryCommit.price -\n                    secondaryCommit.protocolFeeAmount -\n                    secondaryCommit.royaltyAmount;\n\n                // Calculate amount to be released to the reseller:\n                // + part of the price that they paid (relevant for unhappy paths)\n                // + price of the voucher that they sold reduced for part that goes to next reseller, royalties and protocol fee\n                // - immediate payout that was released already during the sequential commit\n                currentResellerAmount =\n                    applyPercent(resellerBuyPrice, (HUNDRED_PERCENT - effectivePriceMultiplier)) +\n                    secondaryCommit.price -\n                    applyPercent(secondaryCommit.price, (HUNDRED_PERCENT - effectivePriceMultiplier)) -\n                    applyPercent(secondaryCommit.protocolFeeAmount, effectivePriceMultiplier) -\n                    applyPercent(secondaryCommit.royaltyAmount, effectivePriceMultiplier) -\n                    Math.min(resellerBuyPrice, reducedSecondaryPrice);\n\n                resellerBuyPrice = secondaryCommit.price;\n            }\n\n            if (currentResellerAmount > 0) {\n                increaseAvailableFundsAndEmitEvent(\n                    _exchangeId,\n                    secondaryCommit.resellerId,\n                    _exchangeToken,\n                    currentResellerAmount,\n                    msgSender\n                );\n            }\n\n            unchecked {\n                i++;\n            }\n        }\n    }\n\n    /**\n     * @notice Forwards values to increaseAvailableFunds and emits notifies external listeners.\n     *\n     * Emits FundsReleased events\n     *\n     * @param _exchangeId - exchange id\n     * @param _entityId - id of the entity to which the funds are released\n     * @param _tokenAddress - address of the token used for the exchange\n     * @param _amount - amount of tokens to be released\n     * @param _sender - address of the sender that executed the transaction\n     */\n    function increaseAvailableFundsAndEmitEvent(\n        uint256 _exchangeId,\n        uint256 _entityId,\n        address _tokenAddress,\n        uint256 _amount,\n        address _sender\n    ) internal {\n        increaseAvailableFunds(_entityId, _tokenAddress, _amount);\n        emit IBosonFundsLibEvents.FundsReleased(_exchangeId, _entityId, _tokenAddress, _amount, _sender);\n    }\n\n    /**\n     * @notice Tries to transfer tokens from the caller to the protocol.\n     *\n     * Emits ERC20 Transfer event in call stack if successful.\n     *\n     * Reverts if:\n     * - Contract at token address does not support ERC20 function transferFrom\n     * - Calling transferFrom on token fails for some reason (e.g. protocol is not approved to transfer)\n     * - Received ERC20 token amount differs from the expected value\n     *\n     * @param _tokenAddress - address of the token to be transferred\n     * @param _from - address to transfer funds from\n     * @param _amount - amount to be transferred\n     */\n    function transferFundsToProtocol(address _tokenAddress, address _from, uint256 _amount) internal {\n        if (_amount > 0) {\n            // protocol balance before the transfer\n            uint256 protocolTokenBalanceBefore = IERC20(_tokenAddress).balanceOf(address(this));\n\n            // transfer ERC20 tokens from the caller\n            IERC20(_tokenAddress).safeTransferFrom(_from, address(this), _amount);\n\n            // protocol balance after the transfer\n            uint256 protocolTokenBalanceAfter = IERC20(_tokenAddress).balanceOf(address(this));\n\n            // make sure that expected amount of tokens was transferred\n            if (protocolTokenBalanceAfter - protocolTokenBalanceBefore != _amount)\n                revert BosonErrors.InsufficientValueReceived();\n        }\n    }\n\n    /**\n     * @notice Same as transferFundsToProtocol(address _tokenAddress, address _from, uint256 _amount),\n     * but _from is message sender\n     *\n     * @param _tokenAddress - address of the token to be transferred\n     * @param _amount - amount to be transferred\n     */\n    function transferFundsToProtocol(address _tokenAddress, uint256 _amount) internal {\n        transferFundsToProtocol(_tokenAddress, EIP712Lib.msgSender(), _amount);\n    }\n\n    /**\n     * @notice Tries to transfer native currency or tokens from the protocol to the recipient.\n     *\n     * Emits FundsWithdrawn event if successful.\n     * Emits ERC20 Transfer event in call stack if ERC20 token is withdrawn and transfer is successful.\n     *\n     * Reverts if:\n     * - Transfer of native currency is not successful (i.e. recipient is a contract which reverted)\n     * - Contract at token address does not support ERC20 function transfer\n     * - Available funds is less than amount to be decreased\n     *\n     * @param _entityId - id of entity for which funds should be decreased, or 0 for protocol\n     * @param _tokenAddress - address of the token to be transferred\n     * @param _to - address of the recipient\n     * @param _amount - amount to be transferred\n     */\n    function transferFundsFromProtocol(\n        uint256 _entityId,\n        address _tokenAddress,\n        address payable _to,\n        uint256 _amount\n    ) internal {\n        // first decrease the amount to prevent the reentrancy attack\n        decreaseAvailableFunds(_entityId, _tokenAddress, _amount);\n\n        // try to transfer the funds\n        transferFundsFromProtocol(_tokenAddress, _to, _amount);\n\n        // notify the external observers\n        emit IBosonFundsLibEvents.FundsWithdrawn(_entityId, _to, _tokenAddress, _amount, EIP712Lib.msgSender());\n    }\n\n    /**\n     * @notice Tries to transfer native currency or tokens from the protocol to the recipient.\n     *\n     * Emits ERC20 Transfer event in call stack if ERC20 token is withdrawn and transfer is successful.\n     *\n     * Reverts if:\n     * - Transfer of native currency is not successful (i.e. recipient is a contract which reverted)\n     * - Contract at token address does not support ERC20 function transfer\n     * - Available funds is less than amount to be decreased\n     *\n     * @param _tokenAddress - address of the token to be transferred\n     * @param _to - address of the recipient\n     * @param _amount - amount to be transferred\n     */\n    function transferFundsFromProtocol(address _tokenAddress, address payable _to, uint256 _amount) internal {\n        // try to transfer the funds\n        if (_tokenAddress == address(0)) {\n            // transfer native currency\n            (bool success, ) = _to.call{ value: _amount }(\"\");\n            if (!success) revert BosonErrors.TokenTransferFailed();\n        } else {\n            // transfer ERC20 tokens\n            IERC20(_tokenAddress).safeTransfer(_to, _amount);\n        }\n    }\n\n    /**\n     * @notice Increases the amount, available to withdraw or use as a seller deposit.\n     *\n     * @param _entityId - id of entity for which funds should be increased, or 0 for protocol\n     * @param _tokenAddress - funds contract address or zero address for native currency\n     * @param _amount - amount to be credited\n     */\n    function increaseAvailableFunds(uint256 _entityId, address _tokenAddress, uint256 _amount) internal {\n        ProtocolLib.ProtocolLookups storage pl = ProtocolLib.protocolLookups();\n\n        // if the current amount of token is 0, the token address must be added to the token list\n        mapping(address => uint256) storage availableFunds = pl.availableFunds[_entityId];\n        if (availableFunds[_tokenAddress] == 0) {\n            address[] storage tokenList = pl.tokenList[_entityId];\n            tokenList.push(_tokenAddress);\n            //Set index mapping. Should be index in tokenList array + 1\n            pl.tokenIndexByAccount[_entityId][_tokenAddress] = tokenList.length;\n        }\n\n        // update the available funds\n        availableFunds[_tokenAddress] += _amount;\n    }\n\n    /**\n     * @notice Decreases the amount available to withdraw or use as a seller deposit.\n     *\n     * Reverts if:\n     * - Available funds is less than amount to be decreased\n     *\n     * @param _entityId - id of entity for which funds should be decreased, or 0 for protocol\n     * @param _tokenAddress - funds contract address or zero address for native currency\n     * @param _amount - amount to be taken away\n     */\n    function decreaseAvailableFunds(uint256 _entityId, address _tokenAddress, uint256 _amount) internal {\n        if (_amount > 0) {\n            ProtocolLib.ProtocolLookups storage pl = ProtocolLib.protocolLookups();\n\n            // get available funds from storage\n            mapping(address => uint256) storage availableFunds = pl.availableFunds[_entityId];\n            uint256 entityFunds = availableFunds[_tokenAddress];\n\n            // make sure that seller has enough funds in the pool and reduce the available funds\n            if (entityFunds < _amount) revert BosonErrors.InsufficientAvailableFunds();\n\n            // Use unchecked to optimize execution cost. The math is safe because of the require above.\n            unchecked {\n                availableFunds[_tokenAddress] = entityFunds - _amount;\n            }\n\n            // if available funds are totally emptied, the token address is removed from the seller's tokenList\n            if (entityFunds == _amount) {\n                // Get the index in the tokenList array, which is 1 less than the tokenIndexByAccount index\n                address[] storage tokenList = pl.tokenList[_entityId];\n                uint256 lastTokenIndex = tokenList.length - 1;\n                mapping(address => uint256) storage entityTokens = pl.tokenIndexByAccount[_entityId];\n                uint256 index = entityTokens[_tokenAddress] - 1;\n\n                // if target is last index then only pop and delete are needed\n                // otherwise, we overwrite the target with the last token first\n                if (index != lastTokenIndex) {\n                    // Need to fill gap caused by delete if more than one element in storage array\n                    address tokenToMove = tokenList[lastTokenIndex];\n                    // Copy the last token in the array to this index to fill the gap\n                    tokenList[index] = tokenToMove;\n                    // Reset index mapping. Should be index in tokenList array + 1\n                    entityTokens[tokenToMove] = index + 1;\n                }\n                // Delete last token address in the array, which was just moved to fill the gap\n                tokenList.pop();\n                // Delete from index mapping\n                delete entityTokens[_tokenAddress];\n            }\n        }\n    }\n\n    /**\n     * @notice Distributes the royalties to external recipients and seller's treasury.\n     *\n     * @param _offer - storage pointer to the offer\n     * @param _secondaryCommit - information about the secondary commit (royaltyInfoIndex, price, escrowedRoyaltyAmount)\n     * @param _effectivePriceMultiplier - multiplier for the price, depending on the state of the exchange\n     */\n    function distributeRoyalties(\n        uint256 _exchangeId,\n        BosonTypes.Offer storage _offer,\n        BosonTypes.ExchangeCosts memory _secondaryCommit,\n        uint256 _effectivePriceMultiplier\n    ) internal returns (uint256 sellerRoyalties) {\n        address sender = EIP712Lib.msgSender();\n        address exchangeToken = _offer.exchangeToken;\n        BosonTypes.RoyaltyInfo storage _royaltyInfo = _offer.royaltyInfo[_secondaryCommit.royaltyInfoIndex];\n        uint256 len = _royaltyInfo.recipients.length;\n        uint256 totalAmount;\n        uint256 effectivePrice = applyPercent(_secondaryCommit.price, _effectivePriceMultiplier);\n        ProtocolLib.ProtocolLookups storage pl = ProtocolLib.protocolLookups();\n        for (uint256 i = 0; i < len; ) {\n            address payable recipient = _royaltyInfo.recipients[i];\n            uint256 amount = applyPercent(_royaltyInfo.bps[i], effectivePrice);\n            totalAmount += amount;\n            if (recipient == address(0)) {\n                // goes to seller's treasury\n                sellerRoyalties += amount;\n            } else {\n                // Make funds available to withdraw\n                if (amount > 0) {\n                    increaseAvailableFundsAndEmitEvent(\n                        _exchangeId,\n                        pl.royaltyRecipientIdByWallet[recipient],\n                        exchangeToken,\n                        amount,\n                        sender\n                    );\n                }\n            }\n\n            unchecked {\n                i++;\n            }\n        }\n\n        // if there is a remainder due to rounding, it goes to the seller's treasury\n        sellerRoyalties =\n            sellerRoyalties +\n            applyPercent(_secondaryCommit.royaltyAmount, _effectivePriceMultiplier) -\n            totalAmount;\n    }\n\n    /**\n     * @notice Calulates the percentage of the amount.\n     *\n     * @param _amount - amount to be used for the calculation\n     * @param _percent - percentage to be calculated, in basis points (1% = 100, 100% = 10000)\n     */\n    function applyPercent(uint256 _amount, uint256 _percent) internal pure returns (uint256) {\n        if (_percent == HUNDRED_PERCENT) return _amount;\n        if (_percent == 0) return 0;\n\n        return (_amount * _percent) / HUNDRED_PERCENT;\n    }\n}\n"
      },
      "contracts/protocol/libs/ProtocolLib.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.22;\n\nimport { BosonTypes } from \"../../domain/BosonTypes.sol\";\n\n/**\n * @title ProtocolLib\n *\n * @notice Provides access to the protocol addresses, limits, entities, fees, counters, initializers and  metaTransactions slots for Facets.\n */\nlibrary ProtocolLib {\n    bytes32 internal constant PROTOCOL_ADDRESSES_POSITION = keccak256(\"boson.protocol.addresses\");\n    bytes32 internal constant PROTOCOL_LIMITS_POSITION = keccak256(\"boson.protocol.limits\");\n    bytes32 internal constant PROTOCOL_ENTITIES_POSITION = keccak256(\"boson.protocol.entities\");\n    bytes32 internal constant PROTOCOL_LOOKUPS_POSITION = keccak256(\"boson.protocol.lookups\");\n    bytes32 internal constant PROTOCOL_FEES_POSITION = keccak256(\"boson.protocol.fees\");\n    bytes32 internal constant PROTOCOL_COUNTERS_POSITION = keccak256(\"boson.protocol.counters\");\n    bytes32 internal constant PROTOCOL_STATUS_POSITION = keccak256(\"boson.protocol.initializers\");\n    bytes32 internal constant PROTOCOL_META_TX_POSITION = keccak256(\"boson.protocol.metaTransactions\");\n\n    // Protocol addresses storage\n    struct ProtocolAddresses {\n        // Address of the Boson Protocol treasury\n        address payable treasury;\n        // Address of the Boson Token (ERC-20 contract)\n        address payable token;\n        // Address of the Boson Protocol Voucher beacon\n        address voucherBeacon;\n        // Address of the Boson Beacon proxy implementation\n        address beaconProxy;\n        // Address of the Boson Price Discovery\n        address priceDiscovery;\n    }\n\n    // Protocol limits storage\n    struct ProtocolLimits {\n        // limit on the resolution period that a seller can specify\n        uint256 maxResolutionPeriod;\n        // limit on the escalation response period that a dispute resolver can specify\n        uint256 maxEscalationResponsePeriod;\n        // lower limit for dispute period\n        uint256 minDisputePeriod;\n        // limit how many exchanges can be processed in single batch transaction\n        uint16 maxExchangesPerBatch;\n        // limit how many offers can be added to the group\n        uint16 maxOffersPerGroup;\n        // limit how many offers can be added to the bundle\n        uint16 maxOffersPerBundle;\n        // limit how many twins can be added to the bundle\n        uint16 maxTwinsPerBundle;\n        // limit how many offers can be processed in single batch transaction\n        uint16 maxOffersPerBatch;\n        // limit how many different tokens can be withdrawn in a single transaction\n        uint16 maxTokensPerWithdrawal;\n        // limit how many dispute resolver fee structs can be processed in a single transaction\n        uint16 maxFeesPerDisputeResolver;\n        // limit how many disputes can be processed in single batch transaction\n        uint16 maxDisputesPerBatch;\n        // limit how many sellers can be added to or removed from an allow list in a single transaction\n        uint16 maxAllowedSellers;\n        // limit the sum of (protocol fee percentage + agent fee percentage) of an offer fee\n        uint16 maxTotalOfferFeePercentage;\n        // limit the max royalty percentage that can be set by the seller\n        uint16 maxRoyaltyPercentage;\n        // limit the max number of vouchers that can be preminted in a single transaction\n        uint256 maxPremintedVouchers;\n        // lower limit for resolution period\n        uint256 minResolutionPeriod;\n    }\n\n    // Protocol fees storage\n    struct ProtocolFees {\n        // Percentage that will be taken as a fee from the net of a Boson Protocol exchange\n        uint256 percentage; // 1.75% = 175, 100% = 10000\n        // Flat fee taken for exchanges in $BOSON\n        uint256 flatBoson;\n        // buyer escalation deposit percentage\n        uint256 buyerEscalationDepositPercentage;\n    }\n\n    // Protocol entities storage\n    struct ProtocolEntities {\n        // offer id => offer\n        mapping(uint256 => BosonTypes.Offer) offers;\n        // offer id => offer dates\n        mapping(uint256 => BosonTypes.OfferDates) offerDates;\n        // offer id => offer fees\n        mapping(uint256 => BosonTypes.OfferFees) offerFees;\n        // offer id => offer durations\n        mapping(uint256 => BosonTypes.OfferDurations) offerDurations;\n        // offer id => dispute resolution terms\n        mapping(uint256 => BosonTypes.DisputeResolutionTerms) disputeResolutionTerms;\n        // exchange id => exchange\n        mapping(uint256 => BosonTypes.Exchange) exchanges;\n        // exchange id => voucher\n        mapping(uint256 => BosonTypes.Voucher) vouchers;\n        // exchange id => dispute\n        mapping(uint256 => BosonTypes.Dispute) disputes;\n        // exchange id => dispute dates\n        mapping(uint256 => BosonTypes.DisputeDates) disputeDates;\n        // seller id => seller\n        mapping(uint256 => BosonTypes.Seller) sellers;\n        // buyer id => buyer\n        mapping(uint256 => BosonTypes.Buyer) buyers;\n        // dispute resolver id => dispute resolver\n        mapping(uint256 => BosonTypes.DisputeResolver) disputeResolvers;\n        // dispute resolver id => dispute resolver fee array\n        mapping(uint256 => BosonTypes.DisputeResolverFee[]) disputeResolverFees;\n        // agent id => agent\n        mapping(uint256 => BosonTypes.Agent) agents;\n        // group id => group\n        mapping(uint256 => BosonTypes.Group) groups;\n        // group id => condition\n        mapping(uint256 => BosonTypes.Condition) conditions;\n        // bundle id => bundle\n        mapping(uint256 => BosonTypes.Bundle) bundles;\n        // twin id => twin\n        mapping(uint256 => BosonTypes.Twin) twins;\n        // entity id => auth token\n        mapping(uint256 => BosonTypes.AuthToken) authTokens;\n        // exchange id => sequential commit info\n        mapping(uint256 => BosonTypes.ExchangeCosts[]) exchangeCosts;\n        // entity id => royalty recipient account\n        mapping(uint256 => BosonTypes.RoyaltyRecipient) royaltyRecipients;\n    }\n\n    // Protocol lookups storage\n    struct ProtocolLookups {\n        // offer id => exchange ids\n        mapping(uint256 => uint256[]) exchangeIdsByOffer;\n        // offer id => bundle id\n        mapping(uint256 => uint256) bundleIdByOffer;\n        // twin id => bundle id\n        mapping(uint256 => uint256) bundleIdByTwin;\n        // offer id => group id\n        mapping(uint256 => uint256) groupIdByOffer;\n        // offer id => agent id\n        mapping(uint256 => uint256) agentIdByOffer;\n        // seller assistant address => sellerId\n        mapping(address => uint256) sellerIdByAssistant;\n        // seller admin address => sellerId\n        mapping(address => uint256) sellerIdByAdmin;\n        // seller clerk address => sellerId\n        // @deprecated sellerIdByClerk is no longer used. Keeping it for backwards compatibility.\n        mapping(address => uint256) sellerIdByClerk;\n        // buyer wallet address => buyerId\n        mapping(address => uint256) buyerIdByWallet;\n        // dispute resolver assistant address => disputeResolverId\n        mapping(address => uint256) disputeResolverIdByAssistant;\n        // dispute resolver admin address => disputeResolverId\n        mapping(address => uint256) disputeResolverIdByAdmin;\n        // dispute resolver clerk address => disputeResolverId\n        // @deprecated disputeResolverIdByClerk is no longer used. Keeping it for backwards compatibility.\n        mapping(address => uint256) disputeResolverIdByClerk;\n        // dispute resolver id to fee token address => index of the token address\n        mapping(uint256 => mapping(address => uint256)) disputeResolverFeeTokenIndex;\n        // agent wallet address => agentId\n        mapping(address => uint256) agentIdByWallet;\n        // account id => token address => amount\n        mapping(uint256 => mapping(address => uint256)) availableFunds;\n        // account id => all tokens with balance > 0\n        mapping(uint256 => address[]) tokenList;\n        // account id => token address => index on token addresses list\n        mapping(uint256 => mapping(address => uint256)) tokenIndexByAccount;\n        // seller id => cloneAddress\n        mapping(uint256 => address) cloneAddress;\n        // buyer id => number of active vouchers\n        mapping(uint256 => uint256) voucherCount;\n        // buyer address => groupId => commit count (addresses that have committed to conditional offers)\n        mapping(address => mapping(uint256 => uint256)) conditionalCommitsByAddress;\n        // AuthTokenType => Auth NFT contract address.\n        mapping(BosonTypes.AuthTokenType => address) authTokenContracts;\n        // AuthTokenType => tokenId => sellerId\n        mapping(BosonTypes.AuthTokenType => mapping(uint256 => uint256)) sellerIdByAuthToken;\n        // seller id => token address (only ERC721) => start and end of token ids range\n        mapping(uint256 => mapping(address => BosonTypes.TokenRange[])) twinRangesBySeller;\n        // seller id => token address (only ERC721) => twin ids\n        // @deprecated twinIdsByTokenAddressAndBySeller is no longer used. Keeping it for backwards compatibility.\n        mapping(uint256 => mapping(address => uint256[])) twinIdsByTokenAddressAndBySeller;\n        // exchange id => BosonTypes.TwinReceipt\n        mapping(uint256 => BosonTypes.TwinReceipt[]) twinReceiptsByExchange;\n        // dispute resolver id => list of allowed sellers\n        mapping(uint256 => uint256[]) allowedSellers;\n        // dispute resolver id => seller id => index of allowed seller in allowedSellers\n        mapping(uint256 => mapping(uint256 => uint256)) allowedSellerIndex;\n        // exchange id => condition\n        mapping(uint256 => BosonTypes.Condition) exchangeCondition;\n        // groupId => offerId => index on Group.offerIds array\n        mapping(uint256 => mapping(uint256 => uint256)) offerIdIndexByGroup;\n        // seller id => Seller\n        mapping(uint256 => BosonTypes.Seller) pendingAddressUpdatesBySeller;\n        // seller id => AuthToken\n        mapping(uint256 => BosonTypes.AuthToken) pendingAuthTokenUpdatesBySeller;\n        // dispute resolver id => DisputeResolver\n        mapping(uint256 => BosonTypes.DisputeResolver) pendingAddressUpdatesByDisputeResolver;\n        // twin id => range id\n        mapping(uint256 => uint256) rangeIdByTwin;\n        // tokenId => groupId =>  commit count (count how many times a token has been used as gate for this group)\n        mapping(uint256 => mapping(uint256 => uint256)) conditionalCommitsByTokenId;\n        // seller id => collections\n        mapping(uint256 => BosonTypes.Collection[]) additionalCollections;\n        // seller id => seller salt used to create collections\n        mapping(uint256 => bytes32) sellerSalt;\n        // seller salt => is used\n        mapping(bytes32 => bool) isUsedSellerSalt;\n        // seller id => royalty recipients info\n        mapping(uint256 => BosonTypes.RoyaltyRecipientInfo[]) royaltyRecipientsBySeller;\n        // seller id => royalty recipient => index of royalty recipient in royaltyRecipientsBySeller\n        mapping(uint256 => mapping(address => uint256)) royaltyRecipientIndexBySellerAndRecipient;\n        // royalty recipient wallet address => agentId\n        mapping(address => uint256) royaltyRecipientIdByWallet;\n    }\n\n    // Incrementing id counters\n    struct ProtocolCounters {\n        // Next account id\n        uint256 nextAccountId;\n        // Next offer id\n        uint256 nextOfferId;\n        // Next exchange id\n        uint256 nextExchangeId;\n        // Next twin id\n        uint256 nextTwinId;\n        // Next group id\n        uint256 nextGroupId;\n        // Next twin id\n        uint256 nextBundleId;\n    }\n\n    // Storage related to Meta Transactions\n    struct ProtocolMetaTxInfo {\n        // The current sender address associated with the transaction\n        address currentSenderAddress;\n        // A flag that tells us whether the current transaction is a meta-transaction or a regular transaction.\n        bool isMetaTransaction;\n        // The domain Separator of the protocol\n        bytes32 domainSeparator;\n        // address => nonce => nonce used indicator\n        mapping(address => mapping(uint256 => bool)) usedNonce;\n        // The cached chain id\n        uint256 cachedChainId;\n        // map function name to input type\n        mapping(string => BosonTypes.MetaTxInputType) inputType;\n        // map input type => hash info\n        mapping(BosonTypes.MetaTxInputType => BosonTypes.HashInfo) hashInfo;\n        // Can function be executed using meta transactions\n        mapping(bytes32 => bool) isAllowlisted;\n    }\n\n    // Individual facet initialization states\n    struct ProtocolStatus {\n        // the current pause scenario, a sum of PausableRegions as powers of two\n        uint256 pauseScenario;\n        // reentrancy status\n        uint256 reentrancyStatus;\n        // interface id => initialized?\n        mapping(bytes4 => bool) initializedInterfaces;\n        // version => initialized?\n        mapping(bytes32 => bool) initializedVersions;\n        // Current protocol version\n        bytes32 version;\n        // Incoming voucher id\n        uint256 incomingVoucherId;\n        // Incoming voucher clone address\n        address incomingVoucherCloneAddress;\n    }\n\n    /**\n     * @dev Gets the protocol addresses slot\n     *\n     * @return pa - the protocol addresses slot\n     */\n    function protocolAddresses() internal pure returns (ProtocolAddresses storage pa) {\n        bytes32 position = PROTOCOL_ADDRESSES_POSITION;\n        assembly {\n            pa.slot := position\n        }\n    }\n\n    /**\n     * @notice Gets the protocol limits slot\n     *\n     * @return pl - the protocol limits slot\n     */\n    function protocolLimits() internal pure returns (ProtocolLimits storage pl) {\n        bytes32 position = PROTOCOL_LIMITS_POSITION;\n        assembly {\n            pl.slot := position\n        }\n    }\n\n    /**\n     * @notice Gets the protocol entities slot\n     *\n     * @return pe - the protocol entities slot\n     */\n    function protocolEntities() internal pure returns (ProtocolEntities storage pe) {\n        bytes32 position = PROTOCOL_ENTITIES_POSITION;\n        assembly {\n            pe.slot := position\n        }\n    }\n\n    /**\n     * @notice Gets the protocol lookups slot\n     *\n     * @return pl - the protocol lookups slot\n     */\n    function protocolLookups() internal pure returns (ProtocolLookups storage pl) {\n        bytes32 position = PROTOCOL_LOOKUPS_POSITION;\n        assembly {\n            pl.slot := position\n        }\n    }\n\n    /**\n     * @notice Gets the protocol fees slot\n     *\n     * @return pf - the protocol fees slot\n     */\n    function protocolFees() internal pure returns (ProtocolFees storage pf) {\n        bytes32 position = PROTOCOL_FEES_POSITION;\n        assembly {\n            pf.slot := position\n        }\n    }\n\n    /**\n     * @notice Gets the protocol counters slot\n     *\n     * @return pc - the protocol counters slot\n     */\n    function protocolCounters() internal pure returns (ProtocolCounters storage pc) {\n        bytes32 position = PROTOCOL_COUNTERS_POSITION;\n        assembly {\n            pc.slot := position\n        }\n    }\n\n    /**\n     * @notice Gets the protocol meta-transactions storage slot\n     *\n     * @return pmti - the protocol meta-transactions storage slot\n     */\n    function protocolMetaTxInfo() internal pure returns (ProtocolMetaTxInfo storage pmti) {\n        bytes32 position = PROTOCOL_META_TX_POSITION;\n        assembly {\n            pmti.slot := position\n        }\n    }\n\n    /**\n     * @notice Gets the protocol status slot\n     *\n     * @return ps - the the protocol status slot\n     */\n    function protocolStatus() internal pure returns (ProtocolStatus storage ps) {\n        bytes32 position = PROTOCOL_STATUS_POSITION;\n        assembly {\n            ps.slot := position\n        }\n    }\n}\n"
      }
    },
    "settings": {
      "viaIR": false,
      "optimizer": {
        "enabled": true,
        "runs": 200,
        "details": {
          "yul": true
        }
      },
      "evmVersion": "london",
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}