creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/conduit/Conduit.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { ConduitInterface } from \"../interfaces/ConduitInterface.sol\";\n\nimport { ConduitItemType } from \"./lib/ConduitEnums.sol\";\n\nimport { TokenTransferrer } from \"../lib/TokenTransferrer.sol\";\n\nimport {\n    ConduitBatch1155Transfer,\n    ConduitTransfer\n} from \"./lib/ConduitStructs.sol\";\n\nimport {\n    ChannelClosed_channel_ptr,\n    ChannelClosed_error_length,\n    ChannelClosed_error_ptr,\n    ChannelClosed_error_signature,\n    ChannelKey_channel_ptr,\n    ChannelKey_length,\n    ChannelKey_slot_ptr\n} from \"./lib/ConduitConstants.sol\";\n\n/**\n * @title Conduit\n * @author 5thWeb\n * @notice This contract serves as an originator for \"proxied\" transfers. Each\n *         conduit is deployed and controlled by a \"conduit controller\" that can\n *         add and remove \"channels\" or contracts that can instruct the conduit\n *         to transfer approved ERC20/721/1155 tokens. *IMPORTANT NOTE: each\n *         conduit has an owner that can arbitrarily add or remove channels, and\n *         a malicious or negligent owner can add a channel that allows for any\n *         approved ERC20/721/1155 tokens to be taken immediately — be extremely\n *         cautious with what conduits you give token approvals to!*\n */\ncontract Conduit is ConduitInterface, TokenTransferrer {\n    // Set deployer as an immutable controller that can update channel statuses.\n    address private immutable _controller;\n\n    // Track the status of each channel.\n    mapping(address => bool) private _channels;\n\n    /**\n     * @notice Ensure that the caller is currently registered as an open channel\n     *         on the conduit.\n     */\n    modifier onlyOpenChannel() {\n        // Utilize assembly to access channel storage mapping directly.\n        assembly {\n            // Write the caller to scratch space.\n            mstore(ChannelKey_channel_ptr, caller())\n\n            // Write the storage slot for _channels to scratch space.\n            mstore(ChannelKey_slot_ptr, _channels.slot)\n\n            // Derive the position in storage of _channels[msg.sender]\n            // and check if the stored value is zero.\n            if iszero(\n                sload(keccak256(ChannelKey_channel_ptr, ChannelKey_length))\n            ) {\n                // The caller is not an open channel; revert with\n                // ChannelClosed(caller). First, set error signature in memory.\n                mstore(ChannelClosed_error_ptr, ChannelClosed_error_signature)\n\n                // Next, set the caller as the argument.\n                mstore(ChannelClosed_channel_ptr, caller())\n\n                // Finally, revert, returning full custom error with argument\n                // data in memory.\n                // revert(abi.encodeWithSignature(\n                //     \"ChannelClosed(address)\", caller()\n                // ))\n                revert(ChannelClosed_error_ptr, ChannelClosed_error_length)\n            }\n        }\n\n        // Continue with function execution.\n        _;\n    }\n\n    /**\n     * @notice In the constructor, set the deployer as the controller.\n     */\n    constructor() {\n        // Set the deployer as the controller.\n        _controller = msg.sender;\n    }\n\n    /**\n     * @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller\n     *         with an open channel can call this function. Note that channels\n     *         are expected to implement reentrancy protection if desired, and\n     *         that cross-channel reentrancy may be possible if the conduit has\n     *         multiple open channels at once. Also note that channels are\n     *         expected to implement checks against transferring any zero-amount\n     *         items if that constraint is desired.\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 override onlyOpenChannel returns (bytes4 magicValue) {\n        // Retrieve the total number of transfers and place on the stack.\n        uint256 totalStandardTransfers = transfers.length;\n\n        // Iterate over each transfer.\n        for (uint256 i = 0; i < totalStandardTransfers; ) {\n            // Retrieve the transfer in question and perform the transfer.\n            _transfer(transfers[i]);\n\n            // Skip overflow check as for loop is indexed starting at zero.\n            unchecked {\n                ++i;\n            }\n        }\n\n        // Return a magic value indicating that the transfers were performed.\n        magicValue = this.execute.selector;\n    }\n\n    /**\n     * @notice Execute a sequence of batch 1155 item transfers. Only a caller\n     *         with an open channel can call this function. Note that channels\n     *         are expected to implement reentrancy protection if desired, and\n     *         that cross-channel reentrancy may be possible if the conduit has\n     *         multiple open channels at once. Also note that channels are\n     *         expected to implement checks against transferring any zero-amount\n     *         items if that constraint is desired.\n     *\n     * @param batchTransfers The 1155 batch item transfers to perform.\n     *\n     * @return magicValue A magic value indicating that the item transfers were\n     *                    performed successfully.\n     */\n    function executeBatch1155(\n        ConduitBatch1155Transfer[] calldata batchTransfers\n    ) external override onlyOpenChannel returns (bytes4 magicValue) {\n        // Perform 1155 batch transfers. Note that memory should be considered\n        // entirely corrupted from this point forward.\n        _performERC1155BatchTransfers(batchTransfers);\n\n        // Return a magic value indicating that the transfers were performed.\n        magicValue = this.executeBatch1155.selector;\n    }\n\n    /**\n     * @notice Execute a sequence of transfers, both single ERC20/721/1155 item\n     *         transfers as well as batch 1155 item transfers. Only a caller\n     *         with an open channel can call this function. Note that channels\n     *         are expected to implement reentrancy protection if desired, and\n     *         that cross-channel reentrancy may be possible if the conduit has\n     *         multiple open channels at once. Also note that channels are\n     *         expected to implement checks against transferring any zero-amount\n     *         items if that constraint is desired.\n     *\n     * @param standardTransfers The ERC20/721/1155 item transfers to perform.\n     * @param batchTransfers    The 1155 batch item transfers to perform.\n     *\n     * @return magicValue A magic value indicating that the item transfers were\n     *                    performed successfully.\n     */\n    function executeWithBatch1155(\n        ConduitTransfer[] calldata standardTransfers,\n        ConduitBatch1155Transfer[] calldata batchTransfers\n    ) external override onlyOpenChannel returns (bytes4 magicValue) {\n        // Retrieve the total number of transfers and place on the stack.\n        uint256 totalStandardTransfers = standardTransfers.length;\n\n        // Iterate over each standard transfer.\n        for (uint256 i = 0; i < totalStandardTransfers; ) {\n            // Retrieve the transfer in question and perform the transfer.\n            _transfer(standardTransfers[i]);\n\n            // Skip overflow check as for loop is indexed starting at zero.\n            unchecked {\n                ++i;\n            }\n        }\n\n        // Perform 1155 batch transfers. Note that memory should be considered\n        // entirely corrupted from this point forward aside from the free memory\n        // pointer having the default value.\n        _performERC1155BatchTransfers(batchTransfers);\n\n        // Return a magic value indicating that the transfers were performed.\n        magicValue = this.executeWithBatch1155.selector;\n    }\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 override {\n        // Ensure that the caller is the controller of this contract.\n        if (msg.sender != _controller) {\n            revert InvalidController();\n        }\n\n        // Ensure that the channel does not already have the indicated status.\n        if (_channels[channel] == isOpen) {\n            revert ChannelStatusAlreadySet(channel, isOpen);\n        }\n\n        // Update the status of the channel.\n        _channels[channel] = isOpen;\n\n        // Emit a corresponding event.\n        emit ChannelUpdated(channel, isOpen);\n    }\n\n    /**\n     * @dev Internal function to transfer a given ERC20/721/1155 item. Note that\n     *      channels are expected to implement checks against transferring any\n     *      zero-amount items if that constraint is desired.\n     *\n     * @param item The ERC20/721/1155 item to transfer.\n     */\n    function _transfer(ConduitTransfer calldata item) internal {\n        // Determine the transfer method based on the respective item type.\n        if (item.itemType == ConduitItemType.ERC20) {\n            // Transfer ERC20 token. Note that item.identifier is ignored and\n            // therefore ERC20 transfer items are potentially malleable — this\n            // check should be performed by the calling channel if a constraint\n            // on item malleability is desired.\n            _performERC20Transfer(item.token, item.from, item.to, item.amount);\n        } else if (item.itemType == ConduitItemType.ERC721) {\n            // Ensure that exactly one 721 item is being transferred.\n            if (item.amount != 1) {\n                revert InvalidERC721TransferAmount(item.amount);\n            }\n\n            // Transfer ERC721 token.\n            _performERC721Transfer(\n                item.token,\n                item.from,\n                item.to,\n                item.identifier\n            );\n        } else if (item.itemType == ConduitItemType.ERC1155) {\n            // Transfer ERC1155 token.\n            _performERC1155Transfer(\n                item.token,\n                item.from,\n                item.to,\n                item.identifier,\n                item.amount\n            );\n        } else {\n            // Throw with an error.\n            revert InvalidItemType();\n        }\n    }\n}\n"
      },
      "contracts/conduit/ConduitController.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport {\n    ConduitControllerInterface\n} from \"../interfaces/ConduitControllerInterface.sol\";\n\nimport { ConduitInterface } from \"../interfaces/ConduitInterface.sol\";\n\nimport { Conduit } from \"./Conduit.sol\";\n\n/**\n * @title ConduitController\n * @author 5thWeb\n * @notice ConduitController enables deploying and managing new conduits, or\n *         contracts that allow registered callers (or open \"channels\") to\n *         transfer approved ERC20/721/1155 tokens on their behalf.\n */\ncontract ConduitController is ConduitControllerInterface {\n    // Register keys, owners, new potential owners, and channels by conduit.\n    mapping(address => ConduitProperties) internal _conduits;\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 Initialize contract by deploying a conduit and setting the creation\n     *      code and runtime code hashes as immutable arguments.\n     */\n    constructor() {\n        // Derive the conduit creation code hash and set it as an immutable.\n        _CONDUIT_CREATION_CODE_HASH = keccak256(type(Conduit).creationCode);\n\n        // Deploy a conduit with the zero hash as the salt.\n        Conduit zeroConduit = new Conduit{ salt: bytes32(0) }();\n\n        // Retrieve the conduit runtime code hash and set it as an immutable.\n        _CONDUIT_RUNTIME_CODE_HASH = address(zeroConduit).codehash;\n    }\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 override returns (address conduit) {\n        // Ensure that an initial owner has been supplied.\n        if (initialOwner == address(0)) {\n            revert InvalidInitialOwner();\n        }\n\n        // If the first 20 bytes of the conduit key do not match the caller...\n        if (address(uint160(bytes20(conduitKey))) != msg.sender) {\n            // Revert with an error indicating that the creator is invalid.\n            revert InvalidCreator();\n        }\n\n        // Derive address from deployer, conduit key and creation code hash.\n        conduit = address(\n            uint160(\n                uint256(\n                    keccak256(\n                        abi.encodePacked(\n                            bytes1(0xff),\n                            address(this),\n                            conduitKey,\n                            _CONDUIT_CREATION_CODE_HASH\n                        )\n                    )\n                )\n            )\n        );\n\n        // If derived conduit exists, as evidenced by comparing runtime code...\n        if (conduit.codehash == _CONDUIT_RUNTIME_CODE_HASH) {\n            // Revert with an error indicating that the conduit already exists.\n            revert ConduitAlreadyExists(conduit);\n        }\n\n        // Deploy the conduit via CREATE2 using the conduit key as the salt.\n        new Conduit{ salt: conduitKey }();\n\n        // Initialize storage variable referencing conduit properties.\n        ConduitProperties storage conduitProperties = _conduits[conduit];\n\n        // Set the supplied initial owner as the owner of the conduit.\n        conduitProperties.owner = initialOwner;\n\n        // Set conduit key used to deploy the conduit to enable reverse lookup.\n        conduitProperties.key = conduitKey;\n\n        // Emit an event indicating that the conduit has been deployed.\n        emit NewConduit(conduit, conduitKey);\n\n        // Emit an event indicating that conduit ownership has been assigned.\n        emit OwnershipTransferred(conduit, address(0), initialOwner);\n    }\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 override {\n        // Ensure the caller is the current owner of the conduit in question.\n        _assertCallerIsConduitOwner(conduit);\n\n        // Call the conduit, updating the channel.\n        ConduitInterface(conduit).updateChannel(channel, isOpen);\n\n        // Retrieve storage region where channels for the conduit are tracked.\n        ConduitProperties storage conduitProperties = _conduits[conduit];\n\n        // Retrieve the index, if one currently exists, for the updated channel.\n        uint256 channelIndexPlusOne = (\n            conduitProperties.channelIndexesPlusOne[channel]\n        );\n\n        // Determine whether the updated channel is already tracked as open.\n        bool channelPreviouslyOpen = channelIndexPlusOne != 0;\n\n        // If the channel has been set to open and was previously closed...\n        if (isOpen && !channelPreviouslyOpen) {\n            // Add the channel to the channels array for the conduit.\n            conduitProperties.channels.push(channel);\n\n            // Add new open channel length to associated mapping as index + 1.\n            conduitProperties.channelIndexesPlusOne[channel] = (\n                conduitProperties.channels.length\n            );\n        } else if (!isOpen && channelPreviouslyOpen) {\n            // Set a previously open channel as closed via \"swap & pop\" method.\n            // Decrement located index to get the index of the closed channel.\n            uint256 removedChannelIndex;\n\n            // Skip underflow check as channelPreviouslyOpen being true ensures\n            // that channelIndexPlusOne is nonzero.\n            unchecked {\n                removedChannelIndex = channelIndexPlusOne - 1;\n            }\n\n            // Use length of channels array to determine index of last channel.\n            uint256 finalChannelIndex = conduitProperties.channels.length - 1;\n\n            // If closed channel is not last channel in the channels array...\n            if (finalChannelIndex != removedChannelIndex) {\n                // Retrieve the final channel and place the value on the stack.\n                address finalChannel = (\n                    conduitProperties.channels[finalChannelIndex]\n                );\n\n                // Overwrite the removed channel using the final channel value.\n                conduitProperties.channels[removedChannelIndex] = finalChannel;\n\n                // Update final index in associated mapping to removed index.\n                conduitProperties.channelIndexesPlusOne[finalChannel] = (\n                    channelIndexPlusOne\n                );\n            }\n\n            // Remove the last channel from the channels array for the conduit.\n            conduitProperties.channels.pop();\n\n            // Remove the closed channel from associated mapping of indexes.\n            delete conduitProperties.channelIndexesPlusOne[channel];\n        }\n    }\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 override {\n        // Ensure the caller is the current owner of the conduit in question.\n        _assertCallerIsConduitOwner(conduit);\n\n        // Ensure the new potential owner is not an invalid address.\n        if (newPotentialOwner == address(0)) {\n            revert NewPotentialOwnerIsZeroAddress(conduit);\n        }\n\n        // Ensure the new potential owner is not already set.\n        if (newPotentialOwner == _conduits[conduit].potentialOwner) {\n            revert NewPotentialOwnerAlreadySet(conduit, newPotentialOwner);\n        }\n\n        // Emit an event indicating that the potential owner has been updated.\n        emit PotentialOwnerUpdated(newPotentialOwner);\n\n        // Set the new potential owner as the potential owner of the conduit.\n        _conduits[conduit].potentialOwner = newPotentialOwner;\n    }\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 override {\n        // Ensure the caller is the current owner of the conduit in question.\n        _assertCallerIsConduitOwner(conduit);\n\n        // Ensure that ownership transfer is currently possible.\n        if (_conduits[conduit].potentialOwner == address(0)) {\n            revert NoPotentialOwnerCurrentlySet(conduit);\n        }\n\n        // Emit an event indicating that the potential owner has been cleared.\n        emit PotentialOwnerUpdated(address(0));\n\n        // Clear the current new potential owner from the conduit.\n        _conduits[conduit].potentialOwner = address(0);\n    }\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 override {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // If caller does not match current potential owner of the conduit...\n        if (msg.sender != _conduits[conduit].potentialOwner) {\n            // Revert, indicating that caller is not current potential owner.\n            revert CallerIsNotNewPotentialOwner(conduit);\n        }\n\n        // Emit an event indicating that the potential owner has been cleared.\n        emit PotentialOwnerUpdated(address(0));\n\n        // Clear the current new potential owner from the conduit.\n        _conduits[conduit].potentialOwner = address(0);\n\n        // Emit an event indicating conduit ownership has been transferred.\n        emit OwnershipTransferred(\n            conduit,\n            _conduits[conduit].owner,\n            msg.sender\n        );\n\n        // Set the caller as the owner of the conduit.\n        _conduits[conduit].owner = msg.sender;\n    }\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(\n        address conduit\n    ) external view override returns (address owner) {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // Retrieve the current owner of the conduit in question.\n        owner = _conduits[conduit].owner;\n    }\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(\n        address conduit\n    ) external view override returns (bytes32 conduitKey) {\n        // Attempt to retrieve a conduit key for the conduit in question.\n        conduitKey = _conduits[conduit].key;\n\n        // Revert if no conduit key was located.\n        if (conduitKey == bytes32(0)) {\n            revert NoConduit();\n        }\n    }\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 override returns (address conduit, bool exists) {\n        // Derive address from deployer, conduit key and creation code hash.\n        conduit = address(\n            uint160(\n                uint256(\n                    keccak256(\n                        abi.encodePacked(\n                            bytes1(0xff),\n                            address(this),\n                            conduitKey,\n                            _CONDUIT_CREATION_CODE_HASH\n                        )\n                    )\n                )\n            )\n        );\n\n        // Determine whether conduit exists by retrieving its runtime code.\n        exists = (conduit.codehash == _CONDUIT_RUNTIME_CODE_HASH);\n    }\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 override returns (address potentialOwner) {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // Retrieve the current potential owner of the conduit in question.\n        potentialOwner = _conduits[conduit].potentialOwner;\n    }\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 override returns (bool isOpen) {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // Retrieve the current channel status for the conduit in question.\n        isOpen = _conduits[conduit].channelIndexesPlusOne[channel] != 0;\n    }\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 override returns (uint256 totalChannels) {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // Retrieve the total open channel count for the conduit in question.\n        totalChannels = _conduits[conduit].channels.length;\n    }\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 override returns (address channel) {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // Retrieve the total open channel count for the conduit in question.\n        uint256 totalChannels = _conduits[conduit].channels.length;\n\n        // Ensure that the supplied index is within range.\n        if (channelIndex >= totalChannels) {\n            revert ChannelOutOfRange(conduit);\n        }\n\n        // Retrieve the channel at the given index.\n        channel = _conduits[conduit].channels[channelIndex];\n    }\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 override returns (address[] memory channels) {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // Retrieve all of the open channels on the conduit in question.\n        channels = _conduits[conduit].channels;\n    }\n\n    /**\n     * @dev Retrieve the conduit creation code and runtime code hashes.\n     */\n    function getConduitCodeHashes()\n        external\n        view\n        override\n        returns (bytes32 creationCodeHash, bytes32 runtimeCodeHash)\n    {\n        // Retrieve the conduit creation code hash from runtime.\n        creationCodeHash = _CONDUIT_CREATION_CODE_HASH;\n\n        // Retrieve the conduit runtime code hash from runtime.\n        runtimeCodeHash = _CONDUIT_RUNTIME_CODE_HASH;\n    }\n\n    /**\n     * @dev Private view function to revert if the caller is not the owner of a\n     *      given conduit.\n     *\n     * @param conduit The conduit for which to assert ownership.\n     */\n    function _assertCallerIsConduitOwner(address conduit) private view {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // If the caller does not match the current owner of the conduit...\n        if (msg.sender != _conduits[conduit].owner) {\n            // Revert, indicating that the caller is not the owner.\n            revert CallerIsNotOwner(conduit);\n        }\n    }\n\n    /**\n     * @dev Private view function to revert if a given conduit does not exist.\n     *\n     * @param conduit The conduit for which to assert existence.\n     */\n    function _assertConduitExists(address conduit) private view {\n        // Attempt to retrieve a conduit key for the conduit in question.\n        if (_conduits[conduit].key == bytes32(0)) {\n            // Revert if no conduit key was located.\n            revert NoConduit();\n        }\n    }\n}\n"
      },
      "contracts/conduit/lib/ConduitConstants.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\n// error ChannelClosed(address channel)\nuint256 constant ChannelClosed_error_signature = (\n    0x93daadf200000000000000000000000000000000000000000000000000000000\n);\nuint256 constant ChannelClosed_error_ptr = 0x00;\nuint256 constant ChannelClosed_channel_ptr = 0x4;\nuint256 constant ChannelClosed_error_length = 0x24;\n\n// For the mapping:\n// mapping(address => bool) channels\n// The position in storage for a particular account is:\n// keccak256(abi.encode(account, channels.slot))\nuint256 constant ChannelKey_channel_ptr = 0x00;\nuint256 constant ChannelKey_slot_ptr = 0x20;\nuint256 constant ChannelKey_length = 0x40;\n"
      },
      "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/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/TokenTransferrerErrors.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\n/**\n * @title TokenTransferrerErrors\n */\ninterface TokenTransferrerErrors {\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 fulfill an order where an\n     *      item has an amount of zero.\n     */\n    error MissingItemAmount();\n\n    /**\n     * @dev Revert with an error when attempting to fulfill an order where an\n     *      item has unused parameters. This includes both the token and the\n     *      identifier parameters for native transfers as well as the identifier\n     *      parameter for ERC20 transfers. Note that the conduit does not\n     *      perform this check, leaving it up to the calling channel to enforce\n     *      when desired.\n     */\n    error UnusedItemParameters();\n\n    /**\n     * @dev Revert with an error when an ERC20, ERC721, or ERC1155 token\n     *      transfer reverts.\n     *\n     * @param token      The token for which the transfer was attempted.\n     * @param from       The source of the attempted transfer.\n     * @param to         The recipient of the attempted transfer.\n     * @param identifier The identifier for the attempted transfer.\n     * @param amount     The amount for the attempted transfer.\n     */\n    error TokenTransferGenericFailure(\n        address token,\n        address from,\n        address to,\n        uint256 identifier,\n        uint256 amount\n    );\n\n    /**\n     * @dev Revert with an error when a batch ERC1155 token transfer reverts.\n     *\n     * @param token       The token for which the transfer was attempted.\n     * @param from        The source of the attempted transfer.\n     * @param to          The recipient of the attempted transfer.\n     * @param identifiers The identifiers for the attempted transfer.\n     * @param amounts     The amounts for the attempted transfer.\n     */\n    error ERC1155BatchTransferGenericFailure(\n        address token,\n        address from,\n        address to,\n        uint256[] identifiers,\n        uint256[] amounts\n    );\n\n    /**\n     * @dev Revert with an error when an ERC20 token transfer returns a falsey\n     *      value.\n     *\n     * @param token      The token for which the ERC20 transfer was attempted.\n     * @param from       The source of the attempted ERC20 transfer.\n     * @param to         The recipient of the attempted ERC20 transfer.\n     * @param amount     The amount for the attempted ERC20 transfer.\n     */\n    error BadReturnValueFromERC20OnTransfer(\n        address token,\n        address from,\n        address to,\n        uint256 amount\n    );\n\n    /**\n     * @dev Revert with an error when an account being called as an assumed\n     *      contract does not have code and returns no data.\n     *\n     * @param account The account that should contain code.\n     */\n    error NoContract(address account);\n\n    /**\n     * @dev Revert with an error when attempting to execute an 1155 batch\n     *      transfer using calldata not produced by default ABI encoding or with\n     *      different lengths for ids and amounts arrays.\n     */\n    error Invalid1155BatchTransferEncoding();\n}\n"
      },
      "contracts/lib/TokenTransferrer.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport {\n    BadReturnValueFromERC20OnTransfer_error_amount_ptr,\n    BadReturnValueFromERC20OnTransfer_error_from_ptr,\n    BadReturnValueFromERC20OnTransfer_error_length,\n    BadReturnValueFromERC20OnTransfer_error_selector,\n    BadReturnValueFromERC20OnTransfer_error_to_ptr,\n    BadReturnValueFromERC20OnTransfer_error_token_ptr,\n    BatchTransfer1155Params_amounts_head_ptr,\n    BatchTransfer1155Params_calldata_baseSize,\n    BatchTransfer1155Params_data_head_ptr,\n    BatchTransfer1155Params_data_length_basePtr,\n    BatchTransfer1155Params_ids_head_ptr,\n    BatchTransfer1155Params_ids_length_offset,\n    BatchTransfer1155Params_ids_length_ptr,\n    BatchTransfer1155Params_ptr,\n    ConduitBatch1155Transfer_amounts_length_baseOffset,\n    ConduitBatch1155Transfer_from_offset,\n    ConduitBatch1155Transfer_ids_head_offset,\n    ConduitBatch1155Transfer_ids_length_offset,\n    ConduitBatch1155Transfer_usable_head_size,\n    ConduitBatchTransfer_amounts_head_offset,\n    CostPerWord,\n    DefaultFreeMemoryPointer,\n    ERC1155_safeBatchTransferFrom_signature,\n    ERC1155_safeTransferFrom_amount_ptr,\n    ERC1155_safeTransferFrom_data_length_offset,\n    ERC1155_safeTransferFrom_data_length_ptr,\n    ERC1155_safeTransferFrom_data_offset_ptr,\n    ERC1155_safeTransferFrom_from_ptr,\n    ERC1155_safeTransferFrom_id_ptr,\n    ERC1155_safeTransferFrom_length,\n    ERC1155_safeTransferFrom_sig_ptr,\n    ERC1155_safeTransferFrom_signature,\n    ERC1155_safeTransferFrom_to_ptr,\n    ERC1155BatchTransferGenericFailure_error_signature,\n    ERC1155BatchTransferGenericFailure_ids_offset,\n    ERC1155BatchTransferGenericFailure_token_ptr,\n    ERC20_transferFrom_amount_ptr,\n    ERC20_transferFrom_from_ptr,\n    ERC20_transferFrom_length,\n    ERC20_transferFrom_sig_ptr,\n    ERC20_transferFrom_signature,\n    ERC20_transferFrom_to_ptr,\n    ERC721_transferFrom_from_ptr,\n    ERC721_transferFrom_id_ptr,\n    ERC721_transferFrom_length,\n    ERC721_transferFrom_sig_ptr,\n    ERC721_transferFrom_signature,\n    ERC721_transferFrom_to_ptr,\n    ExtraGasBuffer,\n    FreeMemoryPointerSlot,\n    Generic_error_selector_offset,\n    Invalid1155BatchTransferEncoding_length,\n    Invalid1155BatchTransferEncoding_ptr,\n    Invalid1155BatchTransferEncoding_selector,\n    MemoryExpansionCoefficientShift,\n    NoContract_error_account_ptr,\n    NoContract_error_length,\n    NoContract_error_selector,\n    OneWord,\n    OneWordShift,\n    Slot0x80,\n    Slot0xA0,\n    Slot0xC0,\n    ThirtyOneBytes,\n    TokenTransferGenericFailure_err_identifier_ptr,\n    TokenTransferGenericFailure_error_amount_ptr,\n    TokenTransferGenericFailure_error_from_ptr,\n    TokenTransferGenericFailure_error_identifier_ptr,\n    TokenTransferGenericFailure_error_length,\n    TokenTransferGenericFailure_error_selector,\n    TokenTransferGenericFailure_error_to_ptr,\n    TokenTransferGenericFailure_error_token_ptr,\n    TwoWords,\n    TwoWordsShift,\n    ZeroSlot\n} from \"./TokenTransferrerConstants.sol\";\n\nimport {\n    TokenTransferrerErrors\n} from \"../interfaces/TokenTransferrerErrors.sol\";\n\nimport { ConduitBatch1155Transfer } from \"../conduit/lib/ConduitStructs.sol\";\n\n/**\n * @title TokenTransferrer\n * @author 5thWeb\n * @notice TokenTransferrer is a library for performing optimized ERC20, ERC721,\n *         ERC1155, and batch ERC1155 transfers, used by both Inkubate as well as\n *         by conduits deployed by the ConduitController. Use great caution when\n *         considering these functions for use in other codebases, as there are\n *         significant side effects and edge cases that need to be thoroughly\n *         understood and carefully addressed.\n */\ncontract TokenTransferrer is TokenTransferrerErrors {\n    /**\n     * @dev Internal function to transfer ERC20 tokens from a given originator\n     *      to a given recipient. Sufficient approvals must be set on the\n     *      contract performing the transfer.\n     *\n     * @param token      The ERC20 token to transfer.\n     * @param from       The originator of the transfer.\n     * @param to         The recipient of the transfer.\n     * @param amount     The amount to transfer.\n     */\n    function _performERC20Transfer(\n        address token,\n        address from,\n        address to,\n        uint256 amount\n    ) internal {\n        // Utilize assembly to perform an optimized ERC20 token transfer.\n        assembly {\n            // The free memory pointer memory slot will be used when populating\n            // call data for the transfer; read the value and restore it later.\n            let memPointer := mload(FreeMemoryPointerSlot)\n\n            // Write call data into memory, starting with function selector.\n            mstore(ERC20_transferFrom_sig_ptr, ERC20_transferFrom_signature)\n            mstore(ERC20_transferFrom_from_ptr, from)\n            mstore(ERC20_transferFrom_to_ptr, to)\n            mstore(ERC20_transferFrom_amount_ptr, amount)\n\n            // Make call & copy up to 32 bytes of return data to scratch space.\n            // Scratch space does not need to be cleared ahead of time, as the\n            // subsequent check will ensure that either at least a full word of\n            // return data is received (in which case it will be overwritten) or\n            // that no data is received (in which case scratch space will be\n            // ignored) on a successful call to the given token.\n            let callStatus := call(\n                gas(),\n                token,\n                0,\n                ERC20_transferFrom_sig_ptr,\n                ERC20_transferFrom_length,\n                0,\n                OneWord\n            )\n\n            // Determine whether transfer was successful using status & result.\n            let success := and(\n                // Set success to whether the call reverted, if not check it\n                // either returned exactly 1 (can't just be non-zero data), or\n                // had no return data.\n                or(\n                    and(eq(mload(0), 1), gt(returndatasize(), 31)),\n                    iszero(returndatasize())\n                ),\n                callStatus\n            )\n\n            // Handle cases where either the transfer failed or no data was\n            // returned. Group these, as most transfers will succeed with data.\n            // Equivalent to `or(iszero(success), iszero(returndatasize()))`\n            // but after it's inverted for JUMPI this expression is cheaper.\n            if iszero(and(success, iszero(iszero(returndatasize())))) {\n                // If the token has no code or the transfer failed: Equivalent\n                // to `or(iszero(success), iszero(extcodesize(token)))` but\n                // after it's inverted for JUMPI this expression is cheaper.\n                if iszero(and(iszero(iszero(extcodesize(token))), success)) {\n                    // If the transfer failed:\n                    if iszero(success) {\n                        // If it was due to a revert:\n                        if iszero(callStatus) {\n                            // If it returned a message, bubble it up as long as\n                            // sufficient gas remains to do so:\n                            if returndatasize() {\n                                // Ensure that sufficient gas is available to\n                                // copy returndata while expanding memory where\n                                // necessary. Start by computing the word size\n                                // of returndata and allocated memory. Round up\n                                // to the nearest full word.\n                                let returnDataWords := shr(\n                                    OneWordShift,\n                                    add(returndatasize(), ThirtyOneBytes)\n                                )\n\n                                // Note: use the free memory pointer in place of\n                                // msize() to work around a Yul warning that\n                                // prevents accessing msize directly when the IR\n                                // pipeline is activated.\n                                let msizeWords := shr(OneWordShift, memPointer)\n\n                                // Next, compute the cost of the returndatacopy.\n                                let cost := mul(CostPerWord, returnDataWords)\n\n                                // Then, compute cost of new memory allocation.\n                                if gt(returnDataWords, msizeWords) {\n                                    cost := add(\n                                        cost,\n                                        add(\n                                            mul(\n                                                sub(\n                                                    returnDataWords,\n                                                    msizeWords\n                                                ),\n                                                CostPerWord\n                                            ),\n                                            shr(\n                                                MemoryExpansionCoefficientShift,\n                                                sub(\n                                                    mul(\n                                                        returnDataWords,\n                                                        returnDataWords\n                                                    ),\n                                                    mul(msizeWords, msizeWords)\n                                                )\n                                            )\n                                        )\n                                    )\n                                }\n\n                                // Finally, add a small constant and compare to\n                                // gas remaining; bubble up the revert data if\n                                // enough gas is still available.\n                                if lt(add(cost, ExtraGasBuffer), gas()) {\n                                    // Copy returndata to memory; overwrite\n                                    // existing memory.\n                                    returndatacopy(0, 0, returndatasize())\n\n                                    // Revert, specifying memory region with\n                                    // copied returndata.\n                                    revert(0, returndatasize())\n                                }\n                            }\n\n                            // Store left-padded selector with push4, mem[28:32]\n                            mstore(\n                                0,\n                                TokenTransferGenericFailure_error_selector\n                            )\n                            mstore(\n                                TokenTransferGenericFailure_error_token_ptr,\n                                token\n                            )\n                            mstore(\n                                TokenTransferGenericFailure_error_from_ptr,\n                                from\n                            )\n                            mstore(TokenTransferGenericFailure_error_to_ptr, to)\n                            mstore(\n                                TokenTransferGenericFailure_err_identifier_ptr,\n                                0\n                            )\n                            mstore(\n                                TokenTransferGenericFailure_error_amount_ptr,\n                                amount\n                            )\n\n                            // revert(abi.encodeWithSignature(\n                            //     \"TokenTransferGenericFailure(\n                            //         address,address,address,uint256,uint256\n                            //     )\", token, from, to, identifier, amount\n                            // ))\n                            revert(\n                                Generic_error_selector_offset,\n                                TokenTransferGenericFailure_error_length\n                            )\n                        }\n\n                        // Otherwise revert with a message about the token\n                        // returning false or non-compliant return values.\n\n                        // Store left-padded selector with push4, mem[28:32]\n                        mstore(\n                            0,\n                            BadReturnValueFromERC20OnTransfer_error_selector\n                        )\n                        mstore(\n                            BadReturnValueFromERC20OnTransfer_error_token_ptr,\n                            token\n                        )\n                        mstore(\n                            BadReturnValueFromERC20OnTransfer_error_from_ptr,\n                            from\n                        )\n                        mstore(\n                            BadReturnValueFromERC20OnTransfer_error_to_ptr,\n                            to\n                        )\n                        mstore(\n                            BadReturnValueFromERC20OnTransfer_error_amount_ptr,\n                            amount\n                        )\n\n                        // revert(abi.encodeWithSignature(\n                        //     \"BadReturnValueFromERC20OnTransfer(\n                        //         address,address,address,uint256\n                        //     )\", token, from, to, amount\n                        // ))\n                        revert(\n                            Generic_error_selector_offset,\n                            BadReturnValueFromERC20OnTransfer_error_length\n                        )\n                    }\n\n                    // Otherwise, revert with error about token not having code:\n                    // Store left-padded selector with push4, mem[28:32]\n                    mstore(0, NoContract_error_selector)\n                    mstore(NoContract_error_account_ptr, token)\n\n                    // revert(abi.encodeWithSignature(\n                    //      \"NoContract(address)\", account\n                    // ))\n                    revert(\n                        Generic_error_selector_offset,\n                        NoContract_error_length\n                    )\n                }\n\n                // Otherwise, the token just returned no data despite the call\n                // having succeeded; no need to optimize for this as it's not\n                // technically ERC20 compliant.\n            }\n\n            // Restore the original free memory pointer.\n            mstore(FreeMemoryPointerSlot, memPointer)\n\n            // Restore the zero slot to zero.\n            mstore(ZeroSlot, 0)\n        }\n    }\n\n    /**\n     * @dev Internal function to transfer an ERC721 token from a given\n     *      originator to a given recipient. Sufficient approvals must be set on\n     *      the contract performing the transfer. Note that this function does\n     *      not check whether the receiver can accept the ERC721 token (i.e. it\n     *      does not use `safeTransferFrom`).\n     *\n     * @param token      The ERC721 token to transfer.\n     * @param from       The originator of the transfer.\n     * @param to         The recipient of the transfer.\n     * @param identifier The tokenId to transfer.\n     */\n    function _performERC721Transfer(\n        address token,\n        address from,\n        address to,\n        uint256 identifier\n    ) internal {\n        // Utilize assembly to perform an optimized ERC721 token transfer.\n        assembly {\n            // If the token has no code, revert.\n            if iszero(extcodesize(token)) {\n                // Store left-padded selector with push4, mem[28:32] = selector\n                mstore(0, NoContract_error_selector)\n                mstore(NoContract_error_account_ptr, token)\n\n                // revert(abi.encodeWithSignature(\n                //     \"NoContract(address)\", account\n                // ))\n                revert(Generic_error_selector_offset, NoContract_error_length)\n            }\n\n            // The free memory pointer memory slot will be used when populating\n            // call data for the transfer; read the value and restore it later.\n            let memPointer := mload(FreeMemoryPointerSlot)\n\n            // Write call data to memory starting with function selector.\n            mstore(ERC721_transferFrom_sig_ptr, ERC721_transferFrom_signature)\n            mstore(ERC721_transferFrom_from_ptr, from)\n            mstore(ERC721_transferFrom_to_ptr, to)\n            mstore(ERC721_transferFrom_id_ptr, identifier)\n\n            // Perform the call, ignoring return data.\n            let success := call(\n                gas(),\n                token,\n                0,\n                ERC721_transferFrom_sig_ptr,\n                ERC721_transferFrom_length,\n                0,\n                0\n            )\n\n            // If the transfer reverted:\n            if iszero(success) {\n                // If it returned a message, bubble it up as long as sufficient\n                // gas remains to do so:\n                if returndatasize() {\n                    // Ensure that sufficient gas is available to copy\n                    // returndata while expanding memory where necessary. Start\n                    // by computing word size of returndata & allocated memory.\n                    // Round up to the nearest full word.\n                    let returnDataWords := shr(\n                        OneWordShift,\n                        add(returndatasize(), ThirtyOneBytes)\n                    )\n\n                    // Note: use the free memory pointer in place of msize() to\n                    // work around a Yul warning that prevents accessing msize\n                    // directly when the IR pipeline is activated.\n                    let msizeWords := shr(OneWordShift, memPointer)\n\n                    // Next, compute the cost of the returndatacopy.\n                    let cost := mul(CostPerWord, returnDataWords)\n\n                    // Then, compute cost of new memory allocation.\n                    if gt(returnDataWords, msizeWords) {\n                        cost := add(\n                            cost,\n                            add(\n                                mul(\n                                    sub(returnDataWords, msizeWords),\n                                    CostPerWord\n                                ),\n                                shr(\n                                    MemoryExpansionCoefficientShift,\n                                    sub(\n                                        mul(returnDataWords, returnDataWords),\n                                        mul(msizeWords, msizeWords)\n                                    )\n                                )\n                            )\n                        )\n                    }\n\n                    // Finally, add a small constant and compare to gas\n                    // remaining; bubble up the revert data if enough gas is\n                    // still available.\n                    if lt(add(cost, ExtraGasBuffer), gas()) {\n                        // Copy returndata to memory; overwrite existing memory.\n                        returndatacopy(0, 0, returndatasize())\n\n                        // Revert, giving memory region with copied returndata.\n                        revert(0, returndatasize())\n                    }\n                }\n\n                // Otherwise revert with a generic error message.\n                // Store left-padded selector with push4, mem[28:32] = selector\n                mstore(0, TokenTransferGenericFailure_error_selector)\n                mstore(TokenTransferGenericFailure_error_token_ptr, token)\n                mstore(TokenTransferGenericFailure_error_from_ptr, from)\n                mstore(TokenTransferGenericFailure_error_to_ptr, to)\n                mstore(\n                    TokenTransferGenericFailure_error_identifier_ptr,\n                    identifier\n                )\n                mstore(TokenTransferGenericFailure_error_amount_ptr, 1)\n\n                // revert(abi.encodeWithSignature(\n                //     \"TokenTransferGenericFailure(\n                //         address,address,address,uint256,uint256\n                //     )\", token, from, to, identifier, amount\n                // ))\n                revert(\n                    Generic_error_selector_offset,\n                    TokenTransferGenericFailure_error_length\n                )\n            }\n\n            // Restore the original free memory pointer.\n            mstore(FreeMemoryPointerSlot, memPointer)\n\n            // Restore the zero slot to zero.\n            mstore(ZeroSlot, 0)\n        }\n    }\n\n    /**\n     * @dev Internal function to transfer ERC1155 tokens from a given\n     *      originator to a given recipient. Sufficient approvals must be set on\n     *      the contract performing the transfer and contract recipients must\n     *      implement the ERC1155TokenReceiver interface to indicate that they\n     *      are willing to accept the transfer.\n     *\n     * @param token      The ERC1155 token to transfer.\n     * @param from       The originator of the transfer.\n     * @param to         The recipient of the transfer.\n     * @param identifier The id to transfer.\n     * @param amount     The amount to transfer.\n     */\n    function _performERC1155Transfer(\n        address token,\n        address from,\n        address to,\n        uint256 identifier,\n        uint256 amount\n    ) internal {\n        // Utilize assembly to perform an optimized ERC1155 token transfer.\n        assembly {\n            // If the token has no code, revert.\n            if iszero(extcodesize(token)) {\n                // Store left-padded selector with push4, mem[28:32] = selector\n                mstore(0, NoContract_error_selector)\n                mstore(NoContract_error_account_ptr, token)\n\n                // revert(abi.encodeWithSignature(\n                //     \"NoContract(address)\", account\n                // ))\n                revert(Generic_error_selector_offset, NoContract_error_length)\n            }\n\n            // The following memory slots will be used when populating call data\n            // for the transfer; read the values and restore them later.\n            let memPointer := mload(FreeMemoryPointerSlot)\n            let slot0x80 := mload(Slot0x80)\n            let slot0xA0 := mload(Slot0xA0)\n            let slot0xC0 := mload(Slot0xC0)\n\n            // Write call data into memory, beginning with function selector.\n            mstore(\n                ERC1155_safeTransferFrom_sig_ptr,\n                ERC1155_safeTransferFrom_signature\n            )\n            mstore(ERC1155_safeTransferFrom_from_ptr, from)\n            mstore(ERC1155_safeTransferFrom_to_ptr, to)\n            mstore(ERC1155_safeTransferFrom_id_ptr, identifier)\n            mstore(ERC1155_safeTransferFrom_amount_ptr, amount)\n            mstore(\n                ERC1155_safeTransferFrom_data_offset_ptr,\n                ERC1155_safeTransferFrom_data_length_offset\n            )\n            mstore(ERC1155_safeTransferFrom_data_length_ptr, 0)\n\n            // Perform the call, ignoring return data.\n            let success := call(\n                gas(),\n                token,\n                0,\n                ERC1155_safeTransferFrom_sig_ptr,\n                ERC1155_safeTransferFrom_length,\n                0,\n                0\n            )\n\n            // If the transfer reverted:\n            if iszero(success) {\n                // If it returned a message, bubble it up as long as sufficient\n                // gas remains to do so:\n                if returndatasize() {\n                    // Ensure that sufficient gas is available to copy\n                    // returndata while expanding memory where necessary. Start\n                    // by computing word size of returndata & allocated memory.\n                    // Round up to the nearest full word.\n                    let returnDataWords := shr(\n                        OneWordShift,\n                        add(returndatasize(), ThirtyOneBytes)\n                    )\n\n                    // Note: use the free memory pointer in place of msize() to\n                    // work around a Yul warning that prevents accessing msize\n                    // directly when the IR pipeline is activated.\n                    let msizeWords := shr(OneWordShift, memPointer)\n\n                    // Next, compute the cost of the returndatacopy.\n                    let cost := mul(CostPerWord, returnDataWords)\n\n                    // Then, compute cost of new memory allocation.\n                    if gt(returnDataWords, msizeWords) {\n                        cost := add(\n                            cost,\n                            add(\n                                mul(\n                                    sub(returnDataWords, msizeWords),\n                                    CostPerWord\n                                ),\n                                shr(\n                                    MemoryExpansionCoefficientShift,\n                                    sub(\n                                        mul(returnDataWords, returnDataWords),\n                                        mul(msizeWords, msizeWords)\n                                    )\n                                )\n                            )\n                        )\n                    }\n\n                    // Finally, add a small constant and compare to gas\n                    // remaining; bubble up the revert data if enough gas is\n                    // still available.\n                    if lt(add(cost, ExtraGasBuffer), gas()) {\n                        // Copy returndata to memory; overwrite existing memory.\n                        returndatacopy(0, 0, returndatasize())\n\n                        // Revert, giving memory region with copied returndata.\n                        revert(0, returndatasize())\n                    }\n                }\n\n                // Otherwise revert with a generic error message.\n\n                // Store left-padded selector with push4, mem[28:32] = selector\n                mstore(0, TokenTransferGenericFailure_error_selector)\n                mstore(TokenTransferGenericFailure_error_token_ptr, token)\n                mstore(TokenTransferGenericFailure_error_from_ptr, from)\n                mstore(TokenTransferGenericFailure_error_to_ptr, to)\n                mstore(\n                    TokenTransferGenericFailure_error_identifier_ptr,\n                    identifier\n                )\n                mstore(TokenTransferGenericFailure_error_amount_ptr, amount)\n\n                // revert(abi.encodeWithSignature(\n                //     \"TokenTransferGenericFailure(\n                //         address,address,address,uint256,uint256\n                //     )\", token, from, to, identifier, amount\n                // ))\n                revert(\n                    Generic_error_selector_offset,\n                    TokenTransferGenericFailure_error_length\n                )\n            }\n\n            mstore(Slot0x80, slot0x80) // Restore slot 0x80.\n            mstore(Slot0xA0, slot0xA0) // Restore slot 0xA0.\n            mstore(Slot0xC0, slot0xC0) // Restore slot 0xC0.\n\n            // Restore the original free memory pointer.\n            mstore(FreeMemoryPointerSlot, memPointer)\n\n            // Restore the zero slot to zero.\n            mstore(ZeroSlot, 0)\n        }\n    }\n\n    /**\n     * @dev Internal function to transfer ERC1155 tokens from a given\n     *      originator to a given recipient. Sufficient approvals must be set on\n     *      the contract performing the transfer and contract recipients must\n     *      implement the ERC1155TokenReceiver interface to indicate that they\n     *      are willing to accept the transfer. NOTE: this function is not\n     *      memory-safe; it will overwrite existing memory, restore the free\n     *      memory pointer to the default value, and overwrite the zero slot.\n     *      This function should only be called once memory is no longer\n     *      required and when uninitialized arrays are not utilized, and memory\n     *      should be considered fully corrupted (aside from the existence of a\n     *      default-value free memory pointer) after calling this function.\n     *\n     * @param batchTransfers The group of 1155 batch transfers to perform.\n     */\n    function _performERC1155BatchTransfers(\n        ConduitBatch1155Transfer[] calldata batchTransfers\n    ) internal {\n        // Utilize assembly to perform optimized batch 1155 transfers.\n        assembly {\n            let len := batchTransfers.length\n            // Pointer to first head in the array, which is offset to the struct\n            // at each index. This gets incremented after each loop to avoid\n            // multiplying by 32 to get the offset for each element.\n            let nextElementHeadPtr := batchTransfers.offset\n\n            // Pointer to beginning of the head of the array. This is the\n            // reference position each offset references. It's held static to\n            // let each loop calculate the data position for an element.\n            let arrayHeadPtr := nextElementHeadPtr\n\n            // Write the function selector, which will be reused for each call:\n            // safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\n            mstore(\n                ConduitBatch1155Transfer_from_offset,\n                ERC1155_safeBatchTransferFrom_signature\n            )\n\n            // Iterate over each batch transfer.\n            for {\n                let i := 0\n            } lt(i, len) {\n                i := add(i, 1)\n            } {\n                // Read the offset to the beginning of the element and add\n                // it to pointer to the beginning of the array head to get\n                // the absolute position of the element in calldata.\n                let elementPtr := add(\n                    arrayHeadPtr,\n                    calldataload(nextElementHeadPtr)\n                )\n\n                // Retrieve the token from calldata.\n                let token := calldataload(elementPtr)\n\n                // If the token has no code, revert.\n                if iszero(extcodesize(token)) {\n                    // Store left-padded selector with push4, mem[28:32]\n                    mstore(0, NoContract_error_selector)\n                    mstore(NoContract_error_account_ptr, token)\n\n                    // revert(abi.encodeWithSignature(\n                    //     \"NoContract(address)\", account\n                    // ))\n                    revert(\n                        Generic_error_selector_offset,\n                        NoContract_error_length\n                    )\n                }\n\n                // Get the total number of supplied ids.\n                let idsLength := calldataload(\n                    add(elementPtr, ConduitBatch1155Transfer_ids_length_offset)\n                )\n\n                // Determine the expected offset for the amounts array.\n                let expectedAmountsOffset := add(\n                    ConduitBatch1155Transfer_amounts_length_baseOffset,\n                    shl(OneWordShift, idsLength)\n                )\n\n                // Validate struct encoding.\n                let invalidEncoding := iszero(\n                    and(\n                        // ids.length == amounts.length\n                        eq(\n                            idsLength,\n                            calldataload(add(elementPtr, expectedAmountsOffset))\n                        ),\n                        and(\n                            // ids_offset == 0xa0\n                            eq(\n                                calldataload(\n                                    add(\n                                        elementPtr,\n                                        ConduitBatch1155Transfer_ids_head_offset\n                                    )\n                                ),\n                                ConduitBatch1155Transfer_ids_length_offset\n                            ),\n                            // amounts_offset == 0xc0 + ids.length*32\n                            eq(\n                                calldataload(\n                                    add(\n                                        elementPtr,\n                                        ConduitBatchTransfer_amounts_head_offset\n                                    )\n                                ),\n                                expectedAmountsOffset\n                            )\n                        )\n                    )\n                )\n\n                // Revert with an error if the encoding is not valid.\n                if invalidEncoding {\n                    // Store left-padded selector with push4, mem[28:32]\n                    mstore(\n                        Invalid1155BatchTransferEncoding_ptr,\n                        Invalid1155BatchTransferEncoding_selector\n                    )\n\n                    // revert(abi.encodeWithSignature(\n                    //     \"Invalid1155BatchTransferEncoding()\"\n                    // ))\n                    revert(\n                        Invalid1155BatchTransferEncoding_ptr,\n                        Invalid1155BatchTransferEncoding_length\n                    )\n                }\n\n                // Update the offset position for the next loop\n                nextElementHeadPtr := add(nextElementHeadPtr, OneWord)\n\n                // Copy the first section of calldata (before dynamic values).\n                calldatacopy(\n                    BatchTransfer1155Params_ptr,\n                    add(elementPtr, ConduitBatch1155Transfer_from_offset),\n                    ConduitBatch1155Transfer_usable_head_size\n                )\n\n                // Determine size of calldata required for ids and amounts. Note\n                // that the size includes both lengths as well as the data.\n                let idsAndAmountsSize := add(\n                    TwoWords,\n                    shl(TwoWordsShift, idsLength)\n                )\n\n                // Update the offset for the data array in memory.\n                mstore(\n                    BatchTransfer1155Params_data_head_ptr,\n                    add(\n                        BatchTransfer1155Params_ids_length_offset,\n                        idsAndAmountsSize\n                    )\n                )\n\n                // Set the length of the data array in memory to zero.\n                mstore(\n                    add(\n                        BatchTransfer1155Params_data_length_basePtr,\n                        idsAndAmountsSize\n                    ),\n                    0\n                )\n\n                // Determine the total calldata size for the call to transfer.\n                let transferDataSize := add(\n                    BatchTransfer1155Params_calldata_baseSize,\n                    idsAndAmountsSize\n                )\n\n                // Copy second section of calldata (including dynamic values).\n                calldatacopy(\n                    BatchTransfer1155Params_ids_length_ptr,\n                    add(elementPtr, ConduitBatch1155Transfer_ids_length_offset),\n                    idsAndAmountsSize\n                )\n\n                // Perform the call to transfer 1155 tokens.\n                let success := call(\n                    gas(),\n                    token,\n                    0,\n                    ConduitBatch1155Transfer_from_offset, // Data portion start.\n                    transferDataSize, // Location of the length of callData.\n                    0,\n                    0\n                )\n\n                // If the transfer reverted:\n                if iszero(success) {\n                    // If it returned a message, bubble it up as long as\n                    // sufficient gas remains to do so:\n                    if returndatasize() {\n                        // Ensure that sufficient gas is available to copy\n                        // returndata while expanding memory where necessary.\n                        // Start by computing word size of returndata and\n                        // allocated memory. Round up to the nearest full word.\n                        let returnDataWords := shr(\n                            OneWordShift,\n                            add(returndatasize(), ThirtyOneBytes)\n                        )\n\n                        // Note: use transferDataSize in place of msize() to\n                        // work around a Yul warning that prevents accessing\n                        // msize directly when the IR pipeline is activated.\n                        // The free memory pointer is not used here because\n                        // this function does almost all memory management\n                        // manually and does not update it, and transferDataSize\n                        // should be the largest memory value used (unless a\n                        // previous batch was larger).\n                        let msizeWords := shr(OneWordShift, transferDataSize)\n\n                        // Next, compute the cost of the returndatacopy.\n                        let cost := mul(CostPerWord, returnDataWords)\n\n                        // Then, compute cost of new memory allocation.\n                        if gt(returnDataWords, msizeWords) {\n                            cost := add(\n                                cost,\n                                add(\n                                    mul(\n                                        sub(returnDataWords, msizeWords),\n                                        CostPerWord\n                                    ),\n                                    shr(\n                                        MemoryExpansionCoefficientShift,\n                                        sub(\n                                            mul(\n                                                returnDataWords,\n                                                returnDataWords\n                                            ),\n                                            mul(msizeWords, msizeWords)\n                                        )\n                                    )\n                                )\n                            )\n                        }\n\n                        // Finally, add a small constant and compare to gas\n                        // remaining; bubble up the revert data if enough gas is\n                        // still available.\n                        if lt(add(cost, ExtraGasBuffer), gas()) {\n                            // Copy returndata to memory; overwrite existing.\n                            returndatacopy(0, 0, returndatasize())\n\n                            // Revert with memory region containing returndata.\n                            revert(0, returndatasize())\n                        }\n                    }\n\n                    // Set the error signature.\n                    mstore(\n                        0,\n                        ERC1155BatchTransferGenericFailure_error_signature\n                    )\n\n                    // Write the token.\n                    mstore(ERC1155BatchTransferGenericFailure_token_ptr, token)\n\n                    // Increase the offset to ids by 32.\n                    mstore(\n                        BatchTransfer1155Params_ids_head_ptr,\n                        ERC1155BatchTransferGenericFailure_ids_offset\n                    )\n\n                    // Increase the offset to amounts by 32.\n                    mstore(\n                        BatchTransfer1155Params_amounts_head_ptr,\n                        add(\n                            OneWord,\n                            mload(BatchTransfer1155Params_amounts_head_ptr)\n                        )\n                    )\n\n                    // Return modified region. The total size stays the same as\n                    // `token` uses the same number of bytes as `data.length`.\n                    revert(0, transferDataSize)\n                }\n            }\n\n            // Reset the free memory pointer to the default value; memory must\n            // be assumed to be dirtied and not reused from this point forward.\n            // Also note that the zero slot is not reset to zero, meaning empty\n            // arrays cannot be safely created or utilized until it is restored.\n            mstore(FreeMemoryPointerSlot, DefaultFreeMemoryPointer)\n        }\n    }\n}\n"
      },
      "contracts/lib/TokenTransferrerConstants.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\n/*\n * -------------------------- Disambiguation & Other Notes ---------------------\n *    - The term \"head\" is used as it is in the documentation for ABI encoding,\n *      but only in reference to dynamic types, i.e. it always refers to the\n *      offset or pointer to the body of a dynamic type. In calldata, the head\n *      is always an offset (relative to the parent object), while in memory,\n *      the head is always the pointer to the body. More information found here:\n *      https://docs.soliditylang.org/en/v0.8.17/abi-spec.html#argument-encoding\n *        - Note that the length of an array is separate from and precedes the\n *          head of the array.\n *\n *    - The term \"body\" is used in place of the term \"head\" used in the ABI\n *      documentation. It refers to the start of the data for a dynamic type,\n *      e.g. the first word of a struct or the first word of the first element\n *      in an array.\n *\n *    - The term \"pointer\" is used to describe the absolute position of a value\n *      and never an offset relative to another value.\n *        - The suffix \"_ptr\" refers to a memory pointer.\n *        - The suffix \"_cdPtr\" refers to a calldata pointer.\n *\n *    - The term \"offset\" is used to describe the position of a value relative\n *      to some parent value. For example, OrderParameters_conduit_offset is the\n *      offset to the \"conduit\" value in the OrderParameters struct relative to\n *      the start of the body.\n *        - Note: Offsets are used to derive pointers.\n *\n *    - Some structs have pointers defined for all of their fields in this file.\n *      Lines which are commented out are fields that are not used in the\n *      codebase but have been left in for readability.\n */\n\nuint256 constant ThirtyOneBytes = 0x1f;\nuint256 constant OneWord = 0x20;\nuint256 constant TwoWords = 0x40;\nuint256 constant ThreeWords = 0x60;\n\nuint256 constant OneWordShift = 0x5;\nuint256 constant TwoWordsShift = 0x6;\n\nuint256 constant FreeMemoryPointerSlot = 0x40;\nuint256 constant ZeroSlot = 0x60;\nuint256 constant DefaultFreeMemoryPointer = 0x80;\n\nuint256 constant Slot0x80 = 0x80;\nuint256 constant Slot0xA0 = 0xa0;\nuint256 constant Slot0xC0 = 0xc0;\n\nuint256 constant Generic_error_selector_offset = 0x1c;\n\n// abi.encodeWithSignature(\"transferFrom(address,address,uint256)\")\nuint256 constant ERC20_transferFrom_signature = (\n    0x23b872dd00000000000000000000000000000000000000000000000000000000\n);\nuint256 constant ERC20_transferFrom_sig_ptr = 0x0;\nuint256 constant ERC20_transferFrom_from_ptr = 0x04;\nuint256 constant ERC20_transferFrom_to_ptr = 0x24;\nuint256 constant ERC20_transferFrom_amount_ptr = 0x44;\nuint256 constant ERC20_transferFrom_length = 0x64; // 4 + 32 * 3 == 100\n\n// abi.encodeWithSignature(\n//     \"safeTransferFrom(address,address,uint256,uint256,bytes)\"\n// )\nuint256 constant ERC1155_safeTransferFrom_signature = (\n    0xf242432a00000000000000000000000000000000000000000000000000000000\n);\nuint256 constant ERC1155_safeTransferFrom_sig_ptr = 0x0;\nuint256 constant ERC1155_safeTransferFrom_from_ptr = 0x04;\nuint256 constant ERC1155_safeTransferFrom_to_ptr = 0x24;\nuint256 constant ERC1155_safeTransferFrom_id_ptr = 0x44;\nuint256 constant ERC1155_safeTransferFrom_amount_ptr = 0x64;\nuint256 constant ERC1155_safeTransferFrom_data_offset_ptr = 0x84;\nuint256 constant ERC1155_safeTransferFrom_data_length_ptr = 0xa4;\nuint256 constant ERC1155_safeTransferFrom_length = 0xc4; // 4 + 32 * 6 == 196\nuint256 constant ERC1155_safeTransferFrom_data_length_offset = 0xa0;\n\n// abi.encodeWithSignature(\n//     \"safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\"\n// )\nuint256 constant ERC1155_safeBatchTransferFrom_signature = (\n    0x2eb2c2d600000000000000000000000000000000000000000000000000000000\n);\n\n// bytes4 constant ERC1155_safeBatchTransferFrom_selector = bytes4(\n//     bytes32(ERC1155_safeBatchTransferFrom_signature)\n// );\n\nuint256 constant ERC721_transferFrom_signature = (\n    0x23b872dd00000000000000000000000000000000000000000000000000000000\n);\nuint256 constant ERC721_transferFrom_sig_ptr = 0x0;\nuint256 constant ERC721_transferFrom_from_ptr = 0x04;\nuint256 constant ERC721_transferFrom_to_ptr = 0x24;\nuint256 constant ERC721_transferFrom_id_ptr = 0x44;\nuint256 constant ERC721_transferFrom_length = 0x64; // 4 + 32 * 3 == 100\n\n/*\n *  error NoContract(address account)\n *    - Defined in TokenTransferrerErrors.sol\n *  Memory layout:\n *    - 0x00: Left-padded selector (data begins at 0x1c)\n *    - 0x00: account\n * Revert buffer is memory[0x1c:0x40]\n */\nuint256 constant NoContract_error_selector = 0x5f15d672;\nuint256 constant NoContract_error_account_ptr = 0x20;\nuint256 constant NoContract_error_length = 0x24;\n\n/*\n *  error TokenTransferGenericFailure(\n *      address token,\n *      address from,\n *      address to,\n *      uint256 identifier,\n *      uint256 amount\n *  )\n *    - Defined in TokenTransferrerErrors.sol\n *  Memory layout:\n *    - 0x00: Left-padded selector (data begins at 0x1c)\n *    - 0x20: token\n *    - 0x40: from\n *    - 0x60: to\n *    - 0x80: identifier\n *    - 0xa0: amount\n * Revert buffer is memory[0x1c:0xc0]\n */\nuint256 constant TokenTransferGenericFailure_error_selector = 0xf486bc87;\nuint256 constant TokenTransferGenericFailure_error_token_ptr = 0x20;\nuint256 constant TokenTransferGenericFailure_error_from_ptr = 0x40;\nuint256 constant TokenTransferGenericFailure_error_to_ptr = 0x60;\nuint256 constant TokenTransferGenericFailure_error_identifier_ptr = 0x80;\nuint256 constant TokenTransferGenericFailure_err_identifier_ptr = 0x80;\nuint256 constant TokenTransferGenericFailure_error_amount_ptr = 0xa0;\nuint256 constant TokenTransferGenericFailure_error_length = 0xa4;\n\nuint256 constant ExtraGasBuffer = 0x20;\nuint256 constant CostPerWord = 0x3;\nuint256 constant MemoryExpansionCoefficientShift = 0x9;\n\n// Values are offset by 32 bytes in order to write the token to the beginning\n// in the event of a revert\nuint256 constant BatchTransfer1155Params_ptr = 0x24;\nuint256 constant BatchTransfer1155Params_ids_head_ptr = 0x64;\nuint256 constant BatchTransfer1155Params_amounts_head_ptr = 0x84;\nuint256 constant BatchTransfer1155Params_data_head_ptr = 0xa4;\nuint256 constant BatchTransfer1155Params_data_length_basePtr = 0xc4;\nuint256 constant BatchTransfer1155Params_calldata_baseSize = 0xc4;\n\nuint256 constant BatchTransfer1155Params_ids_length_ptr = 0xc4;\n\nuint256 constant BatchTransfer1155Params_ids_length_offset = 0xa0;\n// uint256 constant BatchTransfer1155Params_amounts_length_baseOffset = 0xc0;\n// uint256 constant BatchTransfer1155Params_data_length_baseOffset = 0xe0;\n\nuint256 constant ConduitBatch1155Transfer_usable_head_size = 0x80;\n\nuint256 constant ConduitBatch1155Transfer_from_offset = 0x20;\nuint256 constant ConduitBatch1155Transfer_ids_head_offset = 0x60;\n// uint256 constant ConduitBatch1155Transfer_amounts_head_offset = 0x80;\nuint256 constant ConduitBatch1155Transfer_ids_length_offset = 0xa0;\nuint256 constant ConduitBatch1155Transfer_amounts_length_baseOffset = 0xc0;\n// uint256 constant ConduitBatch1155Transfer_calldata_baseSize = 0xc0;\n\n// Note: abbreviated version of above constant to adhere to line length limit.\nuint256 constant ConduitBatchTransfer_amounts_head_offset = 0x80;\n\nuint256 constant Invalid1155BatchTransferEncoding_ptr = 0x00;\nuint256 constant Invalid1155BatchTransferEncoding_length = 0x04;\nuint256 constant Invalid1155BatchTransferEncoding_selector = (\n    0xeba2084c00000000000000000000000000000000000000000000000000000000\n);\n\nuint256 constant ERC1155BatchTransferGenericFailure_error_signature = (\n    0xafc445e200000000000000000000000000000000000000000000000000000000\n);\nuint256 constant ERC1155BatchTransferGenericFailure_token_ptr = 0x04;\nuint256 constant ERC1155BatchTransferGenericFailure_ids_offset = 0xc0;\n\n/*\n *  error BadReturnValueFromERC20OnTransfer(\n *      address token, address from, address to, uint256 amount\n *  )\n *    - Defined in TokenTransferrerErrors.sol\n *  Memory layout:\n *    - 0x00: Left-padded selector (data begins at 0x1c)\n *    - 0x00: token\n *    - 0x20: from\n *    - 0x40: to\n *    - 0x60: amount\n * Revert buffer is memory[0x1c:0xa0]\n */\nuint256 constant BadReturnValueFromERC20OnTransfer_error_selector = 0x98891923;\nuint256 constant BadReturnValueFromERC20OnTransfer_error_token_ptr = 0x20;\nuint256 constant BadReturnValueFromERC20OnTransfer_error_from_ptr = 0x40;\nuint256 constant BadReturnValueFromERC20OnTransfer_error_to_ptr = 0x60;\nuint256 constant BadReturnValueFromERC20OnTransfer_error_amount_ptr = 0x80;\nuint256 constant BadReturnValueFromERC20OnTransfer_error_length = 0x84;\n"
      }
    },
    "settings": {
      "viaIR": true,
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}