creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/conduit/lib/ConduitEnums.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nenum ConduitItemType {\n    NATIVE, // unused\n    ERC20,\n    ERC721,\n    ERC1155\n}\n"
      },
      "contracts/conduit/lib/ConduitStructs.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { ConduitItemType } from \"./ConduitEnums.sol\";\n\n/**\n * @dev A ConduitTransfer is a struct that contains the information needed for a\n *      conduit to transfer an item from one address to another.\n */\nstruct ConduitTransfer {\n    ConduitItemType itemType;\n    address token;\n    address from;\n    address to;\n    uint256 identifier;\n    uint256 amount;\n}\n\n/**\n * @dev A ConduitBatch1155Transfer is a struct that contains the information\n *      needed for a conduit to transfer a batch of ERC-1155 tokens from one\n *      address to another.\n */\nstruct ConduitBatch1155Transfer {\n    address token;\n    address from;\n    address to;\n    uint256[] ids;\n    uint256[] amounts;\n}\n"
      },
      "contracts/helpers/TransferHelper.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { IERC721Receiver } from \"../interfaces/IERC721Receiver.sol\";\n\nimport {\n    TransferHelperItem,\n    TransferHelperItemsWithRecipient\n} from \"./TransferHelperStructs.sol\";\n\nimport { ConduitItemType } from \"../conduit/lib/ConduitEnums.sol\";\n\nimport { ConduitInterface } from \"../interfaces/ConduitInterface.sol\";\n\nimport {\n    ConduitControllerInterface\n} from \"../interfaces/ConduitControllerInterface.sol\";\n\nimport { ConduitTransfer } from \"../conduit/lib/ConduitStructs.sol\";\n\nimport {\n    TransferHelperInterface\n} from \"../interfaces/TransferHelperInterface.sol\";\n\nimport { TransferHelperErrors } from \"../interfaces/TransferHelperErrors.sol\";\n\n/**\n * @title TransferHelper\n * @author 5thWeb\n * @notice TransferHelper is a utility contract for transferring\n *         ERC20/ERC721/ERC1155 items in bulk to specific recipients.\n */\ncontract TransferHelper is TransferHelperInterface, TransferHelperErrors {\n    // Allow for interaction with the conduit controller.\n    ConduitControllerInterface internal immutable _CONDUIT_CONTROLLER;\n\n    // Set conduit creation code and runtime code hashes as immutable arguments.\n    bytes32 internal immutable _CONDUIT_CREATION_CODE_HASH;\n    bytes32 internal immutable _CONDUIT_RUNTIME_CODE_HASH;\n\n    /**\n     * @dev Set the supplied conduit controller and retrieve its\n     *      conduit creation code hash.\n     *\n     *\n     * @param conduitController A contract that deploys conduits, or proxies\n     *                          that may optionally be used to transfer approved\n     *                          ERC20/721/1155 tokens.\n     */\n    constructor(address conduitController) {\n        // Get the conduit creation code and runtime code hashes from the\n        // supplied conduit controller and set them as an immutable.\n        ConduitControllerInterface controller = ConduitControllerInterface(\n            conduitController\n        );\n        (_CONDUIT_CREATION_CODE_HASH, _CONDUIT_RUNTIME_CODE_HASH) = controller\n            .getConduitCodeHashes();\n\n        // Set the supplied conduit controller as an immutable.\n        _CONDUIT_CONTROLLER = controller;\n    }\n\n    /**\n     * @notice Transfer multiple ERC20/ERC721/ERC1155 items to\n     *         specified recipients.\n     *\n     * @param items      The items to transfer to an intended recipient.\n     * @param conduitKey A mandatory conduit key referring to a conduit through\n     *                   which the bulk transfer should occur.\n     *\n     * @return magicValue A value indicating that the transfers were successful.\n     */\n    function bulkTransfer(\n        TransferHelperItemsWithRecipient[] calldata items,\n        bytes32 conduitKey\n    ) external override returns (bytes4 magicValue) {\n        // Ensure that a conduit key has been supplied.\n        if (conduitKey == bytes32(0)) {\n            revert InvalidConduit(conduitKey, address(0));\n        }\n\n        // Use conduit derived from supplied conduit key to perform transfers.\n        _performTransfersWithConduit(items, conduitKey);\n\n        // Return a magic value indicating that the transfers were performed.\n        magicValue = this.bulkTransfer.selector;\n    }\n\n    /**\n     * @notice Perform multiple transfers to specified recipients via the\n     *         conduit derived from the provided conduit key.\n     *\n     * @param transfers  The items to transfer.\n     * @param conduitKey The conduit key referring to the conduit through\n     *                   which the bulk transfer should occur.\n     */\n    function _performTransfersWithConduit(\n        TransferHelperItemsWithRecipient[] calldata transfers,\n        bytes32 conduitKey\n    ) internal {\n        // Retrieve total number of transfers and place on stack.\n        uint256 numTransfers = transfers.length;\n\n        // Derive the conduit address from the deployer, conduit key\n        // and creation code hash.\n        address conduit = address(\n            uint160(\n                uint256(\n                    keccak256(\n                        abi.encodePacked(\n                            bytes1(0xff),\n                            address(_CONDUIT_CONTROLLER),\n                            conduitKey,\n                            _CONDUIT_CREATION_CODE_HASH\n                        )\n                    )\n                )\n            )\n        );\n\n        // Declare a variable to store the sum of all items across transfers.\n        uint256 sumOfItemsAcrossAllTransfers;\n\n        // Skip overflow checks: all for loops are indexed starting at zero.\n        unchecked {\n            // Iterate over each transfer.\n            for (uint256 i = 0; i < numTransfers; ++i) {\n                // Retrieve the transfer in question.\n                TransferHelperItemsWithRecipient calldata transfer = transfers[\n                    i\n                ];\n\n                // Increment totalItems by the number of items in the transfer.\n                sumOfItemsAcrossAllTransfers += transfer.items.length;\n            }\n        }\n\n        // Declare a new array in memory with length totalItems to populate with\n        // each conduit transfer.\n        ConduitTransfer[] memory conduitTransfers = new ConduitTransfer[](\n            sumOfItemsAcrossAllTransfers\n        );\n\n        // Declare an index for storing ConduitTransfers in conduitTransfers.\n        uint256 itemIndex;\n\n        // Skip overflow checks: all for loops are indexed starting at zero.\n        unchecked {\n            // Iterate over each transfer.\n            for (uint256 i = 0; i < numTransfers; ++i) {\n                // Retrieve the transfer in question.\n                TransferHelperItemsWithRecipient calldata transfer = transfers[\n                    i\n                ];\n\n                // Retrieve the items of the transfer in question.\n                TransferHelperItem[] calldata transferItems = transfer.items;\n\n                // Ensure recipient is not the zero address.\n                _checkRecipientIsNotZeroAddress(transfer.recipient);\n\n                // Create a boolean indicating whether validateERC721Receiver\n                // is true and recipient is a contract.\n                bool callERC721Receiver = transfer.validateERC721Receiver &&\n                    transfer.recipient.code.length != 0;\n\n                // Retrieve the total number of items in the transfer and\n                // place on stack.\n                uint256 numItemsInTransfer = transferItems.length;\n\n                // Iterate over each item in the transfer to create a\n                // corresponding ConduitTransfer.\n                for (uint256 j = 0; j < numItemsInTransfer; ++j) {\n                    // Retrieve the item from the transfer.\n                    TransferHelperItem calldata item = transferItems[j];\n\n                    if (item.itemType == ConduitItemType.ERC20) {\n                        // Ensure that the identifier of an ERC20 token is 0.\n                        if (item.identifier != 0) {\n                            revert InvalidERC20Identifier();\n                        }\n                    }\n\n                    // If the item is an ERC721 token and\n                    // callERC721Receiver is true...\n                    if (item.itemType == ConduitItemType.ERC721) {\n                        if (callERC721Receiver) {\n                            // Check if the recipient implements\n                            // onERC721Received for the given tokenId.\n                            _checkERC721Receiver(\n                                conduit,\n                                transfer.recipient,\n                                item.identifier\n                            );\n                        }\n                    }\n\n                    // Create a ConduitTransfer corresponding to each\n                    // TransferHelperItem.\n                    conduitTransfers[itemIndex] = ConduitTransfer(\n                        item.itemType,\n                        item.token,\n                        msg.sender,\n                        transfer.recipient,\n                        item.identifier,\n                        item.amount\n                    );\n\n                    // Increment the index for storing ConduitTransfers.\n                    ++itemIndex;\n                }\n            }\n        }\n\n        // Attempt the external call to transfer tokens via the derived conduit.\n        try ConduitInterface(conduit).execute(conduitTransfers) returns (\n            bytes4 conduitMagicValue\n        ) {\n            // Check if the value returned from the external call matches\n            // the conduit `execute` selector.\n            if (conduitMagicValue != ConduitInterface.execute.selector) {\n                // If the external call fails, revert with the conduit key\n                // and conduit address.\n                revert InvalidConduit(conduitKey, conduit);\n            }\n        } catch Error(string memory reason) {\n            // Catch reverts with a provided reason string and\n            // revert with the reason, conduit key and conduit address.\n            revert ConduitErrorRevertString(reason, conduitKey, conduit);\n        } catch (bytes memory data) {\n            // Conduits will throw a custom error when attempting to transfer\n            // native token item types or an ERC721 item amount other than 1.\n            // Bubble up these custom errors when encountered. Note that the\n            // conduit itself will bubble up revert reasons from transfers as\n            // well, meaning that these errors are not necessarily indicative of\n            // an issue with the item type or amount in cases where the same\n            // custom error signature is encountered during a conduit transfer.\n\n            // Set initial value of first four bytes of revert data to the mask.\n            bytes4 customErrorSelector = bytes4(0xffffffff);\n\n            // Utilize assembly to read first four bytes (if present) directly.\n            assembly {\n                // Combine original mask with first four bytes of revert data.\n                customErrorSelector := and(\n                    mload(add(data, 0x20)), // Data begins after length offset.\n                    customErrorSelector\n                )\n            }\n\n            // Pass through the custom error in question if the revert data is\n            // the correct length and matches an expected custom error selector.\n            if (\n                data.length == 4 &&\n                customErrorSelector == InvalidItemType.selector\n            ) {\n                // \"Bubble up\" the revert reason.\n                assembly {\n                    revert(add(data, 0x20), 0x04)\n                }\n            } else if (\n                data.length == 36 &&\n                customErrorSelector == InvalidERC721TransferAmount.selector\n            ) {\n                // \"Bubble up\" the revert reason.\n                assembly {\n                    revert(add(data, 0x20), 0x24)\n                }\n            }\n\n            // Catch all other reverts from the external call to the conduit and\n            // include the conduit's raw revert reason as a data argument to a\n            // new custom error.\n            revert ConduitErrorRevertBytes(data, conduitKey, conduit);\n        }\n    }\n\n    /**\n     * @notice An internal function to check if a recipient address implements\n     *         onERC721Received for a given tokenId. Note that this check does\n     *         not adhere to the safe transfer specification and is only meant\n     *         to provide an additional layer of assurance that the recipient\n     *         can receive the tokens — any hooks or post-transfer checks will\n     *         fail and the caller will be the transfer helper rather than the\n     *         ERC721 contract. Note that the conduit is set as the operator, as\n     *         it will be the caller once the transfer is performed.\n     *\n     * @param conduit   The conduit to provide as the operator when calling\n     *                  onERC721Received.\n     * @param recipient The ERC721 recipient on which to call onERC721Received.\n     * @param tokenId   The ERC721 tokenId of the token being transferred.\n     */\n    function _checkERC721Receiver(\n        address conduit,\n        address recipient,\n        uint256 tokenId\n    ) internal {\n        // Check if recipient can receive ERC721 tokens.\n        try\n            IERC721Receiver(recipient).onERC721Received(\n                conduit,\n                msg.sender,\n                tokenId,\n                \"\"\n            )\n        returns (bytes4 selector) {\n            // Check if onERC721Received selector is valid.\n            if (selector != IERC721Receiver.onERC721Received.selector) {\n                // Revert if recipient cannot accept\n                // ERC721 tokens.\n                revert InvalidERC721Recipient(recipient);\n            }\n        } catch (bytes memory data) {\n            // \"Bubble up\" recipient's revert reason.\n            revert ERC721ReceiverErrorRevertBytes(\n                data,\n                recipient,\n                msg.sender,\n                tokenId\n            );\n        } catch Error(string memory reason) {\n            // \"Bubble up\" recipient's revert reason.\n            revert ERC721ReceiverErrorRevertString(\n                reason,\n                recipient,\n                msg.sender,\n                tokenId\n            );\n        }\n    }\n\n    /**\n     * @notice An internal function that reverts if the passed-in recipient\n     *         is the zero address.\n     *\n     * @param recipient The recipient on which to perform the check.\n     */\n    function _checkRecipientIsNotZeroAddress(address recipient) internal pure {\n        // Revert if the recipient is the zero address.\n        if (recipient == address(0x0)) {\n            revert RecipientCannotBeZeroAddress();\n        }\n    }\n}\n"
      },
      "contracts/helpers/TransferHelperStructs.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { ConduitItemType } from \"../conduit/lib/ConduitEnums.sol\";\n\n/**\n * @dev A TransferHelperItem specifies the itemType (ERC20/ERC721/ERC1155),\n *      token address, token identifier, and amount of the token to be\n *      transferred via the TransferHelper. For ERC20 tokens, identifier\n *      must be 0. For ERC721 tokens, amount must be 1.\n */\nstruct TransferHelperItem {\n    ConduitItemType itemType;\n    address token;\n    uint256 identifier;\n    uint256 amount;\n}\n\n/**\n * @dev A TransferHelperItemsWithRecipient specifies the tokens to transfer\n *      via the TransferHelper, their intended recipient, and a boolean flag\n *      indicating whether onERC721Received should be called on a recipient\n *      contract.\n */\nstruct TransferHelperItemsWithRecipient {\n    TransferHelperItem[] items;\n    address recipient;\n    bool validateERC721Receiver;\n}\n"
      },
      "contracts/interfaces/ConduitControllerInterface.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\n/**\n * @title ConduitControllerInterface\n * @author 5thWeb\n * @notice ConduitControllerInterface contains all external function interfaces,\n *         structs, events, and errors for the conduit controller.\n */\ninterface ConduitControllerInterface {\n    /**\n     * @dev Track the conduit key, current owner, new potential owner, and open\n     *      channels for each deployed conduit.\n     */\n    struct ConduitProperties {\n        bytes32 key;\n        address owner;\n        address potentialOwner;\n        address[] channels;\n        mapping(address => uint256) channelIndexesPlusOne;\n    }\n\n    /**\n     * @dev Emit an event whenever a new conduit is created.\n     *\n     * @param conduit    The newly created conduit.\n     * @param conduitKey The conduit key used to create the new conduit.\n     */\n    event NewConduit(address conduit, bytes32 conduitKey);\n\n    /**\n     * @dev Emit an event whenever conduit ownership is transferred.\n     *\n     * @param conduit       The conduit for which ownership has been\n     *                      transferred.\n     * @param previousOwner The previous owner of the conduit.\n     * @param newOwner      The new owner of the conduit.\n     */\n    event OwnershipTransferred(\n        address indexed conduit,\n        address indexed previousOwner,\n        address indexed newOwner\n    );\n\n    /**\n     * @dev Emit an event whenever a conduit owner registers a new potential\n     *      owner for that conduit.\n     *\n     * @param newPotentialOwner The new potential owner of the conduit.\n     */\n    event PotentialOwnerUpdated(address indexed newPotentialOwner);\n\n    /**\n     * @dev Revert with an error when attempting to create a new conduit using a\n     *      conduit key where the first twenty bytes of the key do not match the\n     *      address of the caller.\n     */\n    error InvalidCreator();\n\n    /**\n     * @dev Revert with an error when attempting to create a new conduit when no\n     *      initial owner address is supplied.\n     */\n    error InvalidInitialOwner();\n\n    /**\n     * @dev Revert with an error when attempting to set a new potential owner\n     *      that is already set.\n     */\n    error NewPotentialOwnerAlreadySet(\n        address conduit,\n        address newPotentialOwner\n    );\n\n    /**\n     * @dev Revert with an error when attempting to cancel ownership transfer\n     *      when no new potential owner is currently set.\n     */\n    error NoPotentialOwnerCurrentlySet(address conduit);\n\n    /**\n     * @dev Revert with an error when attempting to interact with a conduit that\n     *      does not yet exist.\n     */\n    error NoConduit();\n\n    /**\n     * @dev Revert with an error when attempting to create a conduit that\n     *      already exists.\n     */\n    error ConduitAlreadyExists(address conduit);\n\n    /**\n     * @dev Revert with an error when attempting to update channels or transfer\n     *      ownership of a conduit when the caller is not the owner of the\n     *      conduit in question.\n     */\n    error CallerIsNotOwner(address conduit);\n\n    /**\n     * @dev Revert with an error when attempting to register a new potential\n     *      owner and supplying the null address.\n     */\n    error NewPotentialOwnerIsZeroAddress(address conduit);\n\n    /**\n     * @dev Revert with an error when attempting to claim ownership of a conduit\n     *      with a caller that is not the current potential owner for the\n     *      conduit in question.\n     */\n    error CallerIsNotNewPotentialOwner(address conduit);\n\n    /**\n     * @dev Revert with an error when attempting to retrieve a channel using an\n     *      index that is out of range.\n     */\n    error ChannelOutOfRange(address conduit);\n\n    /**\n     * @notice Deploy a new conduit using a supplied conduit key and assigning\n     *         an initial owner for the deployed conduit. Note that the first\n     *         twenty bytes of the supplied conduit key must match the caller\n     *         and that a new conduit cannot be created if one has already been\n     *         deployed using the same conduit key.\n     *\n     * @param conduitKey   The conduit key used to deploy the conduit. Note that\n     *                     the first twenty bytes of the conduit key must match\n     *                     the caller of this contract.\n     * @param initialOwner The initial owner to set for the new conduit.\n     *\n     * @return conduit The address of the newly deployed conduit.\n     */\n    function createConduit(\n        bytes32 conduitKey,\n        address initialOwner\n    ) external returns (address conduit);\n\n    /**\n     * @notice Open or close a channel on a given conduit, thereby allowing the\n     *         specified account to execute transfers against that conduit.\n     *         Extreme care must be taken when updating channels, as malicious\n     *         or vulnerable channels can transfer any ERC20, ERC721 and ERC1155\n     *         tokens where the token holder has granted the conduit approval.\n     *         Only the owner of the conduit in question may call this function.\n     *\n     * @param conduit The conduit for which to open or close the channel.\n     * @param channel The channel to open or close on the conduit.\n     * @param isOpen  A boolean indicating whether to open or close the channel.\n     */\n    function updateChannel(\n        address conduit,\n        address channel,\n        bool isOpen\n    ) external;\n\n    /**\n     * @notice Initiate conduit ownership transfer by assigning a new potential\n     *         owner for the given conduit. Once set, the new potential owner\n     *         may call `acceptOwnership` to claim ownership of the conduit.\n     *         Only the owner of the conduit in question may call this function.\n     *\n     * @param conduit The conduit for which to initiate ownership transfer.\n     * @param newPotentialOwner The new potential owner of the conduit.\n     */\n    function transferOwnership(\n        address conduit,\n        address newPotentialOwner\n    ) external;\n\n    /**\n     * @notice Clear the currently set potential owner, if any, from a conduit.\n     *         Only the owner of the conduit in question may call this function.\n     *\n     * @param conduit The conduit for which to cancel ownership transfer.\n     */\n    function cancelOwnershipTransfer(address conduit) external;\n\n    /**\n     * @notice Accept ownership of a supplied conduit. Only accounts that the\n     *         current owner has set as the new potential owner may call this\n     *         function.\n     *\n     * @param conduit The conduit for which to accept ownership.\n     */\n    function acceptOwnership(address conduit) external;\n\n    /**\n     * @notice Retrieve the current owner of a deployed conduit.\n     *\n     * @param conduit The conduit for which to retrieve the associated owner.\n     *\n     * @return owner The owner of the supplied conduit.\n     */\n    function ownerOf(address conduit) external view returns (address owner);\n\n    /**\n     * @notice Retrieve the conduit key for a deployed conduit via reverse\n     *         lookup.\n     *\n     * @param conduit The conduit for which to retrieve the associated conduit\n     *                key.\n     *\n     * @return conduitKey The conduit key used to deploy the supplied conduit.\n     */\n    function getKey(address conduit) external view returns (bytes32 conduitKey);\n\n    /**\n     * @notice Derive the conduit associated with a given conduit key and\n     *         determine whether that conduit exists (i.e. whether it has been\n     *         deployed).\n     *\n     * @param conduitKey The conduit key used to derive the conduit.\n     *\n     * @return conduit The derived address of the conduit.\n     * @return exists  A boolean indicating whether the derived conduit has been\n     *                 deployed or not.\n     */\n    function getConduit(\n        bytes32 conduitKey\n    ) external view returns (address conduit, bool exists);\n\n    /**\n     * @notice Retrieve the potential owner, if any, for a given conduit. The\n     *         current owner may set a new potential owner via\n     *         `transferOwnership` and that owner may then accept ownership of\n     *         the conduit in question via `acceptOwnership`.\n     *\n     * @param conduit The conduit for which to retrieve the potential owner.\n     *\n     * @return potentialOwner The potential owner, if any, for the conduit.\n     */\n    function getPotentialOwner(\n        address conduit\n    ) external view returns (address potentialOwner);\n\n    /**\n     * @notice Retrieve the status (either open or closed) of a given channel on\n     *         a conduit.\n     *\n     * @param conduit The conduit for which to retrieve the channel status.\n     * @param channel The channel for which to retrieve the status.\n     *\n     * @return isOpen The status of the channel on the given conduit.\n     */\n    function getChannelStatus(\n        address conduit,\n        address channel\n    ) external view returns (bool isOpen);\n\n    /**\n     * @notice Retrieve the total number of open channels for a given conduit.\n     *\n     * @param conduit The conduit for which to retrieve the total channel count.\n     *\n     * @return totalChannels The total number of open channels for the conduit.\n     */\n    function getTotalChannels(\n        address conduit\n    ) external view returns (uint256 totalChannels);\n\n    /**\n     * @notice Retrieve an open channel at a specific index for a given conduit.\n     *         Note that the index of a channel can change as a result of other\n     *         channels being closed on the conduit.\n     *\n     * @param conduit      The conduit for which to retrieve the open channel.\n     * @param channelIndex The index of the channel in question.\n     *\n     * @return channel The open channel, if any, at the specified channel index.\n     */\n    function getChannel(\n        address conduit,\n        uint256 channelIndex\n    ) external view returns (address channel);\n\n    /**\n     * @notice Retrieve all open channels for a given conduit. Note that calling\n     *         this function for a conduit with many channels will revert with\n     *         an out-of-gas error.\n     *\n     * @param conduit The conduit for which to retrieve open channels.\n     *\n     * @return channels An array of open channels on the given conduit.\n     */\n    function getChannels(\n        address conduit\n    ) external view returns (address[] memory channels);\n\n    /**\n     * @dev Retrieve the conduit creation code and runtime code hashes.\n     */\n    function getConduitCodeHashes()\n        external\n        view\n        returns (bytes32 creationCodeHash, bytes32 runtimeCodeHash);\n}\n"
      },
      "contracts/interfaces/ConduitInterface.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport {\n    ConduitBatch1155Transfer,\n    ConduitTransfer\n} from \"../conduit/lib/ConduitStructs.sol\";\n\n/**\n * @title ConduitInterface\n * @author 5thWeb\n * @notice ConduitInterface contains all external function interfaces, events,\n *         and errors for conduit contracts.\n */\ninterface ConduitInterface {\n    /**\n     * @dev Revert with an error when attempting to execute transfers using a\n     *      caller that does not have an open channel.\n     */\n    error ChannelClosed(address channel);\n\n    /**\n     * @dev Revert with an error when attempting to update a channel to the\n     *      current status of that channel.\n     */\n    error ChannelStatusAlreadySet(address channel, bool isOpen);\n\n    /**\n     * @dev Revert with an error when attempting to execute a transfer for an\n     *      item that does not have an ERC20/721/1155 item type.\n     */\n    error InvalidItemType();\n\n    /**\n     * @dev Revert with an error when attempting to update the status of a\n     *      channel from a caller that is not the conduit controller.\n     */\n    error InvalidController();\n\n    /**\n     * @dev Emit an event whenever a channel is opened or closed.\n     *\n     * @param channel The channel that has been updated.\n     * @param open    A boolean indicating whether the conduit is open or not.\n     */\n    event ChannelUpdated(address indexed channel, bool open);\n\n    /**\n     * @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller\n     *         with an open channel can call this function.\n     *\n     * @param transfers The ERC20/721/1155 transfers to perform.\n     *\n     * @return magicValue A magic value indicating that the transfers were\n     *                    performed successfully.\n     */\n    function execute(\n        ConduitTransfer[] calldata transfers\n    ) external returns (bytes4 magicValue);\n\n    /**\n     * @notice Execute a sequence of batch 1155 transfers. Only a caller with an\n     *         open channel can call this function.\n     *\n     * @param batch1155Transfers The 1155 batch transfers to perform.\n     *\n     * @return magicValue A magic value indicating that the transfers were\n     *                    performed successfully.\n     */\n    function executeBatch1155(\n        ConduitBatch1155Transfer[] calldata batch1155Transfers\n    ) external returns (bytes4 magicValue);\n\n    /**\n     * @notice Execute a sequence of transfers, both single and batch 1155. Only\n     *         a caller with an open channel can call this function.\n     *\n     * @param standardTransfers  The ERC20/721/1155 transfers to perform.\n     * @param batch1155Transfers The 1155 batch transfers to perform.\n     *\n     * @return magicValue A magic value indicating that the transfers were\n     *                    performed successfully.\n     */\n    function executeWithBatch1155(\n        ConduitTransfer[] calldata standardTransfers,\n        ConduitBatch1155Transfer[] calldata batch1155Transfers\n    ) external returns (bytes4 magicValue);\n\n    /**\n     * @notice Open or close a given channel. Only callable by the controller.\n     *\n     * @param channel The channel to open or close.\n     * @param isOpen  The status of the channel (either open or closed).\n     */\n    function updateChannel(address channel, bool isOpen) external;\n}\n"
      },
      "contracts/interfaces/IERC721Receiver.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n *      from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n    /**\n     * @dev Whenever an ERC721 token is transferred to this contract via\n     *      safeTransferFrom, this function is called.\n     *\n     * @param operator  The address of the operator.\n     * @param from      The address of the sender.\n     * @param tokenId   The ID of the ERC721.\n     * @param data      Additional data.\n     *\n     * @return bytes4 The magic value, unless throwing.\n     */\n    function onERC721Received(\n        address operator,\n        address from,\n        uint256 tokenId,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n"
      },
      "contracts/interfaces/TransferHelperErrors.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\n/**\n * @title TransferHelperErrors\n */\ninterface TransferHelperErrors {\n    /**\n     * @dev Revert with an error when attempting to execute transfers with a\n     *      NATIVE itemType.\n     */\n    error InvalidItemType();\n\n    /**\n     * @dev Revert with an error when an ERC721 transfer with amount other than\n     *      one is attempted.\n     *\n     * @param amount The amount of the ERC721 tokens to transfer.\n     */\n    error InvalidERC721TransferAmount(uint256 amount);\n\n    /**\n     * @dev Revert with an error when attempting to execute an ERC721 transfer\n     *      to an invalid recipient.\n     */\n    error InvalidERC721Recipient(address recipient);\n\n    /**\n     * @dev Revert with an error when a call to an ERC721 receiver reverts with\n     *      bytes data.\n     */\n    error ERC721ReceiverErrorRevertBytes(\n        bytes reason,\n        address receiver,\n        address sender,\n        uint256 identifier\n    );\n\n    /**\n     * @dev Revert with an error when a call to an ERC721 receiver reverts with\n     *      string reason.\n     */\n    error ERC721ReceiverErrorRevertString(\n        string reason,\n        address receiver,\n        address sender,\n        uint256 identifier\n    );\n\n    /**\n     * @dev Revert with an error when an ERC20 token has an invalid identifier.\n     */\n    error InvalidERC20Identifier();\n\n    /**\n     * @dev Revert with an error if the recipient is the zero address.\n     */\n    error RecipientCannotBeZeroAddress();\n\n    /**\n     * @dev Revert with an error when attempting to fill an order referencing an\n     *      invalid conduit (i.e. one that has not been deployed).\n     */\n    error InvalidConduit(bytes32 conduitKey, address conduit);\n\n    /**\n     * @dev Revert with an error when a call to a conduit reverts with a\n     *      reason string.\n     */\n    error ConduitErrorRevertString(\n        string reason,\n        bytes32 conduitKey,\n        address conduit\n    );\n\n    /**\n     * @dev Revert with an error when a call to a conduit reverts with bytes\n     *      data.\n     */\n    error ConduitErrorRevertBytes(\n        bytes reason,\n        bytes32 conduitKey,\n        address conduit\n    );\n}\n"
      },
      "contracts/interfaces/TransferHelperInterface.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport {\n    TransferHelperItemsWithRecipient\n} from \"../helpers/TransferHelperStructs.sol\";\n\ninterface TransferHelperInterface {\n    /**\n     * @notice Transfer multiple items to a single recipient.\n     *\n     * @param items The items to transfer.\n     * @param conduitKey  The key of the conduit performing the bulk transfer.\n     */\n    function bulkTransfer(\n        TransferHelperItemsWithRecipient[] calldata items,\n        bytes32 conduitKey\n    ) external returns (bytes4);\n}\n"
      }
    },
    "settings": {
      "viaIR": true,
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}