creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    /// @custom:storage-location erc7201:openzeppelin.storage.Ownable\n    struct OwnableStorage {\n        address _owner;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Ownable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;\n\n    function _getOwnableStorage() private pure returns (OwnableStorage storage $) {\n        assembly {\n            $.slot := OwnableStorageLocation\n        }\n    }\n\n    /**\n     * @dev The caller account is not authorized to perform an operation.\n     */\n    error OwnableUnauthorizedAccount(address account);\n\n    /**\n     * @dev The owner is not a valid owner account. (eg. `address(0)`)\n     */\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n     */\n    function __Ownable_init(address initialOwner) internal onlyInitializing {\n        __Ownable_init_unchained(initialOwner);\n    }\n\n    function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {\n        if (initialOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(initialOwner);\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        OwnableStorage storage $ = _getOwnableStorage();\n        return $._owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        if (owner() != _msgSender()) {\n            revert OwnableUnauthorizedAccount(_msgSender());\n        }\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        OwnableStorage storage $ = _getOwnableStorage();\n        address oldOwner = $._owner;\n        $._owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Storage of the initializable contract.\n     *\n     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n     * when using with upgradeable contracts.\n     *\n     * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n     */\n    struct InitializableStorage {\n        /**\n         * @dev Indicates that the contract has been initialized.\n         */\n        uint64 _initialized;\n        /**\n         * @dev Indicates that the contract is in the process of being initialized.\n         */\n        bool _initializing;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n    /**\n     * @dev The contract is already initialized.\n     */\n    error InvalidInitialization();\n\n    /**\n     * @dev The contract is not initializing.\n     */\n    error NotInitializing();\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint64 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n     * production.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        // Cache values to avoid duplicated sloads\n        bool isTopLevelCall = !$._initializing;\n        uint64 initialized = $._initialized;\n\n        // Allowed calls:\n        // - initialSetup: the contract is not in the initializing state and no previous version was\n        //                 initialized\n        // - construction: the contract is initialized at version 1 (no reininitialization) and the\n        //                 current contract is just being deployed\n        bool initialSetup = initialized == 0 && isTopLevelCall;\n        bool construction = initialized == 1 && address(this).code.length == 0;\n\n        if (!initialSetup && !construction) {\n            revert InvalidInitialization();\n        }\n        $._initialized = 1;\n        if (isTopLevelCall) {\n            $._initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            $._initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint64 version) {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing || $._initialized >= version) {\n            revert InvalidInitialization();\n        }\n        $._initialized = version;\n        $._initializing = true;\n        _;\n        $._initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        _checkInitializing();\n        _;\n    }\n\n    /**\n     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n     */\n    function _checkInitializing() internal view virtual {\n        if (!_isInitializing()) {\n            revert NotInitializing();\n        }\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing) {\n            revert InvalidInitialization();\n        }\n        if ($._initialized != type(uint64).max) {\n            $._initialized = type(uint64).max;\n            emit Initialized(type(uint64).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint64) {\n        return _getInitializableStorage()._initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _getInitializableStorage()._initializing;\n    }\n\n    /**\n     * @dev Returns a pointer to the storage namespace.\n     */\n    // solhint-disable-next-line var-name-mixedcase\n    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n        assembly {\n            $.slot := INITIALIZABLE_STORAGE\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal onlyInitializing {\n    }\n\n    function __Context_init_unchained() internal onlyInitializing {\n    }\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
      },
      "contracts/interfaces/IFlashloanHandler.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.7.0 <0.9.0;\n\ninterface IFlashloanHandler {\n  function execFlashloan(\n    address[] calldata assetToFlashloan,\n    uint[] calldata amount,\n    bytes calldata data\n  ) external returns (bool);\n}\n"
      },
      "contracts/interfaces/IRegistry.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport './ISafe.sol';\n\ninterface IRegistry {\n  function userSafes(address) external view returns (address);\n\n  function handlers(address) external view returns (bytes32);\n\n  function callers(address) external view returns (bytes32);\n\n  function bannedAgents(address) external view returns (uint256);\n\n  function fHalt() external view returns (bool);\n\n  function isValidHandler(address handler) external view returns (bool);\n\n  function isValidCaller(address handler) external view returns (bool);\n\n  function registerSafeForUser(ISafe safe, address user) external;\n}\n"
      },
      "contracts/interfaces/ISafe.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.7.0 <0.9.0;\n\nimport '../utils/Enum.sol';\n\ninterface ISafe {\n  event EnabledModule(address module);\n  event DisabledModule(address module);\n  event ExecutionFromModuleSuccess(address indexed module);\n  event ExecutionFromModuleFailure(address indexed module);\n\n  /// @dev Enables a module on the safe\n  /// @notice Can only be called by the safe\n  /// @notice Modules should be stored as a linked list.\n  /// @notice Must emit EnabledModule(address module) if successful.\n  /// @param module Module to be enabled.\n  function enableModule(address module) external;\n\n  /// @dev Disables a module on the safe\n  /// @notice Can only be called by the safe\n  /// @notice Must emit DisabledModule(address module) if successful.\n  /// @param prevModule Address that pointed to the module to be removed in the linked list\n  /// @param module Module to be removed.\n  function disableModule(address prevModule, address module) external;\n\n  /// @dev Allows a Module to execute a transaction.\n  /// @notice Can only be called by an enabled module.\n  /// @notice Must emit ExecutionFromModuleSuccess(address module) if successful.\n  /// @notice Must emit ExecutionFromModuleFailure(address module) if unsuccessful.\n  /// @param to Destination address of module transaction.\n  /// @param value Ether value of module transaction.\n  /// @param data Data payload of module transaction.\n  /// @param operation Operation type of module transaction: 0 == call, 1 == delegate call.\n  function execTransactionFromModule(\n    address to,\n    uint256 value,\n    bytes memory data,\n    Enum.Operation operation\n  ) external returns (bool success);\n\n  /// @dev Allows a Module to execute a transaction and return data\n  /// @notice Can only be called by an enabled module.\n  /// @notice Must emit ExecutionFromModuleSuccess(address module) if successful.\n  /// @notice Must emit ExecutionFromModuleFailure(address module) if unsuccessful.\n  /// @param to Destination address of module transaction.\n  /// @param value Ether value of module transaction.\n  /// @param data Data payload of module transaction.\n  /// @param operation Operation type of module transaction: 0 == call, 1 == delegate call.\n  function execTransactionFromModuleReturnData(\n    address to,\n    uint256 value,\n    bytes memory data,\n    Enum.Operation operation\n  ) external returns (bool success, bytes memory returnData);\n\n  /// @dev Returns if an module is enabled\n  /// @return True if the module is enabled\n  function isModuleEnabled(address module) external view returns (bool);\n\n  /// @dev Returns array of modules.\n  /// @param start Start of the page.\n  /// @param pageSize Maximum number of modules that should be returned.\n  /// @return array Array of modules.\n  /// @return next Start of the next page.\n  function getModulesPaginated(\n    address start,\n    uint256 pageSize\n  ) external view returns (address[] memory array, address next);\n\n  function getOwners() external view returns (address[] memory);\n}\n"
      },
      "contracts/modules/BaseModule.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\n/// @title Module Interface - A contract that can pass messages and execute transactions to a Safe contract if enabled by that contract.\npragma solidity ^0.8.20;\n\nimport '../utils/Enum.sol';\nimport '../interfaces/ISafe.sol';\nimport './ModuleStorage.sol';\n\nimport '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';\n\n/**\n * @title BaseModule\n * @dev Base contract for modules in the Lucidity v1 protocol.\n */\ncontract BaseModule is ModuleStorage {\n  /**\n   * @dev Executes a transaction on a target contract.\n   * @param to The address of the target contract.\n   * @param value The amount of Ether to send with the transaction.\n   * @param data The data payload for the transaction.\n   * @param operation The operation type for the transaction (e.g., CALL, DELEGATECALL, etc.).\n   * @param safe The instance of the Safe contract.\n   * @return success A boolean indicating the success of the transaction.\n   * @return returnData The return data of the transaction.\n   */\n  function _execTx(\n    address to,\n    uint256 value,\n    bytes memory data,\n    Enum.Operation operation,\n    ISafe safe\n  ) internal returns (bool success, bytes memory returnData) {\n    _checkTransaction(to, safe, msg.sender);\n\n    (success, returnData) = safe.execTransactionFromModuleReturnData(\n      to,\n      value,\n      data,\n      operation\n    );\n    if (success == false) {\n      _revert(returnData);\n    }\n  }\n\n  /**\n   * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n   */\n  function _revert(bytes memory returndata) private pure {\n    // Look for revert reason and bubble it up if present\n    if (returndata.length > 0) {\n      // The easiest way to bubble the revert reason is using memory via assembly\n      /// @solidity memory-safe-assembly\n      assembly {\n        let returndata_size := mload(returndata)\n        revert(add(32, returndata), returndata_size)\n      }\n    } else {\n      revert('Batch call failed');\n    }\n  }\n\n  /**  @dev Guard transactions only use the first four parameters: to, value, data, and operation.\n   *  Guard.sol hardcodes the remaining parameters as 0 since they are not used for guard transactions.\n   *  @notice This interface is used to maintain compatibilty with Gnosis Safe transaction guards.\n   */\n  function _checkTransaction(\n    address to,\n    ISafe safe,\n    address originalSender\n  ) internal view {\n    // Check if originalSender is the owner of the safe.\n    _checkIfValidCaller(originalSender, safe);\n\n    // Check if to is the whitelisted address via registry.\n    _checkIfValidTarget(to, safe);\n  }\n\n  /**\n   * @dev Checks if the originalSender is the owner of the safe or a whitelisted caller in the registry.\n   * @param originalSender The original sender of the transaction.\n   * @param safe The instance of the Safe contract.\n   */\n  function _checkIfValidCaller(\n    address originalSender,\n    ISafe safe\n  ) internal view {\n    MainStorage storage mainStorage = _getMainStorage();\n\n    bool isOwner = address(\n      mainStorage.lucidityRegistry.userSafes(originalSender)\n    ) == address(safe);\n\n    bool isValidCaller = mainStorage.lucidityRegistry.isValidCaller(\n      originalSender\n    );\n\n    require(isOwner || isValidCaller, 'Invalid callers');\n  }\n\n  /**\n   * @dev Checks if the target is a whitelisted address in the registry.\n   * @param target The address of the target. Example: AaveLendingPool, or any other contract that safe will send transaction to.\n   * @notice The purpose of this function is to control contracts to which safe can send the transaction.\n   */\n  function _checkIfValidTarget(address target, ISafe safe) internal view {\n    MainStorage storage mainStorage = _getMainStorage();\n    require(target != address(0), 'zero address');\n\n    bool isValidTarget;\n\n    if (\n      address(mainStorage.lucidityRegistry.userSafes(target)) == address(safe)\n    ) {\n      isValidTarget = true;\n    } else if ((address(safe) == target)) {\n      isValidTarget = true;\n    } else if (mainStorage.lucidityRegistry.isValidHandler(target) == true) {\n      isValidTarget = true;\n    }\n\n    require(isValidTarget, 'Invalid handler.');\n  }\n\n  /**\n   * @notice Returns true if `account` is a contract.\n   * @dev This function will return false if invoked during the constructor of a contract,\n   *      as the code is not actually created until after the constructor finishes.\n   * @param account The address being queried\n   * @return True if `account` is a contract\n   */\n  function _isContract(address account) internal view returns (bool) {\n    uint256 size;\n    /* solhint-disable no-inline-assembly */\n    /// @solidity memory-safe-assembly\n    assembly {\n      size := extcodesize(account)\n    }\n    /* solhint-enable no-inline-assembly */\n    return size > 0;\n  }\n}\n"
      },
      "contracts/modules/LucidityModule.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\n/// @title Core Lucidity Module\n\npragma solidity ^0.8.20;\n\nimport './BaseModule.sol';\nimport './ModuleStorage.sol';\n\nimport '../interfaces/IRegistry.sol';\nimport '../interfaces/IFlashloanHandler.sol';\nimport '../interfaces/ISafe.sol';\n\nimport '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';\n\ncontract LucidityModule is ModuleStorage, BaseModule, OwnableUpgradeable {\n  event LucidityRegistryUpdated(address _lucidityRegistry);\n  event DisabledFlashloanHandler(address _flashLoanHandler);\n  event EnabledFlashloanHandler(address _flashLoanHandler);\n\n  constructor() {\n    _disableInitializers();\n  }\n\n  /**\n   * @notice Initializer for the BaseModule\n   * @param _owner The owner of the Module Singleton.\n   * @param _registry The address of the Lucidity registry\n   */\n  function initialize(address _registry, address _owner) public initializer {\n    MainStorage storage mainStorage = _getMainStorage();\n    __Ownable_init(_owner);\n    mainStorage.LUCIDITY_MODULE_SINGLETON = address(this);\n    mainStorage.lucidityRegistry = IRegistry(_registry);\n  }\n\n  // Can only be called as delegatecall from a GnosisSafe during setup.\n  function enableModule(\n    address module,\n    address registry,\n    address owner\n  ) external {\n    MainStorage storage mainStorage = _getMainStorage();\n    require(\n      _isContract(address(this)),\n      'enableModule should only be called via smartcontract'\n    );\n    require(\n      address(this) != mainStorage.LUCIDITY_MODULE_SINGLETON,\n      'enableModule should only be called via delegatecall'\n    );\n    // Enable Module\n    ISafe((address(this))).enableModule(module);\n\n    // Register the safe for the user.\n    IRegistry(registry).registerSafeForUser(ISafe((address(this))), owner);\n\n    // event is emitted by the safe.\n  }\n\n  /** @dev Passes a transaction to be executed by the safe.\n   * @notice Can only be called by this contract.\n   * @param tos Destination address of module transaction.\n   * @param values Ether value of module transaction.\n   * @param datas Data payload of module transaction.\n   * @param operations Operation type of module transaction: 0 == call, 1 == delegate call.\n   * @param safe address that will be used to execute the module transactions.\n   */\n  function exec(\n    address[] calldata tos,\n    uint256[] calldata values,\n    bytes[] memory datas,\n    Enum.Operation[] calldata operations,\n    ISafe safe\n  ) external payable {\n    require(tos.length == values.length, 'Tos and values length inconsistent');\n    require(tos.length == datas.length, 'Tos and datas length inconsistent');\n    require(\n      tos.length == operations.length,\n      'Tos and operations length inconsistent'\n    );\n    // First transfer the eth to safe if there is any msg.value sent with the tx.\n    if (msg.value > 0) {\n      (bool sent, ) = address(safe).call{value: msg.value}('');\n      require(sent, 'Failed to send Ether');\n    }\n    for (uint256 i = 0; i < tos.length; i++) {\n      _execTx(tos[i], values[i], datas[i], operations[i], safe);\n    }\n  }\n\n  /** @dev Passes a transaction to be executed by the target and returns data.\n   * @notice Can only be called by this contract.\n   * @param tos Destination address of module transaction.\n   * @param values Ether value of module transaction.\n   * @param datas Data payload of module transaction.\n   * @param operations Operation type of module transaction: 0 == call, 1 == delegate call.\n   * @param safe address that will be used to execute the module transactions.\n   */\n  function execAndReturnData(\n    address[] calldata tos,\n    uint256[] calldata values,\n    bytes[] memory datas,\n    Enum.Operation[] calldata operations,\n    ISafe safe\n  )\n    external\n    payable\n    returns (bool[] memory successes, bytes[] memory returnDatas)\n  {\n    require(tos.length == values.length, 'Tos and values length inconsistent');\n    require(tos.length == datas.length, 'Tos and datas length inconsistent');\n    require(\n      tos.length == operations.length,\n      'Tos and operations length inconsistent'\n    );\n    // First transfer the eth to safe if there is any msg.value sent with the tx.\n    if (msg.value > 0) {\n      (bool sent, ) = address(safe).call{value: msg.value}('');\n      require(sent, 'Failed to send Ether');\n    }\n    for (uint256 i = 0; i < tos.length; i++) {\n      (successes[i], returnDatas[i]) = _execTx(\n        tos[i],\n        values[i],\n        datas[i],\n        operations[i],\n        safe\n      );\n    }\n  }\n\n  /**\n   * @notice Executes a flashloan\n   * @param flashloanHandler The flashloan handler contract address\n   * @param assetsToFlashloan The assets to flashloan\n   * @param amountsToFlashloan The amounts to flashloan\n   * @param dataToExecute The data to execute -  abi.encode(tos, values, datas, operations, safe);\n   */\n  function execFlashloan(\n    IFlashloanHandler flashloanHandler,\n    address[] calldata assetsToFlashloan,\n    uint[] calldata amountsToFlashloan,\n    bytes calldata dataToExecute\n  ) external {\n    MainStorage storage mainStorage = _getMainStorage();\n\n    require(\n      mainStorage.flashLoanHandlers[flashloanHandler] == true,\n      'Invalid flashloan handler'\n    );\n    require(\n      assetsToFlashloan.length == amountsToFlashloan.length,\n      'Invalid lengths'\n    );\n\n    (, , , , ISafe safe) = abi.decode(\n      dataToExecute,\n      (address[], uint256[], bytes[], Enum.Operation[], ISafe)\n    );\n\n    // Check if the caller is the safe owner\n    _checkIfValidCaller(msg.sender, safe);\n\n    bytes memory data = abi.encode(dataToExecute, msg.sender);\n\n    require(\n      flashloanHandler.execFlashloan(\n        assetsToFlashloan,\n        amountsToFlashloan,\n        data\n      ) == true\n    );\n  }\n\n  // Admin Functions\n\n  /**\n   * @notice Enables a flashloan handler\n   * @param _flashLoanHandler The flashloan handler\n   * @dev Can only be called by the owner\n   * @dev Emits an event\n   */\n  function enableFlashloanHandler(\n    IFlashloanHandler _flashLoanHandler\n  ) public onlyOwner {\n    MainStorage storage mainStorage = _getMainStorage();\n    mainStorage.flashLoanHandlers[_flashLoanHandler] = true;\n    emit EnabledFlashloanHandler(address(_flashLoanHandler));\n  }\n\n  /**\n   * @notice Disables a flashloan handler\n   * @param _flashLoanHandler The flashloan handler\n   * @dev Can only be called by the owner\n   * @dev Emits an event\n   */\n  function disableFlashloanHandler(\n    IFlashloanHandler _flashLoanHandler\n  ) public onlyOwner {\n    MainStorage storage mainStorage = _getMainStorage();\n    mainStorage.flashLoanHandlers[_flashLoanHandler] = false;\n    emit DisabledFlashloanHandler(address(_flashLoanHandler));\n  }\n\n  /** \n  @notice Return the status of a flashloan handler\n  @param _flashLoanHandler The flashloan handler\n  */\n  function isFlashloanHandlerEnabled(\n    IFlashloanHandler _flashLoanHandler\n  ) public view returns (bool) {\n    return _getMainStorage().flashLoanHandlers[_flashLoanHandler];\n  }\n\n  /**\n   * @notice Sets the lucidity registry\n   * @param _registryAddress The Lucidity Registry\n   * @dev Can only be called by the owner\n   * @dev Emits an event\n   */\n  function setLucidityRegistry(address _registryAddress) public onlyOwner {\n    MainStorage storage mainStorage = _getMainStorage();\n    mainStorage.lucidityRegistry = IRegistry(_registryAddress);\n    emit LucidityRegistryUpdated(address(_registryAddress));\n  }\n\n  /**\n   * @notice Gets the lucidity registry.\n   */\n  function getLucidityRegistry() public view returns (IRegistry) {\n    return _getMainStorage().lucidityRegistry;\n  }\n\n  /**\n   * @notice Gets the flashloan handlers\n   */\n  function getLucidityModule() public view returns (address) {\n    return _getMainStorage().LUCIDITY_MODULE_SINGLETON;\n  }\n}\n"
      },
      "contracts/modules/ModuleStorage.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport '../interfaces/IFlashloanHandler.sol';\nimport '../interfaces/IRegistry.sol';\n\ncontract ModuleStorage {\n  // keccak256(abi.encode(uint256(keccak256('modulestorage.main')) - 1)) & ~bytes32(uint256(0xff));\n  bytes32 private constant MAIN_STORAGE_LOCATION =\n    0x5343796fba3ac3e19f4e5aac935ab1fa90ab94423c688107250cc7fdfcce2900;\n\n  /// @custom:storage-location erc7201:<LucidityModule>\n  struct MainStorage {\n    address LUCIDITY_MODULE_SINGLETON;\n    IRegistry lucidityRegistry;\n    mapping(IFlashloanHandler => bool) flashLoanHandlers;\n  }\n\n  function _getMainStorage() internal pure returns (MainStorage storage $) {\n    assembly {\n      $.slot := MAIN_STORAGE_LOCATION\n    }\n  }\n}\n"
      },
      "contracts/utils/Enum.sol": {
        "content": "// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.7.0 <0.9.0;\n\n/**\n * @title Enum - Collection of enums used in Safe contracts.\n * @author Richard Meissner - @rmeissner\n */\nabstract contract Enum {\n  enum Operation {\n    Call,\n    DelegateCall,\n    Flashloan\n  }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 400
      },
      "evmVersion": "paris",
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}