creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/ConnectorRegistry.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.17;\n\nimport \"./base/Admin.sol\";\n\nerror ConnectorNotRegistered(address target);\n\ninterface ICustomConnectorRegistry {\n    function connectorOf(address target) external view returns (address);\n}\n\ncontract ConnectorRegistry is Admin {\n    event ConnectorChanged(address target, address connector);\n    event CustomRegistryAdded(address registry);\n    event CustomRegistryRemoved(address registry);\n\n    ICustomConnectorRegistry[] public customRegistries;\n\n    mapping(address target => address connector) private connectors_;\n\n    constructor(address admin_) Admin(admin_) { }\n\n    function setConnectors(\n        address[] calldata targets,\n        address[] calldata connectors\n    ) external onlyAdmin {\n        for (uint256 i; i != targets.length;) {\n            connectors_[targets[i]] = connectors[i];\n            emit ConnectorChanged(targets[i], connectors[i]);\n\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    function isCustomRegistry(address target) external view returns (bool) {\n        for (uint256 i; i != customRegistries.length;) {\n            if (address(customRegistries[i]) == target) {\n                return true;\n            }\n\n            unchecked {\n                ++i;\n            }\n        }\n\n        return false;\n    }\n\n    function addCustomRegistry(ICustomConnectorRegistry registry)\n        external\n        onlyAdmin\n    {\n        customRegistries.push(registry);\n        emit CustomRegistryAdded(address(registry));\n    }\n\n    function removeCustomRegistry(uint256 index) external onlyAdmin {\n        address registry = address(customRegistries[index]);\n        delete customRegistries[index];\n        emit CustomRegistryRemoved(registry);\n    }\n\n    function connectorOf(address target) external view returns (address) {\n        address connector = connectors_[target];\n        if (connector != address(0)) {\n            return connector;\n        }\n\n        for (uint256 i; i != customRegistries.length;) {\n            try customRegistries[i].connectorOf(target) returns (\n                address _connector\n            ) {\n                if (_connector != address(0)) {\n                    return _connector;\n                }\n            } catch {\n                // Ignore\n            }\n\n            unchecked {\n                ++i;\n            }\n        }\n\n        revert ConnectorNotRegistered(target);\n    }\n\n    function hasConnector(address target) external view returns (bool) {\n        if (connectors_[target] != address(0)) {\n            return true;\n        }\n\n        for (uint256 i; i != customRegistries.length;) {\n            try customRegistries[i].connectorOf(target) returns (\n                address _connector\n            ) {\n                if (_connector != address(0)) {\n                    return true;\n                }\n            } catch {\n                // Ignore\n            }\n\n            unchecked {\n                ++i;\n            }\n        }\n\n        return false;\n    }\n}\n"
      },
      "contracts/base/Admin.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.17;\n\n/// @title Admin contract\n/// @author vfat.tools\n/// @notice Provides an administration mechanism allowing restricted functions\nabstract contract Admin {\n    /// ERRORS ///\n\n    /// @notice Thrown when the caller is not the admin\n    error NotAdminError(); //0xb5c42b3b\n\n    /// EVENTS ///\n\n    /// @notice Emitted when a new admin is set\n    /// @param oldAdmin Address of the old admin\n    /// @param newAdmin Address of the new admin\n    event AdminSet(address oldAdmin, address newAdmin);\n\n    /// STORAGE ///\n\n    /// @notice Address of the current admin\n    address public admin;\n\n    /// MODIFIERS ///\n\n    /// @dev Restricts a function to the admin\n    modifier onlyAdmin() {\n        if (msg.sender != admin) revert NotAdminError();\n        _;\n    }\n\n    /// WRITE FUNCTIONS ///\n\n    /// @param admin_ Address of the admin\n    constructor(address admin_) {\n        emit AdminSet(admin, admin_);\n        admin = admin_;\n    }\n\n    /// @notice Sets a new admin\n    /// @dev Can only be called by the current admin\n    /// @param newAdmin Address of the new admin\n    function setAdmin(address newAdmin) external onlyAdmin {\n        emit AdminSet(admin, newAdmin);\n        admin = newAdmin;\n    }\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "solmate/=lib/solmate/src/",
        "@openzeppelin/=lib/openzeppelin-contracts/",
        "@uniswap/v3-periphery/=lib/v3-periphery/",
        "@uniswap/v3-core/=lib/v3-core/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "forge-std/=lib/forge-std/src/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "paris",
      "viaIR": false,
      "libraries": {}
    }
  }}