diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..f0f08f0 --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +USER_ADDRESS= +PRIVATE_KEY= diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 902da10..e2c31ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: python-version: [ - "3.8", "3.9", "3.10", "3.11", "3.12", + "3.10", "3.11", "3.12", ] timeout-minutes: 10 steps: @@ -32,6 +32,10 @@ jobs: cache: poetry cache-dependency-path: poetry.lock + - name: Poetry lock + run: | + poetry lock + - name: Install dependencies run: | poetry install diff --git a/.github/workflows/ci_core.yml b/.github/workflows/ci_core.yml deleted file mode 100644 index 4b77f85..0000000 --- a/.github/workflows/ci_core.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: CI libs/core - -on: - pull_request: - paths: - - '.github/workflows/python_reusable.yml' - - '.github/workflows/ci_base.yml' - - 'cow_py/**' - - 'tests/**' - workflow_dispatch: # Allows to trigger the workflow manually in GitHub UI - -jobs: - ci-libs-core: - uses: - ./.github/workflows/python_reusable.yml - with: - working-directory: ./ - secrets: inherit diff --git a/.github/workflows/python_reusable.yml b/.github/workflows/python_reusable.yml deleted file mode 100644 index 975d6f1..0000000 --- a/.github/workflows/python_reusable.yml +++ /dev/null @@ -1,64 +0,0 @@ ---- -name: Reusable Python library CI - -on: - workflow_call: - inputs: - working-directory: - required: true - type: string - description: "From which folder this pipeline executes" - install-packages: - description: "Space seperated list of packages to install using apt-get." - default: "" - type: string - # To avoid being billed 360 minutes if a step does not terminate - # (we've seen the setup-python step below do so!) - ci-timeout: - description: "The timeout of the ci job. Default is 25min" - default: 25 - type: number - -jobs: - local-ci-py-template: - runs-on: ubuntu-22.04 - timeout-minutes: 30 - - defaults: - run: - working-directory: ${{ inputs.working-directory }} - - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Setup Python - uses: actions/setup-python@v4 - timeout-minutes: 5 - with: - python-version-file: ${{ github.workspace }}/.python-version - cache: "pip" - cache-dependency-path: | - dev-requirements.txt - pip-requirements.txt - ${{ inputs.working-directory }}/requirements.txt - - - name: Install extra packages - if: ${{ inputs.install-packages != ''}} - run: | - sudo apt-get install -y ${{ inputs.install-packages }} - - - name: Install Python dependencies - run: | - pip install -r "$(git rev-parse --show-toplevel)/pip-requirements.txt" - pip install -r "$(git rev-parse --show-toplevel)/dev-requirements.txt" -r requirements.txt - - - name: Typecheck - run: | - pyright . - - - name: Test - run: | - python3 -m pytest tests/ # Assume that tests are in folder "tests/" diff --git a/.github/workflows/top_level.yml b/.github/workflows/top_level.yml deleted file mode 100644 index e92818d..0000000 --- a/.github/workflows/top_level.yml +++ /dev/null @@ -1,54 +0,0 @@ ---- -name: Top-level CI -on: - workflow_dispatch: - pull_request: - push: - branches: main # Comment this line if you want to test the CI before opening a PR - -jobs: - ci-global: - runs-on: ubuntu-22.04 - timeout-minutes: 10 - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup Python - uses: actions/setup-python@v4 - timeout-minutes: 5 - with: - python-version-file: .python-version - cache: 'pip' - cache-dependency-path: | - pip-requirements.txt - dev-requirements.txt - - - name: Install Python dependencies - run: | - pip install -r pip-requirements.txt - pip install -r dev-requirements.txt - - # in order to test the template as well, we create a temporary library in the CI - - name: Create library with template - run: | - cookiecutter --no-input templates/pylibrary --output-dir libs/ - git add libs/library_name # So that checks below apply to generated library - - - name: Format Python imports - run: | - isort --check-only $(git ls-files "*.py") - - - name: Format Python - run: | - black --check $(git ls-files "*.py") - - - name: Lint Python - run: | - flake8 $(git ls-files "*.py") - - # Are all public symbols documented? (see top-level pyproject.toml configuration) - - name: Lint Python doc - run: | - pylint $(git ls-files "*.py") diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 704b21f..0710f6a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,9 +1,10 @@ repos: -- repo: https://github.com/astral-sh/ruff-pre-commit - # Ruff version. - rev: v0.1.4 - hooks: - # Run the linter. - - id: ruff - # Run the formatter. - - id: ruff-format + - repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.3.7 + hooks: + # Run the linter. + - id: ruff + args: [--fix] + # Run the formatter. + - id: ruff-format diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..21ed7dc --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +.PHONY: codegen web3_codegen orderbook_codegen subgraph_codegen test lint format remove_unused_imports + +codegen: web3_codegen orderbook_codegen subgraph_codegen + +# web3_codegen: +# poetry run web3_codegen + +orderbook_codegen: + poetry run datamodel-codegen --url="https://raw.githubusercontent.com/cowprotocol/services/v2.245.1/crates/orderbook/openapi.yml" --output cow_py/order_book/generated/model.py --target-python-version 3.12 --output-model-type pydantic_v2.BaseModel --input-file-type openapi + +subgraph_codegen: + poetry run ariadne-codegen + +test: + poetry run pytest -s + +lint: + poetry run ruff check . --fix + +format: remove_unused_imports + poetry run ruff format + +remove_unused_imports: + poetry run pycln --all . + +typecheck: + poetry run pyright \ No newline at end of file diff --git a/README.md b/README.md index 394783e..d81ba0d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -# cow-py - -CoW Protocol Python SDK +# CoW Protocol Python SDK [Help the herd 🐮](https://snapshot.org/#/cowgrants.eth/proposal/0x29bde0a0789a15f2255e11bdff088b4ffdf491729250dbe93b8b0776beb7f999) @@ -10,7 +8,7 @@ Welcome to the CoW Protocol Python SDK (cow_py), a developer-friendly Python lib ## 🐄 Features -- Querying CoW Protocol subgraphs. +- Querying CoW Protocol subgraph. - Managing orders on the CoW Protocol. - Interacting with CoW Protocol smart contracts. - Encoding orders metadata and pinning to CID. @@ -29,14 +27,14 @@ pip install cow_py Here's a simple example to get your hooves dirty: ```python -# TODO: this code is aspirational, this API doesn't exist -from cow_py.order_book import OrderBook -# Initialize the OrderBook -order_book = OrderBook() +from cow_py.order_book.api import OrderBookApi, UID + +# Initialize the OrderBookApi +order_book_api = OrderBookApi() # Fetch and display orders -orders = order_book.get_orders() +orders = order_book.get_order_by_uid(UID("0x...")) print(orders) ``` @@ -46,19 +44,47 @@ print(orders) - `contracts/`(TODO): A pasture of Smart contract ABIs for interaction. - `order_book/`(TODO): Functions to wrangle orders on the CoW Protocol. - `order_signing/`(TODO): Tools for signing and validating orders. Anything inside this module should use higher level modules, and the process of actually signing (ie. calling the web3 function to generate the signature, should be handled in contracts, not here). -- `subgraphs/`(WIP): GraphQL clients for querying CoW Protocol data. +- `subgraph/`(WIP): GraphQL client for querying CoW Protocol's Subgraph. - `web3/`: Web3 providers for blockchain interactions. ## 🐄 How to Use -### Querying the Subgraph (WIP) +### Querying the Subgraph + +Using the built-in GraphQL client, you can query the CoW Protocol's Subgraph to get real-time data on the CoW Protocol. You can query the Subgraph by using the `SubgraphClient` class and passing in the URL of the Subgraph. ```python -from cow_py.subgraphs.queries import TotalsQuery +from cow_py.subgraph.client import SubgraphClient + +url = build_subgraph_url() # Default network is Chain.MAINNET and env SubgraphEnvironment.PRODUCTION +client = SubgraphClient(url=url) -totals_query = TotalsQuery() -totals = await totals_query.execute() -print(totals) +# Fetch the total supply of the CoW Protocol, defined in a query in cow_py/subgraph/queries +totals = await client.totals() +print(totals) # Pydantic model, defined in cow_py/subgraph/graphql_client/{query_name}.py +``` + +Or you can leverage `SubgraphClient` to use a custom query and get the results as JSON: + +```python +from pprint import pprint +from cow_py.subgraph.client import SubgraphClient + +url = build_subgraph_url() # Default network is Chain.MAINNET and env SubgraphEnvironment.PRODUCTION +client = SubgraphClient(url=url) + +response = await client.execute(query=""" + query LastDaysVolume($days: Int!) { + dailyTotals(orderBy: timestamp, orderDirection: desc, first: $days) { + timestamp + volumeUsd + } + } + """, variables=dict(days=2) + ) + +data = client.get_data(response) +pprint(data) ``` ### Signing an Order (TODO) @@ -77,6 +103,34 @@ signed_order = sign_order(order_details, private_key="your_private_key") print(signed_order) ``` +## 🐄 Development + +### 🐄 Tests + +Run tests to ensure everything's working: + +```bash +make test # or poetry run pytest +``` + +### 🐄 Formatting/Linting + +Run the formatter and linter: + +```bash +make format # or ruff check . --fix +make lint # or ruff format +``` + +### 🐄 Codegen + +Generate the SDK from the CoW Protocol smart contracts, Subgraph, and Orderbook API: + +```bash +make codegen +``` + + ## 🐄 Contributing to the Herd Interested in contributing? Here's how you can help: diff --git a/cow_py/codegen/__init__.py b/cow_py/codegen/__init__.py new file mode 100644 index 0000000..00b8a0b --- /dev/null +++ b/cow_py/codegen/__init__.py @@ -0,0 +1,5 @@ +from .abi_handler import ABIHandler + +__all__ = [ + "ABIHandler", +] diff --git a/cow_py/codegen/abi_handler.py b/cow_py/codegen/abi_handler.py new file mode 100644 index 0000000..0bcac52 --- /dev/null +++ b/cow_py/codegen/abi_handler.py @@ -0,0 +1,265 @@ +import importlib.resources +import re +from typing import Any, Dict, List + +from pybars import Compiler + +from cow_py.codegen.components import templates +from cow_py.codegen.components.abi_loader import FileAbiLoader +from cow_py.codegen.components.templates import partials +from cow_py.codegen.solidity_converter import SolidityConverter + +CAMEL_TO_SNAKE_REGEX = re.compile( + r"(?<=[a-z0-9])(?=[A-Z])|" # Lowercase or digit to uppercase + r"(?<=[A-Z])(?=[A-Z][a-z])|" # Uppercase to uppercase followed by lowercase + r"(?<=[A-Za-z])(?=[0-9])|" # Letter to digit + r"(?<=[0-9])(?=[A-Z])" # Digit to uppercase +) + + +def compile_partial(partial_path: str) -> str: + with open(partial_path, "r") as file: + partial = file.read() + compiler = Compiler() + return compiler.compile(partial) + + +def get_filename_without_extension(path: str): + """ + Returns the a filename from the path, without the extension. + """ + return path.split("/")[-1].split(".")[0] + + +def to_python_conventional_name(name: str) -> str: + """Converts a camelCase or PascalCase name to a snake_case name.""" + if name.isupper(): + return name.lower() + + return CAMEL_TO_SNAKE_REGEX.sub("_", name).lower() + + +def _get_template_file() -> str: + pkg_files = importlib.resources.files(templates) + return str(next(x for x in pkg_files.iterdir() if x.suffix == ".hbs")) # type: ignore + + +def _get_partials_files() -> str: + pkg_files = importlib.resources.files(partials) + return [str(x) for x in pkg_files.iterdir() if x.suffix == ".hbs"] # type: ignore + + +class ABIHandlerError(Exception): + """Raised when an error occurs in the ABI handler.""" + + pass + + +class ABIHandler: + """ + Handles the generation of Python classes and methods from Ethereum contract ABIs. + + This class reads the ABI of a contract, processes its contents, and generates Python code that mirrors + the contract's functions and data structures. + + Attributes: + contract_name (str): Name of the contract, used for generating class names. + abi_file_path (str): Path to the ABI JSON file of the contract. + + Methods: + generate: Main method to generate Python code from the ABI.. + """ + + def __init__(self, contract_name: str, abi_file_path: str): + self.contract_name = contract_name + self.abi_file_path = abi_file_path + + def generate(self) -> str: + """ + Generates Python code representing the contract's ABI. + + This method processes the ABI file, extracting information about functions, + input/output arguments, enums, and data structures. It then uses this information + to generate corresponding Python classes and methods. + + Returns: + str: The generated Python code as a string. + + Raises: + ABIHandlerError: If an error occurs during ABI processing or code generation. + """ + try: + template_data = self._prepare_template_data() + return self._render_template(template_data) + except Exception as e: + raise ABIHandlerError(f"Error generating code: {str(e)}") from e + + def _prepare_template_data(self) -> Dict[str, Any]: + """ + Prepares data for the template rendering based on the contract's ABI. + + This method processes the ABI to extract relevant information for generating + Python code, such as methods, data classes, and enums. + + Returns: + Dict[str, Any]: A dictionary containing the structured data for rendering. + + Raises: + ABIHandlerError: If an error occurs during ABI processing. + """ + try: + methods, data_classes, enums = [], [], [] + generated_structs, generated_enums = set(), set() + + abi = FileAbiLoader(self.abi_file_path).load_abi() + + for item in abi: + if item["type"] == "function": + methods.append(self._process_function(item)) + for param in item["inputs"] + item.get("outputs", []): + self._process_parameters( + param, + data_classes, + enums, + generated_structs, + generated_enums, + ) + elif item["type"] == "event": + for param in item["inputs"]: + self._process_parameters( + param, + data_classes, + enums, + generated_structs, + generated_enums, + ) + + return { + "abiPath": self.abi_file_path, + "contractName": self.contract_name, + "methods": methods, + "dataClasses": data_classes, + "enums": enums, + } + except Exception as e: + raise ABIHandlerError(f"Error preparing template data: {str(e)}") from e + + def _process_parameters( + self, param, data_classes, enums, generated_structs, generated_enums + ): + if param["type"] == "tuple" and param["internalType"] not in generated_structs: + struct_name = SolidityConverter._get_struct_name(param["internalType"]) + properties = [ + { + "name": comp["name"], + "type": SolidityConverter.convert_type( + comp["type"], comp.get("internalType") + ), + } + for comp in param["components"] + ] + data_classes.append({"name": struct_name, "properties": properties}) + generated_structs.add(param["internalType"]) + elif ( + "enum " in param["internalType"] + and param["internalType"] not in generated_enums + ): + enum_name = SolidityConverter._get_struct_name(param["internalType"]) + enum_values = [ + {"name": item["name"], "value": item["value"]} + for item in param["components"] + ] + enums.append({"name": enum_name, "values": enum_values}) + generated_enums.add(param["internalType"]) + + def _process_function(self, function_item: Dict[str, Any]) -> Dict[str, Any]: + original_name = function_item["name"] + method_name = to_python_conventional_name(original_name) + + input_types = self._generate_function_input_args_with_types(function_item) + output_types = [ + SolidityConverter.convert_type(o["type"], o.get("internalType")) + for o in function_item.get("outputs", []) + ] + output_str = ( + "None" + if not output_types + else output_types[0] + if len(output_types) == 1 + else f'Tuple[{", ".join(output_types)}]' + ) + + return { + "name": method_name, + "inputs": input_types, + "outputType": output_str, + "originalName": original_name, + } + + def _generate_function_input_args_with_types( + self, function_item: Dict[str, Any] + ) -> List[Dict[str, Any]]: + input_args = [] + unnamed_arg_counters = {} # Track unnamed arguments of each type + + for input_item in function_item.get("inputs", []): + input_type = SolidityConverter.convert_type( + input_item["type"], input_item.get("internalType") + ) + + # Regex to transform type names like 'list[int]' into 'int_list' + base_name = re.sub(r"list\[(\w+)\]", r"\1_list", input_type.lower()) + + input_name = input_item.get("name") + if not input_name: + # If the argument is unnamed, use the base_name with a counter to create a unique name + unnamed_arg_counters[base_name] = ( + unnamed_arg_counters.get(base_name, -1) + 1 + ) + input_name = f"{base_name}_arg{unnamed_arg_counters[base_name]}" + + python_input_name = to_python_conventional_name(input_name) + + if input_item["type"] == "tuple": + struct_name = SolidityConverter._get_struct_name( + input_item["internalType"] + ) + properties = [ + { + "name": component["name"], + "type": SolidityConverter.convert_type( + component["type"], component.get("internalType") + ), + } + for component in input_item["components"] + ] + destructured_args = ", ".join( + [f"{python_input_name}.{prop['name']}" for prop in properties] + ) + input_args.append( + { + "name": python_input_name, + "type": struct_name, + "isTuple": True, + "destructuredArgs": f"({destructured_args})", + } + ) + else: + input_args.append( + {"name": python_input_name, "type": input_type, "isTuple": False} + ) + + return input_args + + def _render_template(self, data: Dict[str, Any]) -> str: + partials = { + get_filename_without_extension(partial_path): compile_partial(partial_path) + for partial_path in _get_partials_files() + } + + with open(_get_template_file(), "r") as file: + template = file.read() + + compiler = Compiler() + template = compiler.compile(template) + return template(data, partials=partials) diff --git a/cow_py/codegen/components/__init__.py b/cow_py/codegen/components/__init__.py new file mode 100644 index 0000000..df6ddb9 --- /dev/null +++ b/cow_py/codegen/components/__init__.py @@ -0,0 +1,17 @@ +from cow_py.codegen.components.abi_loader import FileAbiLoader +from cow_py.codegen.components.base_contract import BaseContract +from cow_py.codegen.components.base_mixin import BaseMixin +from cow_py.codegen.components.contract_factory import ContractFactory +from cow_py.codegen.components.contract_loader import ContractLoader +from cow_py.codegen.components.get_abi_file import get_abi_file +from cow_py.codegen.components.templates import partials + +__all__ = [ + "BaseContract", + "ContractFactory", + "FileAbiLoader", + "ContractLoader", + "BaseMixin", + "get_abi_file", + "partials", +] diff --git a/cow_py/codegen/components/abi_loader.py b/cow_py/codegen/components/abi_loader.py new file mode 100644 index 0000000..4cfa24c --- /dev/null +++ b/cow_py/codegen/components/abi_loader.py @@ -0,0 +1,18 @@ +import json +from abc import ABC, abstractmethod +from typing import Any, List + + +class AbiLoader(ABC): + @abstractmethod + def load_abi(self) -> List[Any]: + return [] + + +class FileAbiLoader(AbiLoader): + def __init__(self, file_name: str): + self.file_name = file_name + + def load_abi(self) -> List[Any]: + with open(self.file_name) as f: + return json.load(f) diff --git a/cow_py/codegen/components/base_contract.py b/cow_py/codegen/components/base_contract.py new file mode 100644 index 0000000..38bd724 --- /dev/null +++ b/cow_py/codegen/components/base_contract.py @@ -0,0 +1,109 @@ +from typing import Any, Dict, List, Optional, Tuple, Type + +from cow_py.codegen.components.contract_loader import ContractLoader +from cow_py.common.chains import Chain + + +class BaseContractError(Exception): + """Raised when an error occurs in the BaseContract class.""" + + pass + + +class BaseContract: + """ + A base class for contracts that implements common functionality. + + This class uses a singleton pattern to ensure that there's only one instance + of the contract for each contract address and chain combination. + + :ivar _instances: A dictionary to store instances of the BaseContract class. + """ + + ABI: Optional[List[Any]] = None + _instances: Dict[Tuple[Type, str, Chain], "BaseContract"] = {} + + def __new__(cls, address, chain, *args, **kwargs): + key = (cls, address, chain) + if key not in cls._instances: + cls._instances[key] = super(BaseContract, cls).__new__(cls) + return cls._instances[key] + + def __init__(self, address: str, chain: Chain, abi: List[Any] = None): + """ + Initializes the BaseContract with a contract address, chain, and optionally an ABI. + + :param address: The address of the contract on the specified chain + :param chain: The chain the contract is deployed on + :param abi: The ABI of the contract, optional + """ + if not hasattr(self, "_initialized"): # Avoid re-initialization + # Initialize the instance (only the first time) + self.contract_loader = ContractLoader(chain) + self.web3_contract = self.contract_loader.get_web3_contract( + address, abi or self.ABI or [] + ) + self._initialized = True + + @property + def address(self) -> str: + return self.web3_contract.address + + def _function_exists_in_abi(self, function_name): + """ + Checks if a function exists in the ABI of the contract. + + :param function_name: The name of the function to check for + :return: True if the function exists, False otherwise + """ + return any( + item.get("type") == "function" and item.get("name") == function_name + for item in self.web3_contract.abi + ) + + def _event_exists_in_abi(self, event_name): + """ + Checks if an event exists in the ABI of the contract. + + :param event_name: The name of the event to check for + :return: True if the event exists, False otherwise + """ + return any( + item.get("type") == "event" and item.get("name") == event_name + for item in self.web3_contract.abi + ) + + def __getattr__(self, name): + """ + Makes contract functions directly accessible as attributes of the BaseContract. + + :param name: The name of the attribute being accessed + :return: The wrapped contract function if it exists, raises AttributeError otherwise + + Raises: + BaseContractError: If an error occurs while accessing the contract function. + """ + if name == "_initialized": + # This is needed to avoid infinite recursion + raise AttributeError(name) + + try: + if hasattr(self.web3_contract, name): + return getattr(self.web3_contract, name) + + if self._event_exists_in_abi(name): + return getattr(self.web3_contract.events, name) + + if self._function_exists_in_abi(name): + function = getattr(self.web3_contract.functions, name) + + def wrapped_call(*args, **kwargs): + return function(*args, **kwargs).call() + + return wrapped_call + except Exception as e: + raise BaseContractError( + f"Error accessing attribute {name}: {str(e)}" + ) from e + + raise AttributeError(f"{self.__class__.__name__} has no attribute {name}") diff --git a/cow_py/codegen/components/base_mixin.py b/cow_py/codegen/components/base_mixin.py new file mode 100644 index 0000000..02510f0 --- /dev/null +++ b/cow_py/codegen/components/base_mixin.py @@ -0,0 +1,18 @@ +from abc import ABC + +from web3.contract.async_contract import AsyncContract + + +class BaseMixin(ABC): + web3_contract: AsyncContract + + def call_contract_method(self, method_name, *args): + """ + Generic method to call a contract function. + + :param method_name: The name of the contract method to call. + :param args: Arguments to pass to the contract method. + :return: The result of the contract method call. + """ + method = getattr(self.web3_contract.functions, method_name) + return method(*args).call() diff --git a/cow_py/codegen/components/contract_factory.py b/cow_py/codegen/components/contract_factory.py new file mode 100644 index 0000000..ccfe8e7 --- /dev/null +++ b/cow_py/codegen/components/contract_factory.py @@ -0,0 +1,44 @@ +from typing import Dict, Tuple, Type + +from cow_py.codegen.components.abi_loader import AbiLoader +from cow_py.codegen.components.base_contract import BaseContract +from cow_py.common.chains import Chain + + +class ContractFactory: + _contract_classes: Dict[Tuple[str, Chain], Type[BaseContract]] = {} + + @classmethod + def get_contract_class( + cls, contract_name: str, chain: Chain, abi_loader: AbiLoader + ) -> Type[BaseContract]: + """ + Retrieves the contract class for a given contract name and chain, creating it if it doesn't exist. + + :param contract_name: The name of the contract + :param chain: The chain the contract is deployed on + :return: The contract class for the given contract name and chain + """ + key = (contract_name, chain) + if key not in cls._contract_classes: + abi = abi_loader.load_abi() + cls._contract_classes[key] = type( + f"{contract_name}", (BaseContract,), {"ABI": abi} + ) + return cls._contract_classes[key] + + @classmethod + def create( + cls, contract_name: str, chain: Chain, address: str, abi_loader: AbiLoader + ) -> BaseContract: + """ + Creates an instance of the contract class for a given contract identifier (name or address) and chain. + + :param chain: The chain the contract is deployed on + :param contract_identifier: The name or address of the contract on the specified chain, optional + :param address_override: address with which to instantiate the contract, optional. We do this because some + pool contracts only have a MockPool contract whose ABI we'd like to use + :return: An instance of the contract class for the given contract identifier and chain + """ + contract_class = cls.get_contract_class(contract_name, chain, abi_loader) + return contract_class(address, chain) diff --git a/cow_py/codegen/components/contract_loader.py b/cow_py/codegen/components/contract_loader.py new file mode 100644 index 0000000..aa68d52 --- /dev/null +++ b/cow_py/codegen/components/contract_loader.py @@ -0,0 +1,43 @@ +from cow_py.web3.provider import Web3Provider + + +class ContractLoaderError(Exception): + """Raised when an error occurs in the ContractLoader class.""" + + pass + + +class ContractLoader: + """ + A utility class to load contract ABIs and create web3 contract instances. + """ + + def __init__(self, network): + """ + Initializes a ContractLoader instance for a specified network. + + :param network: The network the contract loader is associated with. + """ + self.network = network + self._abis = {} + + def get_web3_contract(self, contract_address, abi=None): + """ + Creates a web3 contract instance for the specified contract address and ABI. + + :param contract_address: The address of the contract. + :param abi_file_name: The file name of the ABI, optional. + :return: A web3 contract instance. + + Raises: + ContractLoaderError: If an error occurs while creating the web3 contract instance. + """ + try: + w3 = Web3Provider.get_instance(self.network) + + return w3.eth.contract( + address=w3.to_checksum_address(contract_address), + abi=abi, + ) + except Exception as e: + raise ContractLoaderError(f"Error loading contract: {str(e)}") from e diff --git a/cow_py/codegen/components/get_abi_file.py b/cow_py/codegen/components/get_abi_file.py new file mode 100644 index 0000000..721fe6d --- /dev/null +++ b/cow_py/codegen/components/get_abi_file.py @@ -0,0 +1,15 @@ +import importlib.resources + +from cow_py.contracts import abi + + +def get_abi_file(contract_name: str) -> str: + pkg_files = importlib.resources.files(abi) + return str( + next( + x + for x in pkg_files.iterdir() + if x.suffix == ".json" # type: ignore + and x.name.split(".json")[0] == contract_name + ) + ) diff --git a/cow_py/order_signing/__init__.py b/cow_py/codegen/components/templates/__init__.py similarity index 100% rename from cow_py/order_signing/__init__.py rename to cow_py/codegen/components/templates/__init__.py diff --git a/cow_py/codegen/components/templates/contract_template.hbs b/cow_py/codegen/components/templates/contract_template.hbs new file mode 100644 index 0000000..a9db95d --- /dev/null +++ b/cow_py/codegen/components/templates/contract_template.hbs @@ -0,0 +1,14 @@ +{{! Import statements }} +from typing import List, Tuple, Any +from hexbytes import HexBytes +from cow_py.common.chains import Chain +from dataclasses import dataclass +from enum import Enum +from cow_py.codegen.components import BaseMixin, BaseContract, FileAbiLoader, ContractFactory, get_abi_file + +{{>enums}} +{{>dataclasses}} + +{{>contract_mixin}} + +{{>contract_class}} diff --git a/cow_py/subgraphs/__init__.py b/cow_py/codegen/components/templates/partials/__init__.py similarity index 100% rename from cow_py/subgraphs/__init__.py rename to cow_py/codegen/components/templates/partials/__init__.py diff --git a/cow_py/codegen/components/templates/partials/contract_class.hbs b/cow_py/codegen/components/templates/partials/contract_class.hbs new file mode 100644 index 0000000..ce8a4f4 --- /dev/null +++ b/cow_py/codegen/components/templates/partials/contract_class.hbs @@ -0,0 +1,6 @@ +class {{contractName}}(BaseContract, {{contractName}}Mixin): + def __init__(self, chain: Chain = Chain.MAINNET, address: str = ""): + {{!-- TEMPORARY -- abiPath should be a resolved ABI given we're already generating this --}} + abi_loader = FileAbiLoader(get_abi_file("{{contractName}}")) + contract = ContractFactory.create('{{contractName}}', chain, address, abi_loader) + super({{contractName}}, self).__init__(address, chain, abi=contract.ABI) diff --git a/cow_py/codegen/components/templates/partials/contract_mixin.hbs b/cow_py/codegen/components/templates/partials/contract_mixin.hbs new file mode 100644 index 0000000..4a3d24b --- /dev/null +++ b/cow_py/codegen/components/templates/partials/contract_mixin.hbs @@ -0,0 +1,6 @@ +class {{contractName}}Mixin(BaseMixin): +{{#each methods}} + def {{this.name}}(self{{#each this.inputs}}{{#if @first}}, {{/if}}{{this.name}}: {{this.type}}{{#unless @last}}, {{/unless}}{{/each}}) -> {{this.outputType}}: + return self.call_contract_method('{{this.originalName}}'{{#each this.inputs}}{{#if @first}}, {{/if}}{{#if this.isTuple}}{{this.destructuredArgs}}{{else}}{{this.name}}{{/if}}{{#unless @last}}, {{/unless}}{{/each}}) + +{{/each}} diff --git a/cow_py/codegen/components/templates/partials/dataclasses.hbs b/cow_py/codegen/components/templates/partials/dataclasses.hbs new file mode 100644 index 0000000..b7e2b9d --- /dev/null +++ b/cow_py/codegen/components/templates/partials/dataclasses.hbs @@ -0,0 +1,8 @@ +{{#each dataClasses}} +@dataclass +class {{this.name}}: +{{#each this.properties}} + {{this.name}}: {{this.type}} +{{/each}} + +{{/each}} \ No newline at end of file diff --git a/cow_py/codegen/components/templates/partials/enums.hbs b/cow_py/codegen/components/templates/partials/enums.hbs new file mode 100644 index 0000000..787d2de --- /dev/null +++ b/cow_py/codegen/components/templates/partials/enums.hbs @@ -0,0 +1,10 @@ +{{#each enums}} +{{#if @first}} +# TODO: Enums must be fixed before using them. They currently only use placeholder values. +{{/if}} +class {{this.name}}(Enum): +{{#each this.values}} + {{this.name}} = {{this.value}} +{{/each}} + +{{/each}} \ No newline at end of file diff --git a/cow_py/codegen/main.py b/cow_py/codegen/main.py new file mode 100644 index 0000000..15604e1 --- /dev/null +++ b/cow_py/codegen/main.py @@ -0,0 +1,37 @@ +import importlib.resources +import os + +from cow_py.codegen.abi_handler import ABIHandler +from cow_py.contracts import abi + + +def get_all_abis(): + pkg_files = importlib.resources.files(abi) + return [ + posix_path + for posix_path in pkg_files.iterdir() + if posix_path.suffix == ".json" # type: ignore + ] + + +def main(): + contracts_abis = get_all_abis() + for abi_file_path in contracts_abis: + contract_name = str(abi_file_path).split("/")[-1].split(".json")[0] + handler = ABIHandler(contract_name, str(abi_file_path)) + + content = handler.generate() + + base_path = os.path.dirname(os.path.abspath(__file__)) + + os.makedirs(f"{base_path}/__generated__", exist_ok=True) + generated = f"{base_path}/__generated__/{contract_name}.py" + + with open(generated, "w") as f: + f.write(content) + + print("Done") + + +if __name__ == "__main__": + main() diff --git a/cow_py/codegen/solidity_converter.py b/cow_py/codegen/solidity_converter.py new file mode 100644 index 0000000..90766f0 --- /dev/null +++ b/cow_py/codegen/solidity_converter.py @@ -0,0 +1,99 @@ +import re +from typing import Optional + +SOLIDITY_TO_PYTHON_TYPES = { + "address": "str", + "bool": "bool", + "string": "str", + "bytes": "HexBytes", + "uint": "int", + "int": "int", +} +DYNAMIC_SOLIDITY_TYPES = { + f"{prefix}{i*8 if prefix != 'bytes' else i}": ( + "int" if prefix != "bytes" else "HexBytes" + ) + for prefix in ["uint", "int", "bytes"] + for i in range(1, 33) +} +SOLIDITY_TO_PYTHON_TYPES.update(DYNAMIC_SOLIDITY_TYPES) + + +class SolidityConverterError(Exception): + """Raised when an error occurs in the SolidityConverter.""" + + pass + + +class SolidityConverter: + """ + Converts Solidity data types to equivalent Python data types. + + This class provides methods to map Solidity types as found in Ethereum smart contracts' ABIs + to Python types, facilitating the generation of Python classes and methods to interact with these contracts. + + Methods: + convert_type: Converts a Solidity data type to its Python equivalent. + """ + + @staticmethod + def _get_struct_name(internal_type: str) -> str: + """ + Extracts the struct name from a given internal type. + + Args: + internal_type (str): The internal type string from an ABI, often representing a struct. + + Returns: + str: The extracted name of the struct. + + Raises: + SolidityConverterError: If the internal type is not in the expected format. + """ + if not internal_type or "struct " not in internal_type: + raise SolidityConverterError( + f"Invalid internal type for struct: {internal_type}" + ) + return internal_type.replace("struct ", "").replace(".", "_").replace("[]", "") + + @classmethod + def convert_type(cls, solidity_type: str, internal_type: str) -> str: + """ + Converts a Solidity type to the corresponding Python type. + + Args: + solidity_type (str): The Solidity type as specified in the contract's ABI. + internal_type (str): The internal type representation, used for more complex data structures. + + Returns: + str: The Python type equivalent to the given Solidity type. + """ + if re.search(r"enum", internal_type) or (re.search(r"enum", solidity_type)): + return cls._extract_enum_name(internal_type, solidity_type) + elif solidity_type == "tuple": + return cls._get_struct_name(internal_type) + else: + return cls._convert_array_or_basic_type(solidity_type) + + @staticmethod + def _extract_enum_name( + internal_type: Optional[str], solidity_type: Optional[str] = None + ) -> str: + if internal_type and re.search(r"enum", internal_type): + return internal_type.replace("enum ", "").replace(".", "_") + elif solidity_type and re.search(r"enum", solidity_type): + return solidity_type.replace("enum ", "").replace(".", "_") + raise SolidityConverterError(f"Invalid internal type for enum: {internal_type}") + + @staticmethod + def _convert_array_or_basic_type(solidity_type: str) -> str: + array_match = re.match(r"(.+?)(\[\d*\])", solidity_type) + if array_match: + base_type, array_size = array_match.groups() + if array_size == "[]": + return f'List[{SOLIDITY_TO_PYTHON_TYPES.get(base_type, "Any")}]' + else: + size = int(array_size[1:-1]) + return f'Tuple[{", ".join([SOLIDITY_TO_PYTHON_TYPES.get(base_type, "Any")] * size)}]' + else: + return SOLIDITY_TO_PYTHON_TYPES.get(solidity_type, "Any") diff --git a/cow_py/common/api/api_base.py b/cow_py/common/api/api_base.py new file mode 100644 index 0000000..545150e --- /dev/null +++ b/cow_py/common/api/api_base.py @@ -0,0 +1,85 @@ +from abc import ABC +from typing import Any, Optional + +import httpx + +from cow_py.common.api.decorators import rate_limitted, with_backoff +from cow_py.common.config import SupportedChainId + +Context = dict[str, Any] + + +class APIConfig(ABC): + """Base class for API configuration with common functionality.""" + + config_map = {} + + def __init__( + self, chain_id: SupportedChainId, base_context: Optional[Context] = None + ): + self.chain_id = chain_id + self.context = base_context or {} + + def get_base_url(self) -> str: + return self.config_map.get( + self.chain_id, "default URL if chain_id is not found" + ) + + def get_context(self) -> Context: + return {"base_url": self.get_base_url(), **self.context} + + +class RequestStrategy: + async def make_request(self, client, url, method, **request_kwargs): + headers = { + "accept": "application/json", + "content-type": "application/json", + } + + return await client.request( + url=url, headers=headers, method=method, **request_kwargs + ) + + +class ResponseAdapter: + async def adapt_response(self, _response): + raise NotImplementedError() + + +class RequestBuilder: + def __init__(self, strategy, response_adapter): + self.strategy = strategy + self.response_adapter = response_adapter + + async def execute(self, client, url, method, **kwargs): + response = await self.strategy.make_request(client, url, method, **kwargs) + return self.response_adapter.adapt_response(response) + + +class JsonResponseAdapter(ResponseAdapter): + def adapt_response(self, response): + if response.headers.get("content-type") == "application/json": + return response.json() + else: + return response.text + + +class ApiBase: + """Base class for APIs utilizing configuration and request execution.""" + + def __init__(self, config: APIConfig): + self.config = config + + @with_backoff() + @rate_limitted() + async def _fetch(self, path, method="GET", **kwargs): + url = self.config.get_base_url() + path + + del kwargs["context_override"] + + async with httpx.AsyncClient() as client: + builder = RequestBuilder( + RequestStrategy(), + JsonResponseAdapter(), + ) + return await builder.execute(client, url, method, **kwargs) diff --git a/cow_py/common/api/decorators.py b/cow_py/common/api/decorators.py new file mode 100644 index 0000000..305121a --- /dev/null +++ b/cow_py/common/api/decorators.py @@ -0,0 +1,58 @@ +import backoff +import httpx +from aiolimiter import AsyncLimiter + +DEFAULT_LIMITER_OPTIONS = {"rate": 5, "per": 1.0} + +DEFAULT_BACKOFF_OPTIONS = { + "max_tries": 10, + "max_time": None, + "jitter": None, +} + + +def dig(self, *keys): + try: + for key in keys: + self = self[key] + return self + except KeyError: + return None + + +def with_backoff(): + def decorator(func): + async def wrapper(*args, **kwargs): + backoff_opts = dig(kwargs, "context_override", "backoff_opts") + + if backoff_opts is None: + internal_backoff_opts = DEFAULT_BACKOFF_OPTIONS + else: + internal_backoff_opts = backoff_opts + + @backoff.on_exception( + backoff.expo, httpx.HTTPStatusError, **internal_backoff_opts + ) + async def closure(): + return await func(*args, **kwargs) + + return await closure() + + return wrapper + + return decorator + + +def rate_limitted( + rate=DEFAULT_LIMITER_OPTIONS["rate"], per=DEFAULT_LIMITER_OPTIONS["per"] +): + limiter = AsyncLimiter(rate, per) + + def decorator(func): + async def wrapper(*args, **kwargs): + async with limiter: + return await func(*args, **kwargs) + + return wrapper + + return decorator diff --git a/cow_py/common/chains/__init__.py b/cow_py/common/chains/__init__.py index 083df3e..bf21c1d 100644 --- a/cow_py/common/chains/__init__.py +++ b/cow_py/common/chains/__init__.py @@ -6,24 +6,26 @@ class Chain(Enum): Supported chains and their respective `chainId` for the SDK. """ - MAINNET = 1 - GNOSIS = 100 - SEPOLIA = 11155111 + MAINNET = (1, "ethereum", "https://etherscan.io") + GNOSIS = (100, "gnosis", "https://gnosisscan.io") + SEPOLIA = (11155111, "sepolia", "https://sepolia.etherscan.io/") - def __init__(self, id) -> None: + def __init__(self, id: int, network_name: str, explorer_url: str) -> None: self.id = id + self.network_name = network_name + self.explorer_url = explorer_url + @property + def name(self) -> str: + return self.network_name -SUPPORTED_CHAINS = {Chain.MAINNET, Chain.GNOSIS, Chain.SEPOLIA} + @property + def explorer(self) -> str: + return self.explorer_url -CHAIN_NAMES = { - Chain.MAINNET: "ethereum", - Chain.GNOSIS: "gnosis", - Chain.SEPOLIA: "sepolia", -} + @property + def chain_id(self) -> int: + return self.id -CHAIN_SCANNER_MAP = { - Chain.MAINNET: "https://etherscan.io", - Chain.GNOSIS: "https://gnosisscan.io", - Chain.SEPOLIA: "https://sepolia.etherscan.io/", -} + +SUPPORTED_CHAINS = {chain for chain in Chain} diff --git a/cow_py/common/chains/utils.py b/cow_py/common/chains/utils.py index b428e63..7fdf2dc 100644 --- a/cow_py/common/chains/utils.py +++ b/cow_py/common/chains/utils.py @@ -1,6 +1,6 @@ -from cow_py.common.chains import CHAIN_SCANNER_MAP, Chain +from cow_py.common.chains import Chain def get_explorer_link(chain: Chain, tx_hash: str) -> str: """Return the scan link for the provided transaction hash.""" - return f"{CHAIN_SCANNER_MAP[chain]}/tx/{tx_hash}" + return f"{chain.explorer_url}/tx/{tx_hash}" diff --git a/cow_py/common/config.py b/cow_py/common/config.py index c82a166..ae4316b 100644 --- a/cow_py/common/config.py +++ b/cow_py/common/config.py @@ -1,4 +1,35 @@ +from dataclasses import dataclass from enum import Enum +from typing import Dict, Optional + + +class SupportedChainId(Enum): + MAINNET = 1 + GNOSIS_CHAIN = 100 + SEPOLIA = 11155111 + + +class CowEnv(Enum): + PROD = "prod" + STAGING = "staging" + + +ApiBaseUrls = Dict[SupportedChainId, str] + + +@dataclass +class ApiContext: + chain_id: SupportedChainId + env: CowEnv + base_urls: Optional[ApiBaseUrls] = None + max_tries: Optional[int] = 5 + + +# Define the list of available environments. +ENVS_LIST = [CowEnv.PROD, CowEnv.STAGING] + +# Define the default CoW Protocol API context. +DEFAULT_COW_API_CONTEXT = ApiContext(env=CowEnv.PROD, chain_id=SupportedChainId.MAINNET) class IPFSConfig(Enum): diff --git a/cow_py/common/constants.py b/cow_py/common/constants.py index 29ca7c3..2978a26 100644 --- a/cow_py/common/constants.py +++ b/cow_py/common/constants.py @@ -1,5 +1,6 @@ from enum import Enum from typing import Dict + from .chains import Chain """ @@ -17,14 +18,14 @@ class CowContractAddress(Enum): EXTENSIBLE_FALLBACK_HANDLER = "0x2f55e8b20D0B9FEFA187AA7d00B6Cbe563605bF5" -def map_address_to_supported_networks(address) -> Dict[Chain, str]: +def map_address_to_supported_networks(address) -> Dict[int, str]: """ Maps a given address to all supported networks. :param address: The address to be mapped. :return: A dictionary mapping the address to each supported chain. """ - return {chain_id: address for chain_id in Chain} + return {chain.chain_id: address for chain in Chain} COW_PROTOCOL_SETTLEMENT_CONTRACT_CHAIN_ADDRESS_MAP = map_address_to_supported_networks( diff --git a/cow_py/contracts/domain.py b/cow_py/contracts/domain.py new file mode 100644 index 0000000..51872df --- /dev/null +++ b/cow_py/contracts/domain.py @@ -0,0 +1,29 @@ +from dataclasses import dataclass +from typing import Optional + +from cow_py.common.chains import Chain + + +@dataclass +class TypedDataDomain: + name: str + version: str + chainId: int + verifyingContract: str + salt: Optional[str] = None + + +def domain(chain: Chain, verifying_contract: str) -> TypedDataDomain: + """ + Return the Gnosis Protocol v2 domain used for signing. + + :param chain: The EIP-155 chain ID. + :param verifying_contract: The address of the contract that will verify the signature. + :return: An EIP-712 compatible typed domain data. + """ + return TypedDataDomain( + name="Gnosis Protocol", + version="v2", + chainId=chain.chain_id, + verifyingContract=verifying_contract, + ) diff --git a/cow_py/contracts/order.py b/cow_py/contracts/order.py new file mode 100644 index 0000000..4702f5a --- /dev/null +++ b/cow_py/contracts/order.py @@ -0,0 +1,243 @@ +from dataclasses import dataclass +from enum import Enum +from typing import Literal, Optional, Union + +from eth_account.messages import _hash_eip191_message, encode_typed_data +from eth_typing import Hash32, HexStr +from eth_utils.conversions import to_bytes, to_hex + + +@dataclass +class Order: + # Sell token address. + sellToken: str + # Buy token address. + buyToken: str + # An optional address to receive the proceeds of the trade instead of the + # owner (i.e. the order signer). + receiver: str + # The order sell amount. + # + # For fill or kill sell orders, this amount represents the exact sell amount + # that will be executed in the trade. For fill or kill buy orders, this + # amount represents the maximum sell amount that can be executed. For partial + # fill orders, this represents a component of the limit price fraction. + # + sellAmount: int + # The order buy amount. + # + # For fill or kill sell orders, this amount represents the minimum buy amount + # that can be executed in the trade. For fill or kill buy orders, this amount + # represents the exact buy amount that will be executed. For partial fill + # orders, this represents a component of the limit price fraction. + # + buyAmount: int + # The timestamp this order is valid until + validTo: int + # Arbitrary application specific data that can be added to an order. This can + # also be used to ensure uniqueness between two orders with otherwise the + # exact same parameters. + appData: str + # Fee to give to the protocol. + feeAmount: int + # The order kind. + kind: str + # Specifies whether or not the order is partially fillable. + partiallyFillable: bool = False + # Specifies how the sell token balance will be withdrawn. It can either be + # taken using ERC20 token allowances made directly to the Vault relayer + # (default) or using Balancer Vault internal or external balances. + sellTokenBalance: Optional[str] = None + # Specifies how the buy token balance will be paid. It can either be paid + # directly in ERC20 tokens (default) in Balancer Vault internal balances. + buyTokenBalance: Optional[str] = None + + +# Gnosis Protocol v2 order cancellation data. +@dataclass +class OrderCancellations: + orderUids: bytearray + + +# Marker address to indicate that an order is buying Ether. +# +# Note that this address is only has special meaning in the `buyToken` and will +# be treated as a ERC20 token address in the `sellToken` position, causing the +# settlement to revert. +BUY_ETH_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" + +BytesLike = Union[str, bytes, HexStr] + +HashLike = Union[BytesLike, int] + + +class OrderKind(Enum): + SELL = "sell" + BUY = "buy" + + +class OrderBalance(Enum): + # Use ERC20 token balances. + ERC20 = "erc20" + # Use Balancer Vault external balances. + + # This can only be specified specified for the sell balance and allows orders + # to re-use Vault ERC20 allowances. When specified for the buy balance, it + # will be treated as {@link OrderBalance.ERC20}. + EXTERNAL = "external" + # Use Balancer Vault internal balances. + INTERNAL = "internal" + + +# /** +# * The EIP-712 type fields definition for a Gnosis Protocol v2 order. +# */ +ORDER_TYPE_FIELDS = [ + dict(name="sellToken", type="address"), + dict(name="buyToken", type="address"), + dict(name="receiver", type="address"), + dict(name="sellAmount", type="uint256"), + dict(name="buyAmount", type="uint256"), + dict(name="validTo", type="uint32"), + dict(name="appData", type="bytes32"), + dict(name="feeAmount", type="uint256"), + dict(name="kind", type="string"), + dict(name="partiallyFillable", type="bool"), + dict(name="sellTokenBalance", type="string"), + dict(name="buyTokenBalance", type="string"), +] +# The EIP-712 type fields definition for a Gnosis Protocol v2 order. +CANCELLATIONS_TYPE_FIELDS = [ + dict(name="orderUids", type="bytes[]"), +] + + +def hashify(h: Union[int, str, bytes]) -> str: + """ + Normalizes an app data value to a 32-byte hash. + :param h: A hash-like value to normalize. Can be an integer, hexadecimal string, or bytes. + :return: A 32-byte hash encoded as a hex-string. + """ + if isinstance(h, int): + # Convert the integer to a hexadecimal string and pad it to 64 characters + return f"0x{h:064x}" + elif isinstance(h, str): + # Convert string to bytes, then pad it to 32 bytes (64 hex characters) + return to_hex(to_bytes(hexstr=h).rjust(32, b"\0")) + elif isinstance(h, bytes): + # Pad the bytes to 32 bytes (64 hex characters) + return to_hex(h.rjust(32, b"\0")) + else: + raise ValueError("Input must be an integer, a hexadecimal string, or bytes.") + + +def normalize_buy_token_balance( + balance: Optional[str], +) -> Literal["erc20", "internal"]: + """ + Normalizes the balance configuration for a buy token. + + :param balance: The balance configuration. + :return: The normalized balance configuration. + """ + if balance in [None, OrderBalance.ERC20.value, OrderBalance.EXTERNAL.value]: + return OrderBalance.ERC20.value + elif balance == OrderBalance.INTERNAL: + return OrderBalance.INTERNAL.value + else: + raise ValueError(f"Invalid order balance {balance}") + + +ZERO_ADDRESS = "0x" + "00" * 20 + + +def normalize_order(order: Order): + if order.receiver == ZERO_ADDRESS: + raise ValueError("receiver cannot be address(0)") + + return { + "sellToken": order.sellToken, + "buyToken": order.buyToken, + "receiver": order.receiver if order.receiver else ZERO_ADDRESS, + "sellAmount": order.sellAmount, + "buyAmount": order.buyAmount, + "validTo": order.validTo, + "appData": hashify(order.appData), + "feeAmount": order.feeAmount, + "kind": order.kind, + "partiallyFillable": order.partiallyFillable, + "sellTokenBalance": ( + order.sellTokenBalance + if order.sellTokenBalance + else OrderBalance.ERC20.value + ), + "buyTokenBalance": normalize_buy_token_balance(order.buyTokenBalance), + } + + +def hash_typed_data(domain, types, data) -> Hash32: + """ + Compute the 32-byte signing hash for the specified order. + + :param domain: The EIP-712 domain separator to compute the hash for. + :param types: The typed data types. + :param data: The data to compute the digest for. + :return: Hex-encoded 32-byte order digest. + """ + encoded_data = encode_typed_data( + domain_data=domain, message_types=types, message_data=data + ) + return _hash_eip191_message(encoded_data) + + +def hash_order(domain, order): + """ + Compute the 32-byte signing hash for the specified order. + + :param domain: The EIP-712 domain separator to compute the hash for. + :param order: The order to compute the digest for. + :return: Hex-encoded 32-byte order digest. + """ + return hash_typed_data(domain, ORDER_TYPE_FIELDS, normalize_order(order)) + + +def hash_order_cancellation(domain, order_uid) -> str: + """ + Compute the 32-byte signing hash for the specified cancellation. + + :param domain: The EIP-712 domain separator to compute the hash for. + :param order_uid: The unique identifier of the order to cancel. + :return: Hex-encoded 32-byte order digest. + """ + return hash_order_cancellations(domain, [order_uid]) + + +def hash_order_cancellations(domain_data, order_uids) -> str: + """ + Compute the 32-byte signing hash for the specified order cancellations. + + :param domain_data: The EIP-712 domain separator to compute the hash for. + :param order_uids: The unique identifiers of the orders to cancel. + :return: Hex-encoded 32-byte order digest. + """ + return _hash_eip191_message( + encode_typed_data( + domain_data, + message_types={"OrderCancellations": CANCELLATIONS_TYPE_FIELDS}, + message_data={"orderUids": order_uids}, + ) + ).hex() + + +# The byte length of an order UID. +ORDER_UID_LENGTH = 56 + + +@dataclass +class OrderUidParams: + # The EIP-712 order struct hash. + orderDigest: str + # The owner of the order. + owner: str + # The timestamp this order is valid until. + validTo: int diff --git a/cow_py/contracts/sign.py b/cow_py/contracts/sign.py new file mode 100644 index 0000000..4217527 --- /dev/null +++ b/cow_py/contracts/sign.py @@ -0,0 +1,104 @@ +from enum import IntEnum +from typing import List, NamedTuple, Union + +from eth_account import Account +from eth_account.datastructures import SignedMessage +from eth_account.signers.local import LocalAccount +from eth_utils.conversions import to_hex +from eth_utils.crypto import keccak +from web3 import Web3 + +from cow_py.contracts.order import ( + CANCELLATIONS_TYPE_FIELDS, + ORDER_TYPE_FIELDS, + Order, + hash_typed_data, + normalize_order, +) + +EIP1271_MAGICVALUE = to_hex(keccak(text="isValidSignature(bytes32,bytes)"))[:10] +PRE_SIGNED = to_hex(keccak(text="GPv2Signing.Scheme.PreSign")) + + +class SigningScheme(IntEnum): + # The EIP-712 typed data signing scheme. This is the preferred scheme as it + # provides more infomation to wallets performing the signature on the data + # being signed. + # + # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#definition-of-domainseparator + EIP712 = 0b00 + # Message signed using eth_sign RPC call. + ETHSIGN = 0b01 + # Smart contract signatures as defined in EIP-1271. + EIP1271 = 0b10 + # Pre-signed order. + PRESIGN = 0b11 + + +class EcdsaSignature(NamedTuple): + scheme: SigningScheme + data: str + + +class Eip1271SignatureData(NamedTuple): + verifier: str + signature: bytes + + +class Eip1271Signature(NamedTuple): + scheme: SigningScheme + data: Eip1271SignatureData + + +class PreSignSignature(NamedTuple): + scheme: SigningScheme + data: str + + +Signature = Union[EcdsaSignature, Eip1271Signature, PreSignSignature] + + +def ecdsa_sign_typed_data( + scheme, owner: LocalAccount, domain_data, message_types, message_data +) -> SignedMessage: + return Account._sign_hash( + hash_typed_data(domain_data, message_types, message_data), owner.key + ) + + +def sign_order( + domain, order: Order, owner: LocalAccount, scheme: SigningScheme +) -> EcdsaSignature: + normalized_order = normalize_order(order) + signed_data = ecdsa_sign_typed_data( + scheme, owner, domain, {"Order": ORDER_TYPE_FIELDS}, normalized_order + ) + return EcdsaSignature( + scheme=scheme, + data=signed_data.signature.hex(), + ) + + +def sign_order_cancellation(domain, order_uid: Union[str, bytes], owner, scheme): + return sign_order_cancellations(domain, [order_uid], owner, scheme) + + +def sign_order_cancellations( + domain, order_uids: List[Union[str, bytes]], owner, scheme +): + data = {"orderUids": order_uids} + types = {"OrderCancellations": CANCELLATIONS_TYPE_FIELDS} + + signed_data = ecdsa_sign_typed_data(scheme, owner, domain, types, data) + + return EcdsaSignature(scheme=scheme, data=signed_data.signature.hex()) + + +def encode_eip1271_signature_data(verifier, signature): + return Web3.solidity_keccak(["address", "bytes"], [verifier, signature]) + + +def decode_eip1271_signature_data(signature): + arrayified_signature = bytes.fromhex(signature[2:]) # Removing '0x' + verifier = Web3.to_checksum_address(arrayified_signature[:20].hex()) + return Eip1271SignatureData(verifier, arrayified_signature[20:]) diff --git a/cow_py/core/__init__.py b/cow_py/core/__init__.py deleted file mode 100644 index f83b0ea..0000000 --- a/cow_py/core/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from cow_py.core import constants, cow_error, abis, chains, config -from cow_py.core.chains import utils - -__all__ = ["constants", "cow_error", "abis", "chains", "config", "utils"] diff --git a/cow_py/core/abi/ComposableCoW.json b/cow_py/core/abi/ComposableCoW.json deleted file mode 100644 index 8f50c24..0000000 --- a/cow_py/core/abi/ComposableCoW.json +++ /dev/null @@ -1,608 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "address", - "name": "_settlement", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "InterfaceNotSupported", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHandler", - "type": "error" - }, - { - "inputs": [], - "name": "ProofNotAuthed", - "type": "error" - }, - { - "inputs": [], - "name": "SingleOrderNotAuthed", - "type": "error" - }, - { - "inputs": [], - "name": "SwapGuardRestricted", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "components": [ - { - "internalType": "contract IConditionalOrder", - "name": "handler", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "staticInput", - "type": "bytes" - } - ], - "indexed": false, - "internalType": "struct IConditionalOrder.ConditionalOrderParams", - "name": "params", - "type": "tuple" - } - ], - "name": "ConditionalOrderCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "root", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "location", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "indexed": false, - "internalType": "struct ComposableCoW.Proof", - "name": "proof", - "type": "tuple" - } - ], - "name": "MerkleRootSet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": false, - "internalType": "contract ISwapGuard", - "name": "swapGuard", - "type": "address" - } - ], - "name": "SwapGuardSet", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "name": "cabinet", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IConditionalOrder", - "name": "handler", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "staticInput", - "type": "bytes" - } - ], - "internalType": "struct IConditionalOrder.ConditionalOrderParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bool", - "name": "dispatch", - "type": "bool" - } - ], - "name": "create", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IConditionalOrder", - "name": "handler", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "staticInput", - "type": "bytes" - } - ], - "internalType": "struct IConditionalOrder.ConditionalOrderParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "contract IValueFactory", - "name": "factory", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "bool", - "name": "dispatch", - "type": "bool" - } - ], - "name": "createWithContext", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "domainSeparator", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "components": [ - { - "internalType": "contract IConditionalOrder", - "name": "handler", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "staticInput", - "type": "bytes" - } - ], - "internalType": "struct IConditionalOrder.ConditionalOrderParams", - "name": "params", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "offchainInput", - "type": "bytes" - }, - { - "internalType": "bytes32[]", - "name": "proof", - "type": "bytes32[]" - } - ], - "name": "getTradeableOrderWithSignature", - "outputs": [ - { - "components": [ - { - "internalType": "contract IERC20", - "name": "sellToken", - "type": "address" - }, - { - "internalType": "contract IERC20", - "name": "buyToken", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - }, - { - "internalType": "uint32", - "name": "validTo", - "type": "uint32" - }, - { - "internalType": "bytes32", - "name": "appData", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "feeAmount", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "kind", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "partiallyFillable", - "type": "bool" - }, - { - "internalType": "bytes32", - "name": "sellTokenBalance", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "buyTokenBalance", - "type": "bytes32" - } - ], - "internalType": "struct GPv2Order.Data", - "name": "order", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IConditionalOrder", - "name": "handler", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "staticInput", - "type": "bytes" - } - ], - "internalType": "struct IConditionalOrder.ConditionalOrderParams", - "name": "params", - "type": "tuple" - } - ], - "name": "hash", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract Safe", - "name": "safe", - "type": "address" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "_hash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "_domainSeparator", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "encodeData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "payload", - "type": "bytes" - } - ], - "name": "isValidSafeSignature", - "outputs": [ - { - "internalType": "bytes4", - "name": "magic", - "type": "bytes4" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "singleOrderHash", - "type": "bytes32" - } - ], - "name": "remove", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "roots", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "root", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "location", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct ComposableCoW.Proof", - "name": "proof", - "type": "tuple" - } - ], - "name": "setRoot", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "root", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "location", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct ComposableCoW.Proof", - "name": "proof", - "type": "tuple" - }, - { - "internalType": "contract IValueFactory", - "name": "factory", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "setRootWithContext", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract ISwapGuard", - "name": "swapGuard", - "type": "address" - } - ], - "name": "setSwapGuard", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "name": "singleOrders", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "swapGuards", - "outputs": [ - { - "internalType": "contract ISwapGuard", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } -] \ No newline at end of file diff --git a/cow_py/core/abi/ExtensibleFallbackHandler.json b/cow_py/core/abi/ExtensibleFallbackHandler.json deleted file mode 100644 index 907244d..0000000 --- a/cow_py/core/abi/ExtensibleFallbackHandler.json +++ /dev/null @@ -1,493 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "contract Safe", - "name": "safe", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "domainSeparator", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "contract ISafeSignatureVerifier", - "name": "verifier", - "type": "address" - } - ], - "name": "AddedDomainVerifier", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "contract Safe", - "name": "safe", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "AddedInterface", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "contract Safe", - "name": "safe", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "method", - "type": "bytes32" - } - ], - "name": "AddedSafeMethod", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "contract Safe", - "name": "safe", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "domainSeparator", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "contract ISafeSignatureVerifier", - "name": "oldVerifier", - "type": "address" - }, - { - "indexed": false, - "internalType": "contract ISafeSignatureVerifier", - "name": "newVerifier", - "type": "address" - } - ], - "name": "ChangedDomainVerifier", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "contract Safe", - "name": "safe", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "oldMethod", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "newMethod", - "type": "bytes32" - } - ], - "name": "ChangedSafeMethod", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "contract Safe", - "name": "safe", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "domainSeparator", - "type": "bytes32" - } - ], - "name": "RemovedDomainVerifier", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "contract Safe", - "name": "safe", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "RemovedInterface", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "contract Safe", - "name": "safe", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - } - ], - "name": "RemovedSafeMethod", - "type": "event" - }, - { - "stateMutability": "nonpayable", - "type": "fallback" - }, - { - "inputs": [ - { - "internalType": "contract Safe", - "name": "", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "name": "domainVerifiers", - "outputs": [ - { - "internalType": "contract ISafeSignatureVerifier", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_hash", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "isValidSignature", - "outputs": [ - { - "internalType": "bytes4", - "name": "magic", - "type": "bytes4" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" - }, - { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "onERC1155BatchReceived", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "onERC1155Received", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "onERC721Received", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract Safe", - "name": "", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "name": "safeInterfaces", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract Safe", - "name": "", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "name": "safeMethods", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "domainSeparator", - "type": "bytes32" - }, - { - "internalType": "contract ISafeSignatureVerifier", - "name": "newVerifier", - "type": "address" - } - ], - "name": "setDomainVerifier", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - }, - { - "internalType": "bytes32", - "name": "newMethod", - "type": "bytes32" - } - ], - "name": "setSafeMethod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - }, - { - "internalType": "bool", - "name": "supported", - "type": "bool" - } - ], - "name": "setSupportedInterface", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "_interfaceId", - "type": "bytes4" - }, - { - "internalType": "bytes32[]", - "name": "handlerWithSelectors", - "type": "bytes32[]" - } - ], - "name": "setSupportedInterfaceBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - } -] \ No newline at end of file diff --git a/cow_py/core/abi/TWAP.json b/cow_py/core/abi/TWAP.json deleted file mode 100644 index e6f15ed..0000000 --- a/cow_py/core/abi/TWAP.json +++ /dev/null @@ -1,324 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "contract ComposableCoW", - "name": "_composableCow", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "InvalidFrequency", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidMinPartLimit", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidNumParts", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidPartSellAmount", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSameToken", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidSpan", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidStartTime", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidToken", - "type": "error" - }, - { - "inputs": [], - "name": "OrderNotValid", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "components": [ - { - "internalType": "contract IConditionalOrder", - "name": "handler", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "staticInput", - "type": "bytes" - } - ], - "indexed": false, - "internalType": "struct IConditionalOrder.ConditionalOrderParams", - "name": "params", - "type": "tuple" - } - ], - "name": "ConditionalOrderCreated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "ctx", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "staticInput", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "getTradeableOrder", - "outputs": [ - { - "components": [ - { - "internalType": "contract IERC20", - "name": "sellToken", - "type": "address" - }, - { - "internalType": "contract IERC20", - "name": "buyToken", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - }, - { - "internalType": "uint32", - "name": "validTo", - "type": "uint32" - }, - { - "internalType": "bytes32", - "name": "appData", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "feeAmount", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "kind", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "partiallyFillable", - "type": "bool" - }, - { - "internalType": "bytes32", - "name": "sellTokenBalance", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "buyTokenBalance", - "type": "bytes32" - } - ], - "internalType": "struct GPv2Order.Data", - "name": "order", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "_hash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "domainSeparator", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "ctx", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "staticInput", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "offchainInput", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "contract IERC20", - "name": "sellToken", - "type": "address" - }, - { - "internalType": "contract IERC20", - "name": "buyToken", - "type": "address" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "buyAmount", - "type": "uint256" - }, - { - "internalType": "uint32", - "name": "validTo", - "type": "uint32" - }, - { - "internalType": "bytes32", - "name": "appData", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "feeAmount", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "kind", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "partiallyFillable", - "type": "bool" - }, - { - "internalType": "bytes32", - "name": "sellTokenBalance", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "buyTokenBalance", - "type": "bytes32" - } - ], - "internalType": "struct GPv2Order.Data", - "name": "", - "type": "tuple" - } - ], - "name": "verify", - "outputs": [], - "stateMutability": "view", - "type": "function" - } -] \ No newline at end of file diff --git a/cow_py/core/abis.py b/cow_py/core/abis.py deleted file mode 100644 index 0015a34..0000000 --- a/cow_py/core/abis.py +++ /dev/null @@ -1,860 +0,0 @@ -COMPOSABLE_COW = [ - { - "inputs": [ - {"internalType": "address", "name": "_settlement", "type": "address"} - ], - "stateMutability": "nonpayable", - "type": "constructor", - }, - {"inputs": [], "name": "InterfaceNotSupported", "type": "error"}, - {"inputs": [], "name": "InvalidHandler", "type": "error"}, - {"inputs": [], "name": "ProofNotAuthed", "type": "error"}, - {"inputs": [], "name": "SingleOrderNotAuthed", "type": "error"}, - {"inputs": [], "name": "SwapGuardRestricted", "type": "error"}, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "address", - "name": "owner", - "type": "address", - }, - { - "components": [ - { - "internalType": "contract IConditionalOrder", - "name": "handler", - "type": "address", - }, - {"internalType": "bytes32", "name": "salt", "type": "bytes32"}, - {"internalType": "bytes", "name": "staticInput", "type": "bytes"}, - ], - "indexed": False, - "internalType": "struct IConditionalOrder.ConditionalOrderParams", - "name": "params", - "type": "tuple", - }, - ], - "name": "ConditionalOrderCreated", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "address", - "name": "owner", - "type": "address", - }, - { - "indexed": False, - "internalType": "bytes32", - "name": "root", - "type": "bytes32", - }, - { - "components": [ - {"internalType": "uint256", "name": "location", "type": "uint256"}, - {"internalType": "bytes", "name": "data", "type": "bytes"}, - ], - "indexed": False, - "internalType": "struct ComposableCoW.Proof", - "name": "proof", - "type": "tuple", - }, - ], - "name": "MerkleRootSet", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "address", - "name": "owner", - "type": "address", - }, - { - "indexed": False, - "internalType": "contract ISwapGuard", - "name": "swapGuard", - "type": "address", - }, - ], - "name": "SwapGuardSet", - "type": "event", - }, - { - "inputs": [ - {"internalType": "address", "name": "", "type": "address"}, - {"internalType": "bytes32", "name": "", "type": "bytes32"}, - ], - "name": "cabinet", - "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IConditionalOrder", - "name": "handler", - "type": "address", - }, - {"internalType": "bytes32", "name": "salt", "type": "bytes32"}, - {"internalType": "bytes", "name": "staticInput", "type": "bytes"}, - ], - "internalType": "struct IConditionalOrder.ConditionalOrderParams", - "name": "params", - "type": "tuple", - }, - {"internalType": "bool", "name": "dispatch", "type": "bool"}, - ], - "name": "create", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IConditionalOrder", - "name": "handler", - "type": "address", - }, - {"internalType": "bytes32", "name": "salt", "type": "bytes32"}, - {"internalType": "bytes", "name": "staticInput", "type": "bytes"}, - ], - "internalType": "struct IConditionalOrder.ConditionalOrderParams", - "name": "params", - "type": "tuple", - }, - { - "internalType": "contract IValueFactory", - "name": "factory", - "type": "address", - }, - {"internalType": "bytes", "name": "data", "type": "bytes"}, - {"internalType": "bool", "name": "dispatch", "type": "bool"}, - ], - "name": "createWithContext", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [], - "name": "domainSeparator", - "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "address", "name": "owner", "type": "address"}, - { - "components": [ - { - "internalType": "contract IConditionalOrder", - "name": "handler", - "type": "address", - }, - {"internalType": "bytes32", "name": "salt", "type": "bytes32"}, - {"internalType": "bytes", "name": "staticInput", "type": "bytes"}, - ], - "internalType": "struct IConditionalOrder.ConditionalOrderParams", - "name": "params", - "type": "tuple", - }, - {"internalType": "bytes", "name": "offchainInput", "type": "bytes"}, - {"internalType": "bytes32[]", "name": "proof", "type": "bytes32[]"}, - ], - "name": "getTradeableOrderWithSignature", - "outputs": [ - { - "components": [ - { - "internalType": "contract IERC20", - "name": "sellToken", - "type": "address", - }, - { - "internalType": "contract IERC20", - "name": "buyToken", - "type": "address", - }, - {"internalType": "address", "name": "receiver", "type": "address"}, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256", - }, - {"internalType": "uint256", "name": "buyAmount", "type": "uint256"}, - {"internalType": "uint32", "name": "validTo", "type": "uint32"}, - {"internalType": "bytes32", "name": "appData", "type": "bytes32"}, - {"internalType": "uint256", "name": "feeAmount", "type": "uint256"}, - {"internalType": "bytes32", "name": "kind", "type": "bytes32"}, - { - "internalType": "bool", - "name": "partiallyFillable", - "type": "bool", - }, - { - "internalType": "bytes32", - "name": "sellTokenBalance", - "type": "bytes32", - }, - { - "internalType": "bytes32", - "name": "buyTokenBalance", - "type": "bytes32", - }, - ], - "internalType": "struct GPv2Order.Data", - "name": "order", - "type": "tuple", - }, - {"internalType": "bytes", "name": "signature", "type": "bytes"}, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract IConditionalOrder", - "name": "handler", - "type": "address", - }, - {"internalType": "bytes32", "name": "salt", "type": "bytes32"}, - {"internalType": "bytes", "name": "staticInput", "type": "bytes"}, - ], - "internalType": "struct IConditionalOrder.ConditionalOrderParams", - "name": "params", - "type": "tuple", - } - ], - "name": "hash", - "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], - "stateMutability": "pure", - "type": "function", - }, - { - "inputs": [ - {"internalType": "contract Safe", "name": "safe", "type": "address"}, - {"internalType": "address", "name": "sender", "type": "address"}, - {"internalType": "bytes32", "name": "_hash", "type": "bytes32"}, - {"internalType": "bytes32", "name": "_domainSeparator", "type": "bytes32"}, - {"internalType": "bytes32", "name": "", "type": "bytes32"}, - {"internalType": "bytes", "name": "encodeData", "type": "bytes"}, - {"internalType": "bytes", "name": "payload", "type": "bytes"}, - ], - "name": "isValidSafeSignature", - "outputs": [{"internalType": "bytes4", "name": "magic", "type": "bytes4"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "bytes32", "name": "singleOrderHash", "type": "bytes32"} - ], - "name": "remove", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [{"internalType": "address", "name": "", "type": "address"}], - "name": "roots", - "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "bytes32", "name": "root", "type": "bytes32"}, - { - "components": [ - {"internalType": "uint256", "name": "location", "type": "uint256"}, - {"internalType": "bytes", "name": "data", "type": "bytes"}, - ], - "internalType": "struct ComposableCoW.Proof", - "name": "proof", - "type": "tuple", - }, - ], - "name": "setRoot", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "bytes32", "name": "root", "type": "bytes32"}, - { - "components": [ - {"internalType": "uint256", "name": "location", "type": "uint256"}, - {"internalType": "bytes", "name": "data", "type": "bytes"}, - ], - "internalType": "struct ComposableCoW.Proof", - "name": "proof", - "type": "tuple", - }, - { - "internalType": "contract IValueFactory", - "name": "factory", - "type": "address", - }, - {"internalType": "bytes", "name": "data", "type": "bytes"}, - ], - "name": "setRootWithContext", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "contract ISwapGuard", - "name": "swapGuard", - "type": "address", - } - ], - "name": "setSwapGuard", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "address", "name": "", "type": "address"}, - {"internalType": "bytes32", "name": "", "type": "bytes32"}, - ], - "name": "singleOrders", - "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [{"internalType": "address", "name": "", "type": "address"}], - "name": "swapGuards", - "outputs": [ - {"internalType": "contract ISwapGuard", "name": "", "type": "address"} - ], - "stateMutability": "view", - "type": "function", - }, -] - -EXTENSIBLE_FALLBACK_HANDLER = [ - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "contract Safe", - "name": "safe", - "type": "address", - }, - { - "indexed": False, - "internalType": "bytes32", - "name": "domainSeparator", - "type": "bytes32", - }, - { - "indexed": False, - "internalType": "contract ISafeSignatureVerifier", - "name": "verifier", - "type": "address", - }, - ], - "name": "AddedDomainVerifier", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "contract Safe", - "name": "safe", - "type": "address", - }, - { - "indexed": False, - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4", - }, - ], - "name": "AddedInterface", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "contract Safe", - "name": "safe", - "type": "address", - }, - { - "indexed": False, - "internalType": "bytes4", - "name": "selector", - "type": "bytes4", - }, - { - "indexed": False, - "internalType": "bytes32", - "name": "method", - "type": "bytes32", - }, - ], - "name": "AddedSafeMethod", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "contract Safe", - "name": "safe", - "type": "address", - }, - { - "indexed": False, - "internalType": "bytes32", - "name": "domainSeparator", - "type": "bytes32", - }, - { - "indexed": False, - "internalType": "contract ISafeSignatureVerifier", - "name": "oldVerifier", - "type": "address", - }, - { - "indexed": False, - "internalType": "contract ISafeSignatureVerifier", - "name": "newVerifier", - "type": "address", - }, - ], - "name": "ChangedDomainVerifier", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "contract Safe", - "name": "safe", - "type": "address", - }, - { - "indexed": False, - "internalType": "bytes4", - "name": "selector", - "type": "bytes4", - }, - { - "indexed": False, - "internalType": "bytes32", - "name": "oldMethod", - "type": "bytes32", - }, - { - "indexed": False, - "internalType": "bytes32", - "name": "newMethod", - "type": "bytes32", - }, - ], - "name": "ChangedSafeMethod", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "contract Safe", - "name": "safe", - "type": "address", - }, - { - "indexed": False, - "internalType": "bytes32", - "name": "domainSeparator", - "type": "bytes32", - }, - ], - "name": "RemovedDomainVerifier", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "contract Safe", - "name": "safe", - "type": "address", - }, - { - "indexed": False, - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4", - }, - ], - "name": "RemovedInterface", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "contract Safe", - "name": "safe", - "type": "address", - }, - { - "indexed": False, - "internalType": "bytes4", - "name": "selector", - "type": "bytes4", - }, - ], - "name": "RemovedSafeMethod", - "type": "event", - }, - {"stateMutability": "nonpayable", "type": "fallback"}, - { - "inputs": [ - {"internalType": "contract Safe", "name": "", "type": "address"}, - {"internalType": "bytes32", "name": "", "type": "bytes32"}, - ], - "name": "domainVerifiers", - "outputs": [ - { - "internalType": "contract ISafeSignatureVerifier", - "name": "", - "type": "address", - } - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "bytes32", "name": "_hash", "type": "bytes32"}, - {"internalType": "bytes", "name": "signature", "type": "bytes"}, - ], - "name": "isValidSignature", - "outputs": [{"internalType": "bytes4", "name": "magic", "type": "bytes4"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "address", "name": "", "type": "address"}, - {"internalType": "address", "name": "", "type": "address"}, - {"internalType": "uint256[]", "name": "", "type": "uint256[]"}, - {"internalType": "uint256[]", "name": "", "type": "uint256[]"}, - {"internalType": "bytes", "name": "", "type": "bytes"}, - ], - "name": "onERC1155BatchReceived", - "outputs": [{"internalType": "bytes4", "name": "", "type": "bytes4"}], - "stateMutability": "pure", - "type": "function", - }, - { - "inputs": [ - {"internalType": "address", "name": "", "type": "address"}, - {"internalType": "address", "name": "", "type": "address"}, - {"internalType": "uint256", "name": "", "type": "uint256"}, - {"internalType": "uint256", "name": "", "type": "uint256"}, - {"internalType": "bytes", "name": "", "type": "bytes"}, - ], - "name": "onERC1155Received", - "outputs": [{"internalType": "bytes4", "name": "", "type": "bytes4"}], - "stateMutability": "pure", - "type": "function", - }, - { - "inputs": [ - {"internalType": "address", "name": "", "type": "address"}, - {"internalType": "address", "name": "", "type": "address"}, - {"internalType": "uint256", "name": "", "type": "uint256"}, - {"internalType": "bytes", "name": "", "type": "bytes"}, - ], - "name": "onERC721Received", - "outputs": [{"internalType": "bytes4", "name": "", "type": "bytes4"}], - "stateMutability": "pure", - "type": "function", - }, - { - "inputs": [ - {"internalType": "contract Safe", "name": "", "type": "address"}, - {"internalType": "bytes4", "name": "", "type": "bytes4"}, - ], - "name": "safeInterfaces", - "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "contract Safe", "name": "", "type": "address"}, - {"internalType": "bytes4", "name": "", "type": "bytes4"}, - ], - "name": "safeMethods", - "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "bytes32", "name": "domainSeparator", "type": "bytes32"}, - { - "internalType": "contract ISafeSignatureVerifier", - "name": "newVerifier", - "type": "address", - }, - ], - "name": "setDomainVerifier", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "bytes4", "name": "selector", "type": "bytes4"}, - {"internalType": "bytes32", "name": "newMethod", "type": "bytes32"}, - ], - "name": "setSafeMethod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "bytes4", "name": "interfaceId", "type": "bytes4"}, - {"internalType": "bool", "name": "supported", "type": "bool"}, - ], - "name": "setSupportedInterface", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "bytes4", "name": "_interfaceId", "type": "bytes4"}, - { - "internalType": "bytes32[]", - "name": "handlerWithSelectors", - "type": "bytes32[]", - }, - ], - "name": "setSupportedInterfaceBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [{"internalType": "bytes4", "name": "interfaceId", "type": "bytes4"}], - "name": "supportsInterface", - "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], - "stateMutability": "view", - "type": "function", - }, -] - -TWAP = [ - { - "inputs": [ - { - "internalType": "contract ComposableCoW", - "name": "_composableCow", - "type": "address", - } - ], - "stateMutability": "nonpayable", - "type": "constructor", - }, - {"inputs": [], "name": "InvalidFrequency", "type": "error"}, - {"inputs": [], "name": "InvalidMinPartLimit", "type": "error"}, - {"inputs": [], "name": "InvalidNumParts", "type": "error"}, - {"inputs": [], "name": "InvalidPartSellAmount", "type": "error"}, - {"inputs": [], "name": "InvalidSameToken", "type": "error"}, - {"inputs": [], "name": "InvalidSpan", "type": "error"}, - {"inputs": [], "name": "InvalidStartTime", "type": "error"}, - {"inputs": [], "name": "InvalidToken", "type": "error"}, - {"inputs": [], "name": "OrderNotValid", "type": "error"}, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "address", - "name": "owner", - "type": "address", - }, - { - "components": [ - { - "internalType": "contract IConditionalOrder", - "name": "handler", - "type": "address", - }, - {"internalType": "bytes32", "name": "salt", "type": "bytes32"}, - {"internalType": "bytes", "name": "staticInput", "type": "bytes"}, - ], - "indexed": False, - "internalType": "struct IConditionalOrder.ConditionalOrderParams", - "name": "params", - "type": "tuple", - }, - ], - "name": "ConditionalOrderCreated", - "type": "event", - }, - { - "inputs": [ - {"internalType": "address", "name": "owner", "type": "address"}, - {"internalType": "address", "name": "", "type": "address"}, - {"internalType": "bytes32", "name": "ctx", "type": "bytes32"}, - {"internalType": "bytes", "name": "staticInput", "type": "bytes"}, - {"internalType": "bytes", "name": "", "type": "bytes"}, - ], - "name": "getTradeableOrder", - "outputs": [ - { - "components": [ - { - "internalType": "contract IERC20", - "name": "sellToken", - "type": "address", - }, - { - "internalType": "contract IERC20", - "name": "buyToken", - "type": "address", - }, - {"internalType": "address", "name": "receiver", "type": "address"}, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256", - }, - {"internalType": "uint256", "name": "buyAmount", "type": "uint256"}, - {"internalType": "uint32", "name": "validTo", "type": "uint32"}, - {"internalType": "bytes32", "name": "appData", "type": "bytes32"}, - {"internalType": "uint256", "name": "feeAmount", "type": "uint256"}, - {"internalType": "bytes32", "name": "kind", "type": "bytes32"}, - { - "internalType": "bool", - "name": "partiallyFillable", - "type": "bool", - }, - { - "internalType": "bytes32", - "name": "sellTokenBalance", - "type": "bytes32", - }, - { - "internalType": "bytes32", - "name": "buyTokenBalance", - "type": "bytes32", - }, - ], - "internalType": "struct GPv2Order.Data", - "name": "order", - "type": "tuple", - } - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [{"internalType": "bytes4", "name": "interfaceId", "type": "bytes4"}], - "name": "supportsInterface", - "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "address", "name": "owner", "type": "address"}, - {"internalType": "address", "name": "sender", "type": "address"}, - {"internalType": "bytes32", "name": "_hash", "type": "bytes32"}, - {"internalType": "bytes32", "name": "domainSeparator", "type": "bytes32"}, - {"internalType": "bytes32", "name": "ctx", "type": "bytes32"}, - {"internalType": "bytes", "name": "staticInput", "type": "bytes"}, - {"internalType": "bytes", "name": "offchainInput", "type": "bytes"}, - { - "components": [ - { - "internalType": "contract IERC20", - "name": "sellToken", - "type": "address", - }, - { - "internalType": "contract IERC20", - "name": "buyToken", - "type": "address", - }, - {"internalType": "address", "name": "receiver", "type": "address"}, - { - "internalType": "uint256", - "name": "sellAmount", - "type": "uint256", - }, - {"internalType": "uint256", "name": "buyAmount", "type": "uint256"}, - {"internalType": "uint32", "name": "validTo", "type": "uint32"}, - {"internalType": "bytes32", "name": "appData", "type": "bytes32"}, - {"internalType": "uint256", "name": "feeAmount", "type": "uint256"}, - {"internalType": "bytes32", "name": "kind", "type": "bytes32"}, - { - "internalType": "bool", - "name": "partiallyFillable", - "type": "bool", - }, - { - "internalType": "bytes32", - "name": "sellTokenBalance", - "type": "bytes32", - }, - { - "internalType": "bytes32", - "name": "buyTokenBalance", - "type": "bytes32", - }, - ], - "internalType": "struct GPv2Order.Data", - "name": "", - "type": "tuple", - }, - ], - "name": "verify", - "outputs": [], - "stateMutability": "view", - "type": "function", - }, -] diff --git a/cow_py/core/chains/__init__.py b/cow_py/core/chains/__init__.py deleted file mode 100644 index 083df3e..0000000 --- a/cow_py/core/chains/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -from enum import Enum - - -class Chain(Enum): - """ - Supported chains and their respective `chainId` for the SDK. - """ - - MAINNET = 1 - GNOSIS = 100 - SEPOLIA = 11155111 - - def __init__(self, id) -> None: - self.id = id - - -SUPPORTED_CHAINS = {Chain.MAINNET, Chain.GNOSIS, Chain.SEPOLIA} - -CHAIN_NAMES = { - Chain.MAINNET: "ethereum", - Chain.GNOSIS: "gnosis", - Chain.SEPOLIA: "sepolia", -} - -CHAIN_SCANNER_MAP = { - Chain.MAINNET: "https://etherscan.io", - Chain.GNOSIS: "https://gnosisscan.io", - Chain.SEPOLIA: "https://sepolia.etherscan.io/", -} diff --git a/cow_py/core/chains/utils.py b/cow_py/core/chains/utils.py deleted file mode 100644 index 9aa73a8..0000000 --- a/cow_py/core/chains/utils.py +++ /dev/null @@ -1,6 +0,0 @@ -from cow_py.core.chains import CHAIN_SCANNER_MAP, Chain - - -def get_explorer_link(chain: Chain, tx_hash: str) -> str: - """Return the scan link for the provided transaction hash.""" - return f"{CHAIN_SCANNER_MAP[chain]}/tx/{tx_hash}" diff --git a/cow_py/core/config.py b/cow_py/core/config.py deleted file mode 100644 index c82a166..0000000 --- a/cow_py/core/config.py +++ /dev/null @@ -1,7 +0,0 @@ -from enum import Enum - - -class IPFSConfig(Enum): - READ_URI = "https://gnosis.mypinata.cloud/ipfs" - WRITE_URI = "https://api.pinata.cloud" - # TODO: ensure pinata api key is somewhere? diff --git a/cow_py/core/constants.py b/cow_py/core/constants.py deleted file mode 100644 index f71d666..0000000 --- a/cow_py/core/constants.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import Dict -from .chains import Chain - -BUY_ETH_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" - -VAULT_RELAYER = "0xC92E8bdf79f0507f65a392b0ab4667716BFE0110" -COMPOSABLE_COW = "0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74" -SETTLEMENT_CONTRACT = "0x9008D19f58AAbD9eD0D60971565AA8510560ab41" -EXTENSIBLE_FALLBACK_HANDLER = "0x2f55e8b20D0B9FEFA187AA7d00B6Cbe563605bF5" - - -def map_address_to_supported_networks(address: str) -> Dict[Chain, str]: - return {chain_id: address for chain_id in Chain} - - -""" An object containing the addresses of the CoW Protocol settlement contracts for each supported chain. """ -COW_PROTOCOL_SETTLEMENT_CONTRACT_CHAIN_ADDRESS_MAP = map_address_to_supported_networks( - SETTLEMENT_CONTRACT -) - -""" An object containing the addresses of the CoW Protocol Vault relayer contracts for each supported chain. """ -COW_PROTOCOL_VAULT_RELAYER_CHAIN_ADDRESS_MAP = map_address_to_supported_networks( - VAULT_RELAYER -) - -""" An object containing the addresses of the `ExtensibleFallbackHandler` contracts for each supported chain. """ -EXTENSIBLE_FALLBACK_HANDLER_CONTRACT_CHAIN_ADDRESS_MAP = ( - map_address_to_supported_networks(EXTENSIBLE_FALLBACK_HANDLER) -) - -""" An object containing the addresses of the `ComposableCow` contracts for each supported chain. """ -COMPOSABLE_COW_CONTRACT_CHAIN_ADDRESS_MAP = map_address_to_supported_networks( - COMPOSABLE_COW -) diff --git a/cow_py/core/cow_error.py b/cow_py/core/cow_error.py deleted file mode 100644 index 25c23d1..0000000 --- a/cow_py/core/cow_error.py +++ /dev/null @@ -1,7 +0,0 @@ -class CowError(Exception): - def __init__(self, message, error_code=None): - super().__init__(message) - self.error_code = error_code - - -LOG_PREFIX = "cow-sdk:" diff --git a/cow_py/order_book/api.py b/cow_py/order_book/api.py new file mode 100644 index 0000000..c99b394 --- /dev/null +++ b/cow_py/order_book/api.py @@ -0,0 +1,203 @@ +import json +from typing import Any, Dict, List + +from cow_py.common.api.api_base import ApiBase, Context +from cow_py.common.config import SupportedChainId +from cow_py.order_book.config import OrderBookAPIConfigFactory +from typing import Union +from cow_py.order_book.generated.model import OrderQuoteSide2, OrderQuoteValidity2 + +from .generated.model import ( + UID, + Address, + AppDataHash, + AppDataObject, + NativePriceResponse, + Order, + OrderCancellation, + OrderCreation, + OrderQuoteRequest, + OrderQuoteResponse, + OrderQuoteSide, + OrderQuoteSide1, + OrderQuoteSide3, + OrderQuoteValidity, + OrderQuoteValidity1, + SolverCompetitionResponse, + TotalSurplus, + Trade, + TransactionHash, +) + + +class OrderBookApi(ApiBase): + def __init__( + self, + config=OrderBookAPIConfigFactory.get_config("prod", SupportedChainId.MAINNET), + ): + self.config = config + + async def get_version(self, context_override: Context = {}) -> str: + return await self._fetch( + path="/api/v1/version", context_override=context_override + ) + + async def get_trades_by_owner( + self, owner: Address, context_override: Context = {} + ) -> List[Trade]: + response = await self._fetch( + path="/api/v1/trades", + params={"owner": owner}, + context_override=context_override, + ) + return [Trade(**trade) for trade in response] + + async def get_trades_by_order_uid( + self, order_uid: UID, context_override: Context = {} + ) -> List[Trade]: + response = await self._fetch( + path="/api/v1/trades", + params={"order_uid": order_uid}, + context_override=context_override, + ) + return [Trade(**trade) for trade in response] + + async def get_orders_by_owner( + self, + owner: Address, + limit: int = 1000, + offset: int = 0, + context_override: Context = {}, + ) -> List[Order]: + return [ + Order(**order) + for order in await self._fetch( + path=f"/api/v1/account/{owner}/orders", + params={"limit": limit, "offset": offset}, + context_override=context_override, + ) + ] + + async def get_order_by_uid( + self, order_uid: UID, context_override: Context = {} + ) -> Order: + response = await self._fetch( + path=f"/api/v1/orders/{order_uid}", + context_override=context_override, + ) + return Order(**response) + + def get_order_link(self, order_uid: UID) -> str: + return self.config.get_base_url() + f"/api/v1/orders/{order_uid.root}" + + async def get_tx_orders( + self, tx_hash: TransactionHash, context_override: Context = {} + ) -> List[Order]: + response = await self._fetch( + path=f"/api/v1/transactions/{tx_hash}/orders", + context_override=context_override, + ) + return [Order(**order) for order in response] + + async def get_native_price( + self, tokenAddress: Address, context_override: Context = {} + ) -> NativePriceResponse: + response = await self._fetch( + path=f"/api/v1/token/{tokenAddress}/native_price", + context_override=context_override, + ) + return NativePriceResponse(**response) + + async def get_total_surplus( + self, user: Address, context_override: Context = {} + ) -> TotalSurplus: + response = await self._fetch( + path=f"/api/v1/users/{user}/total_surplus", + context_override=context_override, + ) + return TotalSurplus(**response) + + async def get_app_data( + self, app_data_hash: AppDataHash, context_override: Context = {} + ) -> Dict[str, Any]: + return await self._fetch( + path=f"/api/v1/app_data/{app_data_hash}", + context_override=context_override, + ) + + async def get_solver_competition( + self, action_id: Union[int, str] = "latest", context_override: Context = {} + ) -> SolverCompetitionResponse: + response = await self._fetch( + path=f"/api/v1/solver_competition/{action_id}", + context_override=context_override, + ) + return SolverCompetitionResponse(**response) + + async def get_solver_competition_by_tx_hash( + self, tx_hash: TransactionHash, context_override: Context = {} + ) -> SolverCompetitionResponse: + response = await self._fetch( + path=f"/api/v1/solver_competition/by_tx_hash/{tx_hash}", + context_override=context_override, + ) + return SolverCompetitionResponse(**response) + + async def post_quote( + self, + request: OrderQuoteRequest, + side: Union[OrderQuoteSide, OrderQuoteSide1, OrderQuoteSide2, OrderQuoteSide3], + validity: Union[ + OrderQuoteValidity, OrderQuoteValidity1, OrderQuoteValidity2 + ] = OrderQuoteValidity1(validTo=None), + context_override: Context = {}, + ) -> OrderQuoteResponse: + response = await self._fetch( + path="/api/v1/quote", + json={ + **request.model_dump(by_alias=True), + # side object need to be converted to json first to avoid on kind type + **json.loads(side.model_dump_json()), + **validity.model_dump(), + }, + context_override=context_override, + method="POST", + ) + return OrderQuoteResponse(**response) + + async def post_order(self, order: OrderCreation, context_override: Context = {}): + response = await self._fetch( + path="/api/v1/orders", + json=json.loads(order.model_dump_json(by_alias=True)), + context_override=context_override, + method="POST", + ) + return UID(response) + + async def delete_order( + self, + orders_cancelation: OrderCancellation, + context_override: Context = {}, + ): + response = await self._fetch( + path="/api/v1/orders", + json=orders_cancelation.model_dump_json(), + context_override=context_override, + method="DELETE", + ) + return UID(response) + + async def put_app_data( + self, + app_data: AppDataObject, + app_data_hash: str = "", + context_override: Context = {}, + ) -> AppDataHash: + app_data_hash_url = app_data_hash if app_data_hash else "" + response = await self._fetch( + path=f"/api/v1/app_data/{app_data_hash_url}", + json=app_data.model_dump_json(), + context_override=context_override, + method="PUT", + ) + return AppDataHash(response) diff --git a/cow_py/order_book/config.py b/cow_py/order_book/config.py new file mode 100644 index 0000000..1953ca7 --- /dev/null +++ b/cow_py/order_book/config.py @@ -0,0 +1,39 @@ +from typing import Dict, Literal, Type + +from cow_py.common.api.api_base import APIConfig +from cow_py.common.config import SupportedChainId + + +class ProdAPIConfig(APIConfig): + config_map = { + SupportedChainId.MAINNET: "https://api.cow.fi/mainnet", + SupportedChainId.GNOSIS_CHAIN: "https://api.cow.fi/xdai", + SupportedChainId.SEPOLIA: "https://api.cow.fi/sepolia", + } + + +class StagingAPIConfig(APIConfig): + config_map = { + SupportedChainId.MAINNET: "https://barn.api.cow.fi/mainnet", + SupportedChainId.GNOSIS_CHAIN: "https://barn.api.cow.fi/xdai", + SupportedChainId.SEPOLIA: "https://barn.api.cow.fi/sepolia", + } + + +Envs = Literal["prod", "staging"] + + +class OrderBookAPIConfigFactory: + config_classes: Dict[Envs, Type[APIConfig]] = { + "prod": ProdAPIConfig, + "staging": StagingAPIConfig, + } + + @staticmethod + def get_config(env: Envs, chain_id: SupportedChainId) -> APIConfig: + config_class = OrderBookAPIConfigFactory.config_classes.get(env) + + if config_class: + return config_class(chain_id) + else: + raise ValueError("Unknown environment") diff --git a/cow_py/subgraphs/base/client.py b/cow_py/subgraphs/base/client.py deleted file mode 100644 index 20dce3e..0000000 --- a/cow_py/subgraphs/base/client.py +++ /dev/null @@ -1,51 +0,0 @@ -from abc import ABC, abstractmethod - -from cow_py.core.chains import Chain - -import json -import logging - -import httpx - -class GraphQLError(Exception): - pass - - -async def gql(url, query, variables={}): - logging.debug(f"Executing query: {query[:15]}") - logging.debug(f"URL: {url}") - logging.debug(f"Variables: {variables}") - async with httpx.AsyncClient() as client: - r = await client.post( - url, - json=dict(query=query, variables=variables), - ) - logging.debug(f"Response status: {r.status_code}") - logging.debug(f"Response body: {r.text}") - r.raise_for_status() - - try: - return r.json().get("data", r.json()) - except KeyError: - print(json.dumps(r.json(), indent=2)) - raise GraphQLError - - -class GraphQLClient(ABC): - def __init__(self, chain) -> None: - self.url = self.get_url(chain) - - async def instance_query(self, query, variables=dict()): - return await gql(self.url, query, variables=variables) - - @abstractmethod - def get_url(self, chain) -> str: - pass - - @classmethod - async def query(cls, chain=Chain.MAINNET, query=None, variables=dict()): - if not query: - raise ValueError("query must be provided") - - client = cls(chain) - return await client.instance_query(query, variables) diff --git a/cow_py/subgraphs/base/query.py b/cow_py/subgraphs/base/query.py deleted file mode 100644 index c6e81c5..0000000 --- a/cow_py/subgraphs/base/query.py +++ /dev/null @@ -1,23 +0,0 @@ -from abc import ABC, abstractmethod - -from cow_py.core.chains import Chain -from cow_py.subgraphs.base.client import GraphQLClient - - -class GraphQLQuery(ABC): - def __init__(self, chain=Chain.MAINNET, variables=dict()) -> None: - self.chain = chain - self.variables = variables - - @abstractmethod - def get_query(self) -> str: - pass - - @abstractmethod - def get_client(self) -> GraphQLClient: - pass - - async def execute(self): - query = self.get_query() - client = self.get_client() - return await client.__class__.query(self.chain, query, self.variables) diff --git a/cow_py/subgraphs/client.py b/cow_py/subgraphs/client.py deleted file mode 100644 index 035bbb5..0000000 --- a/cow_py/subgraphs/client.py +++ /dev/null @@ -1,14 +0,0 @@ -from cow_py.subgraphs.base.query import GraphQLQuery -from cow_py.subgraphs.base.client import GraphQLClient -from cow_py.subgraphs.deployments import build_subgraph_url, SubgraphEnvironment - - -class CoWSubgraph(GraphQLClient): - def get_url(self, chain): - # TODO: add a nice way to change the environment - return build_subgraph_url(chain, SubgraphEnvironment.PRODUCTION) - - -class CoWSubgraphQuery(GraphQLQuery): - def get_client(self): - return CoWSubgraph(self.chain) diff --git a/cow_py/subgraphs/deployments.py b/cow_py/subgraphs/deployments.py deleted file mode 100644 index bc4538e..0000000 --- a/cow_py/subgraphs/deployments.py +++ /dev/null @@ -1,36 +0,0 @@ -from cow_py.core.chains import Chain -from dataclasses import dataclass -from enum import Enum - - -class SubgraphEnvironment(Enum): - PRODUCTION = "production" - STAGING = "staging" - - -SUBGRAPH_BASE_URL = "https://api.thegraph.com/subgraphs/name/cowprotocol" - - -def build_subgraph_url(chain: Chain, env: SubgraphEnvironment) -> str: - base_url = SUBGRAPH_BASE_URL - - network_suffix = "" if chain == Chain.MAINNET else "-gc" - env_suffix = "-" + env.value if env == SubgraphEnvironment.STAGING else "" - - if chain == Chain.SEPOLIA: - raise ValueError(f"Unsupported chain: {chain}") - - return f"{base_url}/cow{network_suffix}{env_suffix}" - - -@dataclass -class SubgraphConfig: - chain: Chain - - @property - def production(self) -> str: - return build_subgraph_url(self.chain, SubgraphEnvironment.PRODUCTION) - - @property - def staging(self) -> str: - return build_subgraph_url(self.chain, SubgraphEnvironment.STAGING) diff --git a/cow_py/subgraphs/queries.py b/cow_py/subgraphs/queries.py deleted file mode 100644 index b25ba9a..0000000 --- a/cow_py/subgraphs/queries.py +++ /dev/null @@ -1,60 +0,0 @@ -from cow_py.subgraphs.client import CoWSubgraphQuery - -# /** -# * GraphQL query for the total number of tokens, orders, traders, settlements, volume, and fees. -# */ -TOTALS_QUERY = """ - query Totals { - totals { - tokens - orders - traders - settlements - volumeUsd - volumeEth - feesUsd - feesEth - } - } -""" - -# /** -# * GraphQL query for the total volume over the last N days. -# * @param days The number of days to query. -# */ -LAST_DAYS_VOLUME_QUERY = """ - query LastDaysVolume($days: Int!) { - dailyTotals(orderBy: timestamp, orderDirection: desc, first: $days) { - timestamp - volumeUsd - } - } -""" - -# /** -# * GraphQL query for the total volume over the last N hours. -# * @param hours The number of hours to query. -# */ -LAST_HOURS_VOLUME_QUERY = """ - query LastHoursVolume($hours: Int!) { - hourlyTotals(orderBy: timestamp, orderDirection: desc, first: $hours) { - timestamp - volumeUsd - } - } -""" - - -class TotalsQuery(CoWSubgraphQuery): - def get_query(self): - return TOTALS_QUERY - - -class LastDaysVolumeQuery(CoWSubgraphQuery): - def get_query(self): - return LAST_DAYS_VOLUME_QUERY - - -class LastHoursVolumeQuery(CoWSubgraphQuery): - def get_query(self): - return LAST_HOURS_VOLUME_QUERY diff --git a/cow_py/subgraphs/queries/queries.py b/cow_py/subgraphs/queries/queries.py deleted file mode 100644 index b25ba9a..0000000 --- a/cow_py/subgraphs/queries/queries.py +++ /dev/null @@ -1,60 +0,0 @@ -from cow_py.subgraphs.client import CoWSubgraphQuery - -# /** -# * GraphQL query for the total number of tokens, orders, traders, settlements, volume, and fees. -# */ -TOTALS_QUERY = """ - query Totals { - totals { - tokens - orders - traders - settlements - volumeUsd - volumeEth - feesUsd - feesEth - } - } -""" - -# /** -# * GraphQL query for the total volume over the last N days. -# * @param days The number of days to query. -# */ -LAST_DAYS_VOLUME_QUERY = """ - query LastDaysVolume($days: Int!) { - dailyTotals(orderBy: timestamp, orderDirection: desc, first: $days) { - timestamp - volumeUsd - } - } -""" - -# /** -# * GraphQL query for the total volume over the last N hours. -# * @param hours The number of hours to query. -# */ -LAST_HOURS_VOLUME_QUERY = """ - query LastHoursVolume($hours: Int!) { - hourlyTotals(orderBy: timestamp, orderDirection: desc, first: $hours) { - timestamp - volumeUsd - } - } -""" - - -class TotalsQuery(CoWSubgraphQuery): - def get_query(self): - return TOTALS_QUERY - - -class LastDaysVolumeQuery(CoWSubgraphQuery): - def get_query(self): - return LAST_DAYS_VOLUME_QUERY - - -class LastHoursVolumeQuery(CoWSubgraphQuery): - def get_query(self): - return LAST_HOURS_VOLUME_QUERY diff --git a/cow_py/web3/provider.py b/cow_py/web3/provider.py index ec20204..7087d24 100644 --- a/cow_py/web3/provider.py +++ b/cow_py/web3/provider.py @@ -1,7 +1,8 @@ from typing import Dict import web3 -from cow_py.core.chains import Chain + +from cow_py.common.chains import Chain DEFAULT_PROVIDER_NETWORK_MAPPING = { Chain.MAINNET: "https://eth.llamarpc.com", diff --git a/tests/core/__init__.py b/examples/__init__.py similarity index 100% rename from tests/core/__init__.py rename to examples/__init__.py diff --git a/examples/order_posting_e2e.py b/examples/order_posting_e2e.py new file mode 100644 index 0000000..5dc9842 --- /dev/null +++ b/examples/order_posting_e2e.py @@ -0,0 +1,120 @@ +# To run this test you will need to fill the .env file with the necessary variables (see .env.example). +# You will also need to have enough funds in you wallet of the sell token to create the order. +# The funds have to already be approved to the CoW Swap Vault Relayer + +import asyncio +import json +import os +from dataclasses import asdict + +from web3 import Account + +from cow_py.common.chains import Chain +from cow_py.common.config import SupportedChainId +from cow_py.common.constants import CowContractAddress +from cow_py.contracts.domain import domain +from cow_py.contracts.order import Order +from cow_py.contracts.sign import EcdsaSignature, SigningScheme +from cow_py.contracts.sign import sign_order as _sign_order +from cow_py.order_book.api import OrderBookApi +from cow_py.order_book.config import OrderBookAPIConfigFactory +from cow_py.order_book.generated.model import OrderQuoteSide1, TokenAmount +from cow_py.order_book.generated.model import OrderQuoteSideKindSell +from cow_py.order_book.generated.model import ( + UID, + OrderCreation, + OrderQuoteRequest, + OrderQuoteResponse, +) + +BUY_TOKEN = "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14" # WETH +SELL_TOKEN = "0xbe72E441BF55620febc26715db68d3494213D8Cb" # USDC +SELL_AMOUNT_BEFORE_FEE = "10000000000000000000" # 100 USDC with 18 decimals +ORDER_KIND = "sell" +CHAIN = Chain.SEPOLIA +CHAIN_ID = SupportedChainId.SEPOLIA + +config = OrderBookAPIConfigFactory.get_config("prod", CHAIN_ID) +ORDER_BOOK_API = OrderBookApi(config) + +ADDRESS = os.getenv("USER_ADDRESS") +ACCOUNT = Account.from_key(os.getenv("PRIVATE_KEY")) + + +async def get_order_quote( + order_quote_request: OrderQuoteRequest, order_side: OrderQuoteSide1 +) -> OrderQuoteResponse: + return await ORDER_BOOK_API.post_quote(order_quote_request, order_side) + + +def sign_order(order: Order) -> EcdsaSignature: + order_domain = asdict( + domain( + chain=CHAIN, verifying_contract=CowContractAddress.SETTLEMENT_CONTRACT.value + ) + ) + del order_domain["salt"] # TODO: improve interfaces + + return _sign_order(order_domain, order, ACCOUNT, SigningScheme.EIP712) + + +async def post_order(order: Order, signature: EcdsaSignature) -> UID: + order_creation = OrderCreation( + **{ + "from": ADDRESS, + "sellToken": order.sellToken, + "buyToken": order.buyToken, + "sellAmount": order.sellAmount, + "feeAmount": order.feeAmount, + "buyAmount": order.buyAmount, + "validTo": order.validTo, + "kind": order.kind, + "partiallyFillable": order.partiallyFillable, + "appData": order.appData, + "signature": signature.data, + "signingScheme": "eip712", + "receiver": order.receiver, + }, + ) + return await ORDER_BOOK_API.post_order(order_creation) + + +async def main(): + order_quote_request = OrderQuoteRequest( + **{ + "sellToken": SELL_TOKEN, + "buyToken": BUY_TOKEN, + "from": ADDRESS, + } + ) + order_side = OrderQuoteSide1( + kind=OrderQuoteSideKindSell.sell, + sellAmountBeforeFee=TokenAmount(SELL_AMOUNT_BEFORE_FEE), + ) + + order_quote = await get_order_quote(order_quote_request, order_side) + + order_quote_dict = json.loads(order_quote.quote.model_dump_json(by_alias=True)) + order = Order( + **{ + "sellToken": SELL_TOKEN, + "buyToken": BUY_TOKEN, + "receiver": ADDRESS, + "validTo": order_quote_dict["validTo"], + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "sellAmount": SELL_AMOUNT_BEFORE_FEE, # Since it is a sell order, the sellAmountBeforeFee is the same as the sellAmount + "buyAmount": order_quote_dict["buyAmount"], + "feeAmount": "0", # CoW Swap does not charge fees + "kind": ORDER_KIND, + "sellTokenBalance": "erc20", + "buyTokenBalance": "erc20", + } + ) + + signature = sign_order(order) + order_uid = await post_order(order, signature) + print(f"order posted on link: {ORDER_BOOK_API.get_order_link(order_uid)}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/poetry.lock b/poetry.lock index 5032f9b..ce74efa 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,92 +1,93 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "aiohttp" -version = "3.9.3" +version = "3.9.5" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"}, - {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"}, - {file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"}, - {file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"}, - {file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"}, - {file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"}, - {file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f"}, - {file = "aiohttp-3.9.3-cp312-cp312-win32.whl", hash = "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38"}, - {file = "aiohttp-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2"}, - {file = "aiohttp-3.9.3-cp38-cp38-win32.whl", hash = "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63"}, - {file = "aiohttp-3.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d"}, - {file = "aiohttp-3.9.3-cp39-cp39-win32.whl", hash = "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051"}, - {file = "aiohttp-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc"}, - {file = "aiohttp-3.9.3.tar.gz", hash = "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7"}, + {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7"}, + {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c"}, + {file = "aiohttp-3.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10"}, + {file = "aiohttp-3.9.5-cp310-cp310-win32.whl", hash = "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb"}, + {file = "aiohttp-3.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb"}, + {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342"}, + {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d"}, + {file = "aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75"}, + {file = "aiohttp-3.9.5-cp311-cp311-win32.whl", hash = "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6"}, + {file = "aiohttp-3.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a"}, + {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678"}, + {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c"}, + {file = "aiohttp-3.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da"}, + {file = "aiohttp-3.9.5-cp312-cp312-win32.whl", hash = "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59"}, + {file = "aiohttp-3.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888"}, + {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8"}, + {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8"}, + {file = "aiohttp-3.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe"}, + {file = "aiohttp-3.9.5-cp38-cp38-win32.whl", hash = "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da"}, + {file = "aiohttp-3.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a"}, + {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed"}, + {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a"}, + {file = "aiohttp-3.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2"}, + {file = "aiohttp-3.9.5-cp39-cp39-win32.whl", hash = "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09"}, + {file = "aiohttp-3.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1"}, + {file = "aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551"}, ] [package.dependencies] aiosignal = ">=1.1.2" +async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" @@ -95,6 +96,17 @@ yarl = ">=1.0,<2.0" [package.extras] speedups = ["Brotli", "aiodns", "brotlicffi"] +[[package]] +name = "aiolimiter" +version = "1.1.0" +description = "asyncio rate limiter, a leaky bucket implementation" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "aiolimiter-1.1.0-py3-none-any.whl", hash = "sha256:0b4997961fc58b8df40279e739f9cf0d3e255e63e9a44f64df567a8c17241e24"}, + {file = "aiolimiter-1.1.0.tar.gz", hash = "sha256:461cf02f82a29347340d031626c92853645c099cb5ff85577b831a7bd21132b5"}, +] + [[package]] name = "aiosignal" version = "1.3.1" @@ -109,6 +121,17 @@ files = [ [package.dependencies] frozenlist = ">=1.1.0" +[[package]] +name = "annotated-types" +version = "0.6.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, + {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, +] + [[package]] name = "anyio" version = "4.3.0" @@ -121,14 +144,56 @@ files = [ ] [package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" +typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] trio = ["trio (>=0.23)"] +[[package]] +name = "argcomplete" +version = "3.3.0" +description = "Bash tab completion for argparse" +optional = false +python-versions = ">=3.8" +files = [ + {file = "argcomplete-3.3.0-py3-none-any.whl", hash = "sha256:c168c3723482c031df3c207d4ba8fa702717ccb9fc0bfe4117166c1f537b4a54"}, + {file = "argcomplete-3.3.0.tar.gz", hash = "sha256:fd03ff4a5b9e6580569d34b273f741e85cd9e072f3feeeee3eba4891c70eda62"}, +] + +[package.extras] +test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] + +[[package]] +name = "ariadne-codegen" +version = "0.13.0" +description = "Generate fully typed GraphQL client from schema, queries and mutations!" +optional = false +python-versions = "*" +files = [ + {file = "ariadne_codegen-0.13.0-py2.py3-none-any.whl", hash = "sha256:61d0be4b1ba711bc5df35aaf0fa61d04cf4ea6f25a0038b687f845ab4f859a23"}, + {file = "ariadne_codegen-0.13.0.tar.gz", hash = "sha256:52aa67037dcd88a2f6013118e69ba0ed35a49f37312668a1969907f0e9c9bf8b"}, +] + +[package.dependencies] +autoflake = "*" +black = "*" +click = ">=8.1,<9.0" +graphql-core = ">=3.2.0,<3.3" +httpx = ">=0.23,<1.0" +isort = "*" +pydantic = ">=2.0.0,<3.0.0" +toml = ">=0.10,<1.0" + +[package.extras] +dev = ["ariadne", "freezegun", "mypy", "pylint", "pytest", "pytest-asyncio", "pytest-httpx", "pytest-mock", "requests-toolbelt", "types-toml"] +opentelemetry = ["opentelemetry-api"] +subscriptions = ["websockets (>=11.0,<12.0)"] + [[package]] name = "asttokens" version = "2.4.1" @@ -147,6 +212,17 @@ six = ">=1.12.0" astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] +[[package]] +name = "async-timeout" +version = "4.0.3" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, + {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, +] + [[package]] name = "attrs" version = "23.2.0" @@ -166,6 +242,32 @@ tests = ["attrs[tests-no-zope]", "zope-interface"] tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +[[package]] +name = "autoflake" +version = "2.3.1" +description = "Removes unused imports and unused variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "autoflake-2.3.1-py3-none-any.whl", hash = "sha256:3ae7495db9084b7b32818b4140e6dc4fc280b712fb414f5b8fe57b0a8e85a840"}, + {file = "autoflake-2.3.1.tar.gz", hash = "sha256:c98b75dc5b0a86459c4f01a1d32ac7eb4338ec4317a4469515ff1e687ecd909e"}, +] + +[package.dependencies] +pyflakes = ">=3.0.0" +tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} + +[[package]] +name = "backoff" +version = "2.2.1" +description = "Function decoration for backoff and retry" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"}, + {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, +] + [[package]] name = "bitarray" version = "2.9.2" @@ -297,6 +399,63 @@ files = [ {file = "bitarray-2.9.2.tar.gz", hash = "sha256:a8f286a51a32323715d77755ed959f94bef13972e9a2fe71b609e40e6d27957e"}, ] +[[package]] +name = "black" +version = "24.4.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.8" +files = [ + {file = "black-24.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6ad001a9ddd9b8dfd1b434d566be39b1cd502802c8d38bbb1ba612afda2ef436"}, + {file = "black-24.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3a3a092b8b756c643fe45f4624dbd5a389f770a4ac294cf4d0fce6af86addaf"}, + {file = "black-24.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dae79397f367ac8d7adb6c779813328f6d690943f64b32983e896bcccd18cbad"}, + {file = "black-24.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:71d998b73c957444fb7c52096c3843875f4b6b47a54972598741fe9a7f737fcb"}, + {file = "black-24.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8e5537f456a22cf5cfcb2707803431d2feeb82ab3748ade280d6ccd0b40ed2e8"}, + {file = "black-24.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64e60a7edd71fd542a10a9643bf369bfd2644de95ec71e86790b063aa02ff745"}, + {file = "black-24.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cd5b4f76056cecce3e69b0d4c228326d2595f506797f40b9233424e2524c070"}, + {file = "black-24.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:64578cf99b6b46a6301bc28bdb89f9d6f9b592b1c5837818a177c98525dbe397"}, + {file = "black-24.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f95cece33329dc4aa3b0e1a771c41075812e46cf3d6e3f1dfe3d91ff09826ed2"}, + {file = "black-24.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4396ca365a4310beef84d446ca5016f671b10f07abdba3e4e4304218d2c71d33"}, + {file = "black-24.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44d99dfdf37a2a00a6f7a8dcbd19edf361d056ee51093b2445de7ca09adac965"}, + {file = "black-24.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:21f9407063ec71c5580b8ad975653c66508d6a9f57bd008bb8691d273705adcd"}, + {file = "black-24.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:652e55bb722ca026299eb74e53880ee2315b181dfdd44dca98e43448620ddec1"}, + {file = "black-24.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7f2966b9b2b3b7104fca9d75b2ee856fe3fdd7ed9e47c753a4bb1a675f2caab8"}, + {file = "black-24.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bb9ca06e556a09f7f7177bc7cb604e5ed2d2df1e9119e4f7d2f1f7071c32e5d"}, + {file = "black-24.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4e71cdebdc8efeb6deaf5f2deb28325f8614d48426bed118ecc2dcaefb9ebf3"}, + {file = "black-24.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6644f97a7ef6f401a150cca551a1ff97e03c25d8519ee0bbc9b0058772882665"}, + {file = "black-24.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:75a2d0b4f5eb81f7eebc31f788f9830a6ce10a68c91fbe0fade34fff7a2836e6"}, + {file = "black-24.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb949f56a63c5e134dfdca12091e98ffb5fd446293ebae123d10fc1abad00b9e"}, + {file = "black-24.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:7852b05d02b5b9a8c893ab95863ef8986e4dda29af80bbbda94d7aee1abf8702"}, + {file = "black-24.4.0-py3-none-any.whl", hash = "sha256:74eb9b5420e26b42c00a3ff470dc0cd144b80a766128b1771d07643165e08d0e"}, + {file = "black-24.4.0.tar.gz", hash = "sha256:f07b69fda20578367eaebbd670ff8fc653ab181e1ff95d84497f9fa20e7d0641"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "cached-property" +version = "1.5.2" +description = "A decorator for caching properties in classes." +optional = false +python-versions = "*" +files = [ + {file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"}, + {file = "cached_property-1.5.2-py2.py3-none-any.whl", hash = "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0"}, +] + [[package]] name = "certifi" version = "2024.2.2" @@ -308,6 +467,17 @@ files = [ {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] +[[package]] +name = "cfgv" +version = "3.4.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + [[package]] name = "charset-normalizer" version = "3.3.2" @@ -407,6 +577,113 @@ files = [ {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] +[[package]] +name = "ckzg" +version = "1.0.0" +description = "Python bindings for C-KZG-4844" +optional = false +python-versions = "*" +files = [ + {file = "ckzg-1.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f40731759b608d74b240fe776853b7b081100d8fc06ac35e22fd0db760b7bcaa"}, + {file = "ckzg-1.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8b5d08189ffda2f869711c4149dc41012f73656bc20606f69b174d15488f6ed1"}, + {file = "ckzg-1.0.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c37af3d01a4b0c3f0a4f51cd0b85df44e30d3686f90c2a7cc84530e4e9d7a00e"}, + {file = "ckzg-1.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1272db9cf5cdd6f564b3de48dae4646d9e04aa10432c0f278ca7c752cf6a333c"}, + {file = "ckzg-1.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5a464900627b66848f4187dd415bea5edf78f3918927bd27461749e75730459"}, + {file = "ckzg-1.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e1d4abc0d58cb04678915ef7c4236834e58774ef692194b9bca15f837a0aaff8"}, + {file = "ckzg-1.0.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9205a6ea38c5e030f6f719b8f8ea6207423378e0339d45db81c946a0818d0f31"}, + {file = "ckzg-1.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9d8c45cd427f34682add5715360b358ffc2cbd9533372470eae12cbb74960042"}, + {file = "ckzg-1.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:91868e2aa17497ea864bb9408269176d961ba56d89543af292556549b18a03b7"}, + {file = "ckzg-1.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cffc3a23ccc967fd7993a9839aa0c133579bfcfd9f124c1ad8916a21c40ed594"}, + {file = "ckzg-1.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9936e5adf2030fc2747aaadc0cbfee6b5a06507e2b74e70998ac4e37cd7203a6"}, + {file = "ckzg-1.0.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a8d97acb5f84cf2c4db0c962ce3aefa2819b10c5b6b9dccf55e83f2a999676"}, + {file = "ckzg-1.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a49bd5dcf288a40df063f7ebd88476fa96a5d22dcbafc843193964993f36e26"}, + {file = "ckzg-1.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1495b5bb9016160a71d5f2727b935cb532d5578b7d29b280f0531b50c5ef1ee"}, + {file = "ckzg-1.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ad39d0549237d136e32263a71182833e26fab8fe8ab62db4d6161b9a7f74623e"}, + {file = "ckzg-1.0.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d5a838b4de4cc0b01a84531a115cf19aa508049c20256e493a2cca98cf806e3e"}, + {file = "ckzg-1.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dfadf8aab3f5a9a94796ba2b688f3679d1d681afe92dfa223da7d4f751fe487d"}, + {file = "ckzg-1.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:6aff64ce8eae856bb5684c76f8e07d4ac31ff07ad46a24bf62c9ea2104975bc9"}, + {file = "ckzg-1.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7b1eed4e35a3fb35f867770eee12018098bd261fa66b768f75b343e0198ff258"}, + {file = "ckzg-1.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3d7f609e943880303ea3f60b0426c9b53a596c74bb09ceed00c917618b519373"}, + {file = "ckzg-1.0.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f8c422673236ea67608c434956181b050039b2f57b1006503eeec574b1af8467"}, + {file = "ckzg-1.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9321226e65868e66edbe18301b8f76f3298d316e6d3a1261371c7fdbc913816"}, + {file = "ckzg-1.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f6fd5bc8c2362483c61adbd00188f7448c968807f00ee067666355c63cf45e0"}, + {file = "ckzg-1.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:be79e3c4a735f5bf4c71cc07a89500448555f2d4f4f765da5867194c7e46ec5c"}, + {file = "ckzg-1.0.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2896c108425b64f6b741cc389beee2b8467a41f8d4f901f4a4ecc037311dc681"}, + {file = "ckzg-1.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fd3f0db4cf514054c386d1a38f9a144725b5109379dd9d2c1b4b0736119f848e"}, + {file = "ckzg-1.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:7a864097cb88be5b7aeff6103bf03d7dfb1c6dda6c8ef82378838ce32e158a15"}, + {file = "ckzg-1.0.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0404db8ded404b36617d60d678d5671652798952571ae4993d4d379ef6563f4f"}, + {file = "ckzg-1.0.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3aee88b228a9ca81d677d57d8d3f6ee483165d8b3955ea408bda674d0f9b4ee5"}, + {file = "ckzg-1.0.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6b4d15188803602afc56e113fc588617219a6316789766fc95e0fa010a93ab"}, + {file = "ckzg-1.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ae6d24e83af8c097b62fdc2183378b9f2d8253fa14ccfc07d075a579f98d876"}, + {file = "ckzg-1.0.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8facda4eafc451bb5f6019a2b779f1b6da7f91322aef0eab1f1d9f542220de1c"}, + {file = "ckzg-1.0.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:4f552fa3b654bc376fcb73e975d521eacff324dba111fa2f0c80c84ad586a0b1"}, + {file = "ckzg-1.0.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:851b7eaca0034b51b6867623b0fae2260466126d8fc669646890464812afd932"}, + {file = "ckzg-1.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:df63d78d9a3d1ffcf32ccb262512c780de42798543affc1209f6fd0cddac49b4"}, + {file = "ckzg-1.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3aefd29f6d339358904ed88e5a642e5bf338fd85151a982a040d4352ae95e53f"}, + {file = "ckzg-1.0.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f2bbbcd24f5ac7f29a0f3f3f51d8934764f5d579e63601a415ace4dad0c2785"}, + {file = "ckzg-1.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ed54765a3067f20786a0c6ee24a8440cfedfe39c5865744c99f605e6ec4249"}, + {file = "ckzg-1.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5101500009a8851843b5aab44bc320b281cfe46ffbbab35f29fa763dc2ac4a2"}, + {file = "ckzg-1.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a35e0f027749a131a5086dcb3f094ec424280cdf7708c24e0c45421a0e9bebf"}, + {file = "ckzg-1.0.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:71860eda6019cc57b197037427ad4078466de232a768fa7c77c7094585689a8d"}, + {file = "ckzg-1.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87729a2e861093d9ee4667dcf047a0073644da7f9de5b9c269821e3c9c3f7164"}, + {file = "ckzg-1.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1d1bd47cfa82f92f14ec77fffee6480b03144f414861fc6664190e89d3aa542d"}, + {file = "ckzg-1.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4644e6e0d66d4a36dc37c2ef64807d1db39bf76b10a933b2f7fbb0b4ee9d991"}, + {file = "ckzg-1.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:96d88c6ea2fd49ecfa16767d05a2d056f1bd1a42b0cf10ab99fb4f88fefab5d7"}, + {file = "ckzg-1.0.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c921b9172aa155ede173abe9d3495c04a55b1afde317339443451e889b531891"}, + {file = "ckzg-1.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a09cce801a20929d49337bd0f1df6d079d5a2ebaa58f58ab8649c706485c759"}, + {file = "ckzg-1.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a02d21ceda0c3bec82342f050de5b22eb4a928be00913fa8992ab0f717095f8"}, + {file = "ckzg-1.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bf751e989a428be569e27010c98192451af4c729d5c27a6e0132647fe93b6e84"}, + {file = "ckzg-1.0.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:37192e9fcbced22e64cd00785ea082bd22254ce7d9cfdfd5364683bea8e1d043"}, + {file = "ckzg-1.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:54808ba5b3692ff31713de6d57c30c21060f11916d2e233f5554fcc85790fcda"}, + {file = "ckzg-1.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:d3b343a4a26d5994bdb39216f5b03bf2345bb6e37ae90fcf7181df37c244217a"}, + {file = "ckzg-1.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:481dfd101acc8a473146b35e61c11cee2ef41210b77775f306c4f1f7f8bdbf28"}, + {file = "ckzg-1.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bd392f3ae05a851f9aa1fc114b565cb7e6744cec39790af56af2adf9dd400f3d"}, + {file = "ckzg-1.0.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2ca50b9d0e947d3b5530dacf25cc00391d041e861751c4872eba4a4567a2efe"}, + {file = "ckzg-1.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91dafec4f72e30176fb9861d0e2ed46cd506f6837ed70066f2136378f5cd84df"}, + {file = "ckzg-1.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c72b07d5cac293d7e49a5510d56163f18cdbf9c7a6c6446422964d5667097c2"}, + {file = "ckzg-1.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:67144d1b545cdd6cb5af38ed2c03b234a24f72b6021ea095b70f0cfe11181bd6"}, + {file = "ckzg-1.0.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43935d730a9ee13ca264455356bdd01055c55c241508f5682d67265379b29dcf"}, + {file = "ckzg-1.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5911419a785c732f0f5edcda89ecc489e7880191b8c0147f629025cb910f913"}, + {file = "ckzg-1.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:8a00c295c5657162c24b162ca9a030fbfbc6930e0782378ce3e3d64b14cf470e"}, + {file = "ckzg-1.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8d272107d63500ba9c62adef39f01835390ee467c2583fd96c78f05773d87b0d"}, + {file = "ckzg-1.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:52bfcad99cc0f5611c3a7e452de4d7fa66ce020327c1c1de425b84b20794687b"}, + {file = "ckzg-1.0.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ae70915d41702d33775d9b81c106b2bff5aa7981f82b06e0c5892daa921ff55"}, + {file = "ckzg-1.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5deaae9151215d1fad3934fa423a87ee752345f665448a30f58bf5c3177c4623"}, + {file = "ckzg-1.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f7e8861174fe26e6bb0f13655aa1f07fd7c3300852748b0f6e47b998153b56b"}, + {file = "ckzg-1.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dc6c211e16ef7750b2579346eaa05e4f1e7f1726effa55c2cb42354603800b01"}, + {file = "ckzg-1.0.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d392ef8281f306a0377f4e5fe816e03e4dce2754a4b2ab209b16d9628b7a0bac"}, + {file = "ckzg-1.0.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52cbe279f5d3ec9dd7745de8e796383ba201302606edaa9838b5dd5a34218241"}, + {file = "ckzg-1.0.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a5d3367cee7ebb48131acc78ca3fb0565e3af3fd8fa8eb4ca25bb88577692c4"}, + {file = "ckzg-1.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55e8c6d8df9dc1bdd3862114e239c292f9bdd92d67055ca4e0e7503826e6524f"}, + {file = "ckzg-1.0.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:b040396df453b51cd5f1461bec9b942173b95ca181c7f65caa10c0204cb6144a"}, + {file = "ckzg-1.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7951c53321136aabdab64dc389c92ffeda5859d59304b97092e893a6b09e9722"}, + {file = "ckzg-1.0.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:56256067d31eb6eed1a42c9f3038936aeb7decee322aa13a3224b51cfa3e8026"}, + {file = "ckzg-1.0.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c166f254ce3434dd0d56ef64788fc9637d60721f4e7e126b15a847abb9a44962"}, + {file = "ckzg-1.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab02c7ad64fb8616a430b05ad2f8fa4f3fc0a22e3dd4ea7a5d5fa4362534bb21"}, + {file = "ckzg-1.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63bb5e6bc4822c732270c70ef12522b0215775ff61cae04fb54983973aef32e3"}, + {file = "ckzg-1.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:409f1f18dbc92df5ddbf1ff0d154dc2280a495ec929a4fa27abc69eeacf31ff0"}, + {file = "ckzg-1.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2eceae0ef7189d47bd89fd9efd9d8f54c5b06bc92c435ec00c62815363cd9d79"}, + {file = "ckzg-1.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e189c00a0030d1a593b020264d7f9b30fa0b980d108923f353c565c206a99147"}, + {file = "ckzg-1.0.0-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36735543ce3aec4730e7128690265ef90781d28e9b56c039c72b6b2ce9b06839"}, + {file = "ckzg-1.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fef5f276e24f4bdd19e28ddcc5212e9b6c8514d3c7426bd443c9221f348c176f"}, + {file = "ckzg-1.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d02164a0d84e55965c14132f6d43cc367be3d12eb318f79ba2f262dac47665c2"}, + {file = "ckzg-1.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:88fafab3493a12d5212374889783352bb4b59dddc9e61c86d063358eff6da7bb"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + [[package]] name = "colorama" version = "0.4.6" @@ -418,6 +695,73 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "coverage" +version = "7.4.4" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2"}, + {file = "coverage-7.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c"}, + {file = "coverage-7.4.4-cp310-cp310-win32.whl", hash = "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d"}, + {file = "coverage-7.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b"}, + {file = "coverage-7.4.4-cp311-cp311-win32.whl", hash = "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286"}, + {file = "coverage-7.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9"}, + {file = "coverage-7.4.4-cp312-cp312-win32.whl", hash = "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0"}, + {file = "coverage-7.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c"}, + {file = "coverage-7.4.4-cp38-cp38-win32.whl", hash = "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e"}, + {file = "coverage-7.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade"}, + {file = "coverage-7.4.4-cp39-cp39-win32.whl", hash = "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57"}, + {file = "coverage-7.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c"}, + {file = "coverage-7.4.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677"}, + {file = "coverage-7.4.4.tar.gz", hash = "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + [[package]] name = "cytoolz" version = "0.12.3" @@ -537,6 +881,39 @@ toolz = ">=0.8.0" [package.extras] cython = ["cython"] +[[package]] +name = "datamodel-code-generator" +version = "0.25.5" +description = "Datamodel Code Generator" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "datamodel_code_generator-0.25.5-py3-none-any.whl", hash = "sha256:3b62b42c8ebf2bb98cfbc24467b523c5b76780c585b72f4ac2fc1f1f576702ab"}, + {file = "datamodel_code_generator-0.25.5.tar.gz", hash = "sha256:545f897481a94781e32b3c26a452ce049320b091310729f7fc6fa780f6a87898"}, +] + +[package.dependencies] +argcomplete = ">=1.10,<4.0" +black = ">=19.10b0" +genson = ">=1.2.1,<2.0" +inflect = ">=4.1.0,<6.0" +isort = ">=4.3.21,<6.0" +jinja2 = ">=2.10.1,<4.0" +packaging = "*" +pydantic = [ + {version = ">=1.10.0,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.4.0 || >2.4.0,<3.0", extras = ["email"], markers = "python_version >= \"3.12\" and python_version < \"4.0\""}, + {version = ">=1.10.0,<2.4.0 || >2.4.0,<3.0", extras = ["email"], markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, + {version = ">=1.9.0,<2.4.0 || >2.4.0,<3.0", extras = ["email"], markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, +] +pyyaml = ">=6.0.1" +toml = {version = ">=0.10.0,<1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +debug = ["PySnooper (>=0.4.1,<2.0.0)"] +graphql = ["graphql-core (>=3.2.3,<4.0.0)"] +http = ["httpx"] +validation = ["openapi-spec-validator (>=0.2.8,<0.7.0)", "prance (>=0.18.2)"] + [[package]] name = "decorator" version = "5.1.1" @@ -548,41 +925,88 @@ files = [ {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, ] +[[package]] +name = "distlib" +version = "0.3.8" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, +] + +[[package]] +name = "dnspython" +version = "2.6.1" +description = "DNS toolkit" +optional = false +python-versions = ">=3.8" +files = [ + {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, + {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, +] + +[package.extras] +dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] +dnssec = ["cryptography (>=41)"] +doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] +doq = ["aioquic (>=0.9.25)"] +idna = ["idna (>=3.6)"] +trio = ["trio (>=0.23)"] +wmi = ["wmi (>=1.5.1)"] + +[[package]] +name = "email-validator" +version = "2.1.1" +description = "A robust email address syntax and deliverability validation library." +optional = false +python-versions = ">=3.8" +files = [ + {file = "email_validator-2.1.1-py3-none-any.whl", hash = "sha256:97d882d174e2a65732fb43bfce81a3a834cbc1bde8bf419e30ef5ea976370a05"}, + {file = "email_validator-2.1.1.tar.gz", hash = "sha256:200a70680ba08904be6d1eef729205cc0d687634399a5924d842533efb824b84"}, +] + +[package.dependencies] +dnspython = ">=2.0.0" +idna = ">=2.0.0" + [[package]] name = "eth-abi" -version = "5.0.0" +version = "5.1.0" description = "eth_abi: Python utilities for working with Ethereum ABI definitions, especially encoding and decoding" optional = false -python-versions = ">=3.8, <4" +python-versions = "<4,>=3.8" files = [ - {file = "eth_abi-5.0.0-py3-none-any.whl", hash = "sha256:936a715d7366ac13cac665cbdaf01cc4aabbe8c2d810d716287a9634f9665e01"}, - {file = "eth_abi-5.0.0.tar.gz", hash = "sha256:89c4454d794d9ed92ad5cb2794698c5cee6b7b3ca6009187d0e282adc7f9b6dc"}, + {file = "eth_abi-5.1.0-py3-none-any.whl", hash = "sha256:84cac2626a7db8b7d9ebe62b0fdca676ab1014cc7f777189e3c0cd721a4c16d8"}, + {file = "eth_abi-5.1.0.tar.gz", hash = "sha256:33ddd756206e90f7ddff1330cc8cac4aa411a824fe779314a0a52abea2c8fc14"}, ] [package.dependencies] eth-typing = ">=3.0.0" eth-utils = ">=2.0.0" -parsimonious = ">=0.9.0,<0.10.0" +parsimonious = ">=0.10.0,<0.11.0" [package.extras] -dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "hypothesis (>=4.18.2,<5.0.0)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-pythonpath (>=0.7.1)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "hypothesis (>=4.18.2,<5.0.0)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-pythonpath (>=0.7.1)", "pytest-timeout (>=2.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -test = ["eth-hash[pycryptodome]", "hypothesis (>=4.18.2,<5.0.0)", "pytest (>=7.0.0)", "pytest-pythonpath (>=0.7.1)", "pytest-xdist (>=2.4.0)"] +test = ["eth-hash[pycryptodome]", "hypothesis (>=4.18.2,<5.0.0)", "pytest (>=7.0.0)", "pytest-pythonpath (>=0.7.1)", "pytest-timeout (>=2.0.0)", "pytest-xdist (>=2.4.0)"] tools = ["hypothesis (>=4.18.2,<5.0.0)"] [[package]] name = "eth-account" -version = "0.11.0" +version = "0.11.2" description = "eth-account: Sign Ethereum transactions and messages with local private keys" optional = false -python-versions = ">=3.8, <4" +python-versions = "<4,>=3.8" files = [ - {file = "eth-account-0.11.0.tar.gz", hash = "sha256:2ffc7a0c7538053a06a7d11495c16c7ad9897dd42be0f64ca7551e9f6e0738c3"}, - {file = "eth_account-0.11.0-py3-none-any.whl", hash = "sha256:76dd261ea096ee09e51455b0a4c99f22185516fdc062f63df0817c28f605e430"}, + {file = "eth-account-0.11.2.tar.gz", hash = "sha256:b43daf2c0ae43f2a24ba754d66889f043fae4d3511559cb26eb0122bae9afbbd"}, + {file = "eth_account-0.11.2-py3-none-any.whl", hash = "sha256:95157c262a9823c1e08be826d4bc304bf32f0c32e80afb38c126a325a64f651a"}, ] [package.dependencies] bitarray = ">=2.4.0" +ckzg = ">=0.4.3" eth-abi = ">=4.0.0-b.2" eth-keyfile = ">=0.6.0" eth-keys = ">=0.4.0" @@ -596,19 +1020,39 @@ dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "coverage", "hypothesis (>=4. docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] test = ["coverage", "hypothesis (>=4.18.0,<5)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] +[[package]] +name = "eth-bloom" +version = "3.0.0" +description = "A python implementation of the bloom filter used by Ethereum" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "eth-bloom-3.0.0.tar.gz", hash = "sha256:94bab384b01f2eb1012abbd6bb504e4c743878414d8695ee5a5d25f4247b3886"}, + {file = "eth_bloom-3.0.0-py3-none-any.whl", hash = "sha256:bb884ece93d292dfbbe4696744db874a88ac5bfc45f6f1b0ee147d801604a46c"}, +] + +[package.dependencies] +eth-hash = {version = ">=0.4.0", extras = ["pycryptodome"]} + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "hypothesis (>=3.31.2)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["towncrier (>=21,<22)"] +test = ["hypothesis (>=3.31.2)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + [[package]] name = "eth-hash" -version = "0.6.0" +version = "0.7.0" description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" optional = false python-versions = ">=3.8, <4" files = [ - {file = "eth-hash-0.6.0.tar.gz", hash = "sha256:ae72889e60db6acbb3872c288cfa02ed157f4c27630fcd7f9c8442302c31e478"}, - {file = "eth_hash-0.6.0-py3-none-any.whl", hash = "sha256:9f8daaa345764f8871dc461855049ac54ae4291d780279bce6fce7f24e3f17d3"}, + {file = "eth-hash-0.7.0.tar.gz", hash = "sha256:bacdc705bfd85dadd055ecd35fd1b4f846b671add101427e089a4ca2e8db310a"}, + {file = "eth_hash-0.7.0-py3-none-any.whl", hash = "sha256:b8d5a230a2b251f4a291e3164a23a14057c4a6de4b0aa4a16fa4dc9161b57e2f"}, ] [package.dependencies] pycryptodome = {version = ">=3.6.6,<4", optional = true, markers = "extra == \"pycryptodome\""} +safe-pysha3 = {version = ">=1.0.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"pysha3\""} [package.extras] dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] @@ -619,13 +1063,13 @@ test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "eth-keyfile" -version = "0.7.0" +version = "0.8.0" description = "eth-keyfile: A library for handling the encrypted keyfiles used to store ethereum private keys" optional = false python-versions = ">=3.8, <4" files = [ - {file = "eth-keyfile-0.7.0.tar.gz", hash = "sha256:6bdb8110c3a50439deb68a04c93c9d5ddd5402353bfae1bf4cfca1d6dff14fcf"}, - {file = "eth_keyfile-0.7.0-py3-none-any.whl", hash = "sha256:6a89b231a2fe250c3a8f924f2695bb9cce33ddd0d6f7ebbcdacd183d7f83d537"}, + {file = "eth-keyfile-0.8.0.tar.gz", hash = "sha256:02e3c2e564c7403b92db3fef8ecae3d21123b15787daecd5b643a57369c530f9"}, + {file = "eth_keyfile-0.8.0-py3-none-any.whl", hash = "sha256:9e09f5bc97c8309876c06bdea7a94f0051c25ba3109b5df37afb815418322efe"}, ] [package.dependencies] @@ -674,21 +1118,53 @@ files = [ eth-utils = ">=2.0.0" hexbytes = ">=0.1.0,<1" rlp = ">=0.6.0" +typing-extensions = {version = ">=4.0.1", markers = "python_version <= \"3.11\""} [package.extras] dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] test = ["eth-hash[pycryptodome]", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] +[[package]] +name = "eth-tester" +version = "0.11.0b1" +description = "eth-tester: Tools for testing Ethereum applications." +optional = false +python-versions = "<4,>=3.8" +files = [ + {file = "eth-tester-0.11.0b1.tar.gz", hash = "sha256:8f9985037bbe6057cfff705063add5de506d75b725740bc44fb5ac03cc7b5130"}, + {file = "eth_tester-0.11.0b1-py3-none-any.whl", hash = "sha256:5ac85ff048ce2a5415aa5624d99093ad8b7d1f1f80e23b6d220ca5432839fb00"}, +] + +[package.dependencies] +eth-abi = ">=3.0.1" +eth-account = ">=0.11.2" +eth-hash = [ + {version = ">=0.1.4,<1.0.0", extras = ["pysha3"], optional = true, markers = "implementation_name == \"cpython\" and extra == \"py-evm\""}, + {version = ">=0.1.4,<1.0.0", extras = ["pycryptodome"], optional = true, markers = "implementation_name == \"pypy\" and extra == \"py-evm\""}, +] +eth-keys = ">=0.4.0" +eth-utils = ">=2.0.0" +py-evm = {version = ">=0.10.0b0,<0.11.0b0", optional = true, markers = "extra == \"py-evm\""} +rlp = ">=3.0.0" +semantic-version = ">=2.6.0" + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome] (>=0.1.4,<1.0.0)", "eth-hash[pycryptodome] (>=0.1.4,<1.0.0)", "eth-hash[pysha3] (>=0.1.4,<1.0.0)", "ipython", "pre-commit (>=3.4.0)", "py-evm (>=0.10.0b0,<0.11.0b0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.0.0,<3)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["towncrier (>=21,<22)"] +py-evm = ["eth-hash[pycryptodome] (>=0.1.4,<1.0.0)", "eth-hash[pysha3] (>=0.1.4,<1.0.0)", "py-evm (>=0.10.0b0,<0.11.0b0)"] +pyevm = ["eth-hash[pycryptodome] (>=0.1.4,<1.0.0)", "eth-hash[pysha3] (>=0.1.4,<1.0.0)", "py-evm (>=0.10.0b0,<0.11.0b0)"] +test = ["eth-hash[pycryptodome] (>=0.1.4,<1.0.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.0.0,<3)"] + [[package]] name = "eth-typing" -version = "4.0.0" +version = "4.1.0" description = "eth-typing: Common type annotations for ethereum python packages" optional = false -python-versions = ">=3.8, <4" +python-versions = "<4,>=3.8" files = [ - {file = "eth-typing-4.0.0.tar.gz", hash = "sha256:9af0b6beafbc5c2e18daf19da5f5a68315023172c4e79d149e12ad10a3d3f731"}, - {file = "eth_typing-4.0.0-py3-none-any.whl", hash = "sha256:7e556bea322b6e8c0a231547b736c258e10ce9eed5ddc254f51031b12af66a16"}, + {file = "eth-typing-4.1.0.tar.gz", hash = "sha256:ed52b0c6b049240fd810bc87c8857c7ea39370f060f70b9ca3876285269f2938"}, + {file = "eth_typing-4.1.0-py3-none-any.whl", hash = "sha256:1f1b16bf37bfe0be730731fd24c7398e931a2b45a8feebf82df2e77a611a23be"}, ] [package.extras] @@ -698,13 +1174,13 @@ test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "eth-utils" -version = "3.0.0" +version = "4.1.0" description = "eth-utils: Common utility functions for python code that interacts with Ethereum" optional = false -python-versions = ">=3.8, <4" +python-versions = "<4,>=3.8" files = [ - {file = "eth-utils-3.0.0.tar.gz", hash = "sha256:8721869568448349bceae63c277b75758d11e0dc190e7ef31e161b89619458f1"}, - {file = "eth_utils-3.0.0-py3-none-any.whl", hash = "sha256:9a284106acf6f6ce91ddf792489cf8bd4c681fd5ae7653d2f3d5d100be5c3905"}, + {file = "eth-utils-4.1.0.tar.gz", hash = "sha256:c170168198ddecac1ea911f74937e9364de81dbd03f42450fe40725c4d6e6220"}, + {file = "eth_utils-4.1.0-py3-none-any.whl", hash = "sha256:f2e0f617edc81e53fad0faca7f7b169e56bef59ecc530d919a7482640236a228"}, ] [package.dependencies] @@ -718,6 +1194,20 @@ dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "hy docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] test = ["hypothesis (>=4.43.0)", "mypy (==1.5.1)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] +[[package]] +name = "exceptiongroup" +version = "1.2.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "executing" version = "2.0.1" @@ -732,6 +1222,22 @@ files = [ [package.extras] tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] +[[package]] +name = "filelock" +version = "3.13.4" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.8" +files = [ + {file = "filelock-3.13.4-py3-none-any.whl", hash = "sha256:404e5e9253aa60ad457cae1be07c0f0ca90a63931200a47d9b6a6af84fd7b45f"}, + {file = "filelock-3.13.4.tar.gz", hash = "sha256:d13f466618bfde72bd2c18255e269f72542c6e70e7bac83a0232d6b1cc5c8cf4"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] + [[package]] name = "frozenlist" version = "1.4.1" @@ -818,6 +1324,27 @@ files = [ {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, ] +[[package]] +name = "genson" +version = "1.2.2" +description = "GenSON is a powerful, user-friendly JSON Schema generator." +optional = false +python-versions = "*" +files = [ + {file = "genson-1.2.2.tar.gz", hash = "sha256:8caf69aa10af7aee0e1a1351d1d06801f4696e005f06cedef438635384346a16"}, +] + +[[package]] +name = "graphql-core" +version = "3.2.3" +description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." +optional = false +python-versions = ">=3.6,<4" +files = [ + {file = "graphql-core-3.2.3.tar.gz", hash = "sha256:06d2aad0ac723e35b1cb47885d3e5c45e956a53bc1b209a9fc5369007fe46676"}, + {file = "graphql_core-3.2.3-py3-none-any.whl", hash = "sha256:5766780452bd5ec8ba133f8bf287dc92713e3868ddd83aee4faab9fc3e303dc3"}, +] + [[package]] name = "h11" version = "0.14.0" @@ -848,13 +1375,13 @@ test = ["eth-utils (>=1.0.1,<3)", "hypothesis (>=3.44.24,<=6.31.6)", "pytest (>= [[package]] name = "httpcore" -version = "1.0.3" +version = "1.0.5" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.3-py3-none-any.whl", hash = "sha256:9a6a501c3099307d9fd76ac244e08503427679b1e81ceb1d922485e2f2462ad2"}, - {file = "httpcore-1.0.3.tar.gz", hash = "sha256:5c0f9546ad17dac4d0772b0808856eb616eb8b48ce94f49ed819fd6982a8a544"}, + {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, + {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, ] [package.dependencies] @@ -865,17 +1392,17 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.24.0)"] +trio = ["trio (>=0.22.0,<0.26.0)"] [[package]] name = "httpx" -version = "0.26.0" +version = "0.27.0" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpx-0.26.0-py3-none-any.whl", hash = "sha256:8915f5a3627c4d47b73e8202457cb28f1266982d1159bd5779d86a80c0eab1cd"}, - {file = "httpx-0.26.0.tar.gz", hash = "sha256:451b55c30d5185ea6b23c2c793abf9bb237d2a7dfb901ced6ff69ad37ec1dfaf"}, + {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, + {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, ] [package.dependencies] @@ -891,17 +1418,46 @@ cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +[[package]] +name = "identify" +version = "2.5.35" +description = "File identification library for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "identify-2.5.35-py2.py3-none-any.whl", hash = "sha256:c4de0081837b211594f8e877a6b4fad7ca32bbfc1a9307fdd61c28bfe923f13e"}, + {file = "identify-2.5.35.tar.gz", hash = "sha256:10a7ca245cfcd756a554a7288159f72ff105ad233c7c4b9c6f0f4d108f5f6791"}, +] + +[package.extras] +license = ["ukkonen"] + [[package]] name = "idna" -version = "3.6" +version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] +[[package]] +name = "inflect" +version = "5.6.2" +description = "Correctly generate plurals, singular nouns, ordinals, indefinite articles; convert numbers to words" +optional = false +python-versions = ">=3.7" +files = [ + {file = "inflect-5.6.2-py3-none-any.whl", hash = "sha256:b45d91a4a28a4e617ff1821117439b06eaa86e2a4573154af0149e9be6687238"}, + {file = "inflect-5.6.2.tar.gz", hash = "sha256:aadc7ed73928f5e014129794bbac03058cca35d0a973a5fc4eb45c7fa26005f9"}, +] + +[package.extras] +docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"] +testing = ["pygments", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -915,38 +1471,55 @@ files = [ [[package]] name = "ipython" -version = "8.21.0" +version = "8.23.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" files = [ - {file = "ipython-8.21.0-py3-none-any.whl", hash = "sha256:1050a3ab8473488d7eee163796b02e511d0735cf43a04ba2a8348bd0f2eaf8a5"}, - {file = "ipython-8.21.0.tar.gz", hash = "sha256:48fbc236fbe0e138b88773fa0437751f14c3645fb483f1d4c5dee58b37e5ce73"}, + {file = "ipython-8.23.0-py3-none-any.whl", hash = "sha256:07232af52a5ba146dc3372c7bf52a0f890a23edf38d77caef8d53f9cdc2584c1"}, + {file = "ipython-8.23.0.tar.gz", hash = "sha256:7468edaf4f6de3e1b912e57f66c241e6fd3c7099f2ec2136e239e142e800274d"}, ] [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} decorator = "*" +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} jedi = ">=0.16" matplotlib-inline = "*" -pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} prompt-toolkit = ">=3.0.41,<3.1.0" pygments = ">=2.4.0" stack-data = "*" -traitlets = ">=5" +traitlets = ">=5.13.0" +typing-extensions = {version = "*", markers = "python_version < \"3.12\""} [package.extras] -all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.23)", "pandas", "pickleshare", "pytest (<8)", "pytest-asyncio (<0.22)", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] black = ["black"] -doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest (<8)", "pytest-asyncio (<0.22)", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "stack-data", "typing-extensions"] kernel = ["ipykernel"] +matplotlib = ["matplotlib"] nbconvert = ["nbconvert"] nbformat = ["nbformat"] notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] test = ["pickleshare", "pytest (<8)", "pytest-asyncio (<0.22)", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "pickleshare", "pytest (<8)", "pytest-asyncio (<0.22)", "testpath", "trio"] +test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] + +[[package]] +name = "isort" +version = "5.13.2" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, +] + +[package.extras] +colors = ["colorama (>=0.4.6)"] [[package]] name = "jedi" @@ -967,6 +1540,23 @@ docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alab qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] +[[package]] +name = "jinja2" +version = "3.1.3" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + [[package]] name = "jsonschema" version = "4.21.1" @@ -1002,6 +1592,46 @@ files = [ [package.dependencies] referencing = ">=0.31.0" +[[package]] +name = "libcst" +version = "1.3.1" +description = "A concrete syntax tree with AST-like properties for Python 3.0 through 3.12 programs." +optional = false +python-versions = ">=3.9" +files = [ + {file = "libcst-1.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:de93193cba6d54f2a4419e94ba2de642b111f52e4fa01bb6e2c655914585f65b"}, + {file = "libcst-1.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2d64d86dcd6c80a5dac2e243c5ed7a7a193242209ac33bad4b0639b24f6d131"}, + {file = "libcst-1.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db084f7bbf825c7bd5ed256290066d0336df6a7dc3a029c9870a64cd2298b87f"}, + {file = "libcst-1.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16880711be03a1f5da7028fe791ba5b482a50d830225a70272dc332dfd927652"}, + {file = "libcst-1.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:189bb28c19c5dd3c64583f969b72f7732dbdb1dee9eca3acc85099e4cef9148b"}, + {file = "libcst-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:181372386c986e3de07d7a93f269214cd825adc714f1f9da8252b44f05e181c4"}, + {file = "libcst-1.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8c2020f7449270e3ff0bdc481ae244d812f2d9a8b7dbff0ea66b830f4b350f54"}, + {file = "libcst-1.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:be3bf9aaafebda6a21e241e819f0ab67e186e898c3562704e41241cf8738353a"}, + {file = "libcst-1.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a0d250fb6a2c1d158f30d25ba5e33e3ed3672d2700d480dd47beffd1431a008"}, + {file = "libcst-1.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ad5741b251d901f3da1819ac539192230cc6f8f81aaf04eb4ec0009c1c97285"}, + {file = "libcst-1.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b740dc0c3d1adbd91442fb878343d5a11e23a0e3ac5484be301fd8d148bcb085"}, + {file = "libcst-1.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:9e6bc95fa7dde79cde63a34a0412cd4a3d9fcc27be781a590f8c45c840c83658"}, + {file = "libcst-1.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4186076ce12141609ce950d61867b2a73ea199a7a9870dbafa76ad600e075b3c"}, + {file = "libcst-1.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4ed52a1a2fe4d8603de51649db5e438317b8116ebb9fc09ec68703535fe6c1c8"}, + {file = "libcst-1.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0886a9963597367b227345f19b24931b3ed6a4703fff237760745f90f0e6a20"}, + {file = "libcst-1.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:904c4cc5c801a5747e64b43e0accc87c67a4c804842d977ee215872c4cf8cf88"}, + {file = "libcst-1.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cdb7e8a118b60e064a02f6cbfa4d328212a3a115d125244495190f405709d5f"}, + {file = "libcst-1.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:431badf0e544b79c0ac9682dbd291ff63ddbc3c3aca0d13d3cc7a10c3a9db8a2"}, + {file = "libcst-1.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:701f5335e4fd566871497b9af1e871c98e1ef10c30b3b244f39343d709213401"}, + {file = "libcst-1.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7c6e709623b68ca9148e8ecbdc145f7b83befb26032e4bf6a8122500ba558b17"}, + {file = "libcst-1.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ede0f026a82b03b33a559ec566860085ece2e76d8f9bc21cb053eedf9cde8c79"}, + {file = "libcst-1.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c12b7b01d8745f82dd86a82acd2a9f8e8e7d6c94ddcfda996896e83d1a8d5c42"}, + {file = "libcst-1.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2995ca687118a9d3d41876f7270bc29305a2d402f4b8c81a3cff0aeee6d4c81"}, + {file = "libcst-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:2dbac1ac0a9d59ea7bbc3f87cdcca5bfe98835e31c668e95cb6f3d907ffc53fc"}, + {file = "libcst-1.3.1.tar.gz", hash = "sha256:03b1df1ae02456f1d465fcd5ead1d0d454bb483caefd8c8e6bde515ffdb53d1b"}, +] + +[package.dependencies] +pyyaml = ">=5.2" + +[package.extras] +dev = ["Sphinx (>=5.1.1)", "black (==23.12.1)", "build (>=0.10.0)", "coverage (>=4.5.4)", "fixit (==2.1.0)", "flake8 (==7.0.0)", "hypothesis (>=4.36.0)", "hypothesmith (>=0.0.4)", "jinja2 (==3.1.3)", "jupyter (>=1.0.0)", "maturin (>=0.8.3,<1.5)", "nbsphinx (>=0.4.2)", "prompt-toolkit (>=2.0.9)", "pyre-check (==0.9.18)", "setuptools-rust (>=1.5.2)", "setuptools-scm (>=6.0.1)", "slotscheck (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "ufmt (==2.5.1)", "usort (==1.0.8.post1)"] + [[package]] name = "lru-dict" version = "1.2.0" @@ -1096,20 +1726,124 @@ files = [ [package.extras] test = ["pytest"] +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + [[package]] name = "matplotlib-inline" -version = "0.1.6" +version = "0.1.7" description = "Inline Matplotlib backend for Jupyter" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, - {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, + {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, + {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, ] [package.dependencies] traitlets = "*" +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + [[package]] name = "multidict" version = "6.0.5" @@ -1209,6 +1943,17 @@ files = [ {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, ] +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + [[package]] name = "nodeenv" version = "1.8.0" @@ -1225,23 +1970,24 @@ setuptools = "*" [[package]] name = "packaging" -version = "23.2" +version = "24.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] [[package]] name = "parsimonious" -version = "0.9.0" +version = "0.10.0" description = "(Soon to be) the fastest pure-Python PEG parser I could muster" optional = false python-versions = "*" files = [ - {file = "parsimonious-0.9.0.tar.gz", hash = "sha256:b2ad1ae63a2f65bd78f5e0a8ac510a98f3607a43f1db2a8d46636a5d9e4a30c1"}, + {file = "parsimonious-0.10.0-py3-none-any.whl", hash = "sha256:982ab435fabe86519b57f6b35610aa4e4e977e9f02a14353edf4bbc75369fc0f"}, + {file = "parsimonious-0.10.0.tar.gz", hash = "sha256:8281600da180ec8ae35427a4ab4f7b82bfec1e3d1e52f80cb60ea82b9512501c"}, ] [package.dependencies] @@ -1249,18 +1995,29 @@ regex = ">=2022.3.15" [[package]] name = "parso" -version = "0.8.3" +version = "0.8.4" description = "A Python Parser" optional = false python-versions = ">=3.6" files = [ - {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, - {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, + {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, + {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, ] [package.extras] -qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["docopt", "pytest (<6.0.0)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["docopt", "pytest"] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] [[package]] name = "pexpect" @@ -1276,6 +2033,21 @@ files = [ [package.dependencies] ptyprocess = ">=0.5" +[[package]] +name = "platformdirs" +version = "4.2.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] + [[package]] name = "pluggy" version = "1.4.0" @@ -1291,6 +2063,24 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "pre-commit" +version = "3.7.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.9" +files = [ + {file = "pre_commit-3.7.0-py2.py3-none-any.whl", hash = "sha256:5eae9e10c2b5ac51577c3452ec0a490455c45a0533f7960f993a0d01e59decab"}, + {file = "pre_commit-3.7.0.tar.gz", hash = "sha256:e209d61b8acdcf742404408531f0c37d49d2c734fd7cff2d6076083d191cb060"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + [[package]] name = "prompt-toolkit" version = "3.0.43" @@ -1307,22 +2097,22 @@ wcwidth = "*" [[package]] name = "protobuf" -version = "4.25.3" +version = "5.26.1" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"}, - {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"}, - {file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"}, - {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"}, - {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"}, - {file = "protobuf-4.25.3-cp38-cp38-win32.whl", hash = "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2"}, - {file = "protobuf-4.25.3-cp38-cp38-win_amd64.whl", hash = "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4"}, - {file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"}, - {file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"}, - {file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"}, - {file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"}, + {file = "protobuf-5.26.1-cp310-abi3-win32.whl", hash = "sha256:3c388ea6ddfe735f8cf69e3f7dc7611e73107b60bdfcf5d0f024c3ccd3794e23"}, + {file = "protobuf-5.26.1-cp310-abi3-win_amd64.whl", hash = "sha256:e6039957449cb918f331d32ffafa8eb9255769c96aa0560d9a5bf0b4e00a2a33"}, + {file = "protobuf-5.26.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:38aa5f535721d5bb99861166c445c4105c4e285c765fbb2ac10f116e32dcd46d"}, + {file = "protobuf-5.26.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:fbfe61e7ee8c1860855696e3ac6cfd1b01af5498facc6834fcc345c9684fb2ca"}, + {file = "protobuf-5.26.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:f7417703f841167e5a27d48be13389d52ad705ec09eade63dfc3180a959215d7"}, + {file = "protobuf-5.26.1-cp38-cp38-win32.whl", hash = "sha256:d693d2504ca96750d92d9de8a103102dd648fda04540495535f0fec7577ed8fc"}, + {file = "protobuf-5.26.1-cp38-cp38-win_amd64.whl", hash = "sha256:9b557c317ebe6836835ec4ef74ec3e994ad0894ea424314ad3552bc6e8835b4e"}, + {file = "protobuf-5.26.1-cp39-cp39-win32.whl", hash = "sha256:b9ba3ca83c2e31219ffbeb9d76b63aad35a3eb1544170c55336993d7a18ae72c"}, + {file = "protobuf-5.26.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ee014c2c87582e101d6b54260af03b6596728505c79f17c8586e7523aaa8f8c"}, + {file = "protobuf-5.26.1-py3-none-any.whl", hash = "sha256:da612f2720c0183417194eeaa2523215c4fcc1a1949772dc65f05047e08d5932"}, + {file = "protobuf-5.26.1.tar.gz", hash = "sha256:8ca2a1d97c290ec7b16e4e5dff2e5ae150cc1582f55b5ab300d45cb0dfa90e51"}, ] [[package]] @@ -1350,6 +2140,107 @@ files = [ [package.extras] tests = ["pytest"] +[[package]] +name = "py-ecc" +version = "7.0.0" +description = "py-ecc: Elliptic curve crypto in python including secp256k1, alt_bn128, and bls12_381" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "py-ecc-7.0.0.tar.gz", hash = "sha256:c141e7330559758d2233adaf0af1f05ec4cade67e7fa35fc118750ce79d83257"}, + {file = "py_ecc-7.0.0-py3-none-any.whl", hash = "sha256:a655fa499ab2e695c9d4e49be19e40ad195dd61076642edcbcbb5b7c645820cf"}, +] + +[package.dependencies] +cached-property = ">=1.5.1" +eth-typing = ">=3.0.0" +eth-utils = ">=2.0.0" + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "py-evm" +version = "0.10.0b6" +description = "Python implementation of the Ethereum Virtual Machine" +optional = false +python-versions = "<4,>=3.8" +files = [ + {file = "py_evm-0.10.0b6-py3-none-any.whl", hash = "sha256:98d886d7d50937924cfb3d6607c9ec7259c91b082ce4972a569a89b363d7be32"}, +] + +[package.dependencies] +cached-property = ">=1.5.1" +ckzg = ">=0.4.3" +eth-bloom = ">=1.0.3" +eth-keys = ">=0.4.0" +eth-typing = ">=3.3.0" +eth-utils = ">=2.0.0" +lru-dict = ">=1.1.6" +py-ecc = ">=1.4.7" +rlp = ">=3.0.0" +trie = ">=2.0.0" + +[package.extras] +benchmark = ["termcolor (>=1.1.0)", "web3 (>=6.0.0)"] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "cached-property (>=1.5.1)", "ckzg (>=0.4.3)", "eth-bloom (>=1.0.3)", "eth-keys (>=0.4.0)", "eth-typing (>=3.3.0)", "eth-utils (>=2.0.0)", "factory-boy (>=3.0.0)", "hypothesis (>=5,<6)", "ipython", "lru-dict (>=1.1.6)", "pre-commit (>=3.4.0)", "py-ecc (>=1.4.7)", "py-evm (>=0.8.0b1)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.20.0)", "pytest-cov (>=4.0.0)", "pytest-timeout (>=2.0.0)", "pytest-xdist (>=3.0)", "rlp (>=3.0.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "sphinxcontrib-asyncio (>=0.2.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "trie (>=2.0.0)", "twine", "wheel"] +docs = ["py-evm (>=0.8.0b1)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "sphinxcontrib-asyncio (>=0.2.0)", "towncrier (>=21,<22)"] +eth = ["cached-property (>=1.5.1)", "ckzg (>=0.4.3)", "eth-bloom (>=1.0.3)", "eth-keys (>=0.4.0)", "eth-typing (>=3.3.0)", "eth-utils (>=2.0.0)", "lru-dict (>=1.1.6)", "py-ecc (>=1.4.7)", "rlp (>=3.0.0)", "trie (>=2.0.0)"] +eth-extra = ["blake2b-py (>=0.2.0)", "coincurve (>=18.0.0)"] +test = ["factory-boy (>=3.0.0)", "hypothesis (>=5,<6)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.20.0)", "pytest-cov (>=4.0.0)", "pytest-timeout (>=2.0.0)", "pytest-xdist (>=3.0)"] + +[[package]] +name = "py-geth" +version = "4.4.0" +description = "py-geth: Run Go-Ethereum as a subprocess" +optional = false +python-versions = "<4,>=3.8" +files = [ + {file = "py-geth-4.4.0.tar.gz", hash = "sha256:c08d84f6dad4f86a9b8ffd74c0a0f160d600db0ee45dfc2a66d5e13522aeb039"}, + {file = "py_geth-4.4.0-py3-none-any.whl", hash = "sha256:ae8771b028c68f6710e6434d2aa1310ce2ba3cc9099d244d9bb5a9e340786a92"}, +] + +[package.dependencies] +semantic-version = ">=2.6.0" + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "flaky (>=3.2.0)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "requests (>=2.20)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["towncrier (>=21,<22)"] +test = ["flaky (>=3.2.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "pybars3" +version = "0.9.7" +description = "Handlebars.js templating for Python 3 and 2" +optional = false +python-versions = "*" +files = [ + {file = "pybars3-0.9.7.tar.gz", hash = "sha256:6ac847e905e53b9c5b936af112c910475e27bf767f79f4528c16f9af1ec0e252"}, +] + +[package.dependencies] +PyMeta3 = ">=0.5.1" + +[[package]] +name = "pycln" +version = "2.4.0" +description = "A formatter for finding and removing unused import statements." +optional = false +python-versions = ">=3.7.0,<4" +files = [ + {file = "pycln-2.4.0-py3-none-any.whl", hash = "sha256:d1bf648df17077306100815d255d45430035b36f66bac635df04a323c61ba126"}, + {file = "pycln-2.4.0.tar.gz", hash = "sha256:1f3eefb7be18a9ee06c3bdd0ba2e91218cd39317e20130325f107e96eb84b9f6"}, +] + +[package.dependencies] +libcst = ">=0.3.10" +pathspec = ">=0.9.0" +pyyaml = ">=5.3.1" +tomlkit = ">=0.11.1" +typer = ">=0.4.1" + [[package]] name = "pycryptodome" version = "3.20.0" @@ -1391,6 +2282,128 @@ files = [ {file = "pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7"}, ] +[[package]] +name = "pydantic" +version = "2.7.0" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic-2.7.0-py3-none-any.whl", hash = "sha256:9dee74a271705f14f9a1567671d144a851c675b072736f0a7b2608fd9e495352"}, + {file = "pydantic-2.7.0.tar.gz", hash = "sha256:b5ecdd42262ca2462e2624793551e80911a1e989f462910bb81aef974b4bb383"}, +] + +[package.dependencies] +annotated-types = ">=0.4.0" +email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"email\""} +pydantic-core = "2.18.1" +typing-extensions = ">=4.6.1" + +[package.extras] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.18.1" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ee9cf33e7fe14243f5ca6977658eb7d1042caaa66847daacbd2117adb258b226"}, + {file = "pydantic_core-2.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b7bbb97d82659ac8b37450c60ff2e9f97e4eb0f8a8a3645a5568b9334b08b50"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df4249b579e75094f7e9bb4bd28231acf55e308bf686b952f43100a5a0be394c"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d0491006a6ad20507aec2be72e7831a42efc93193d2402018007ff827dc62926"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ae80f72bb7a3e397ab37b53a2b49c62cc5496412e71bc4f1277620a7ce3f52b"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58aca931bef83217fca7a390e0486ae327c4af9c3e941adb75f8772f8eeb03a1"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be91ad664fc9245404a789d60cba1e91c26b1454ba136d2a1bf0c2ac0c0505a"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:667880321e916a8920ef49f5d50e7983792cf59f3b6079f3c9dac2b88a311d17"}, + {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f7054fdc556f5421f01e39cbb767d5ec5c1139ea98c3e5b350e02e62201740c7"}, + {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:030e4f9516f9947f38179249778709a460a3adb516bf39b5eb9066fcfe43d0e6"}, + {file = "pydantic_core-2.18.1-cp310-none-win32.whl", hash = "sha256:2e91711e36e229978d92642bfc3546333a9127ecebb3f2761372e096395fc649"}, + {file = "pydantic_core-2.18.1-cp310-none-win_amd64.whl", hash = "sha256:9a29726f91c6cb390b3c2338f0df5cd3e216ad7a938762d11c994bb37552edb0"}, + {file = "pydantic_core-2.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9ece8a49696669d483d206b4474c367852c44815fca23ac4e48b72b339807f80"}, + {file = "pydantic_core-2.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a5d83efc109ceddb99abd2c1316298ced2adb4570410defe766851a804fcd5b"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7973c381283783cd1043a8c8f61ea5ce7a3a58b0369f0ee0ee975eaf2f2a1b"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54c7375c62190a7845091f521add19b0f026bcf6ae674bdb89f296972272e86d"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd63cec4e26e790b70544ae5cc48d11b515b09e05fdd5eff12e3195f54b8a586"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:561cf62c8a3498406495cfc49eee086ed2bb186d08bcc65812b75fda42c38294"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68717c38a68e37af87c4da20e08f3e27d7e4212e99e96c3d875fbf3f4812abfc"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d5728e93d28a3c63ee513d9ffbac9c5989de8c76e049dbcb5bfe4b923a9739d"}, + {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f0f17814c505f07806e22b28856c59ac80cee7dd0fbb152aed273e116378f519"}, + {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d816f44a51ba5175394bc6c7879ca0bd2be560b2c9e9f3411ef3a4cbe644c2e9"}, + {file = "pydantic_core-2.18.1-cp311-none-win32.whl", hash = "sha256:09f03dfc0ef8c22622eaa8608caa4a1e189cfb83ce847045eca34f690895eccb"}, + {file = "pydantic_core-2.18.1-cp311-none-win_amd64.whl", hash = "sha256:27f1009dc292f3b7ca77feb3571c537276b9aad5dd4efb471ac88a8bd09024e9"}, + {file = "pydantic_core-2.18.1-cp311-none-win_arm64.whl", hash = "sha256:48dd883db92e92519201f2b01cafa881e5f7125666141a49ffba8b9facc072b0"}, + {file = "pydantic_core-2.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b6b0e4912030c6f28bcb72b9ebe4989d6dc2eebcd2a9cdc35fefc38052dd4fe8"}, + {file = "pydantic_core-2.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3202a429fe825b699c57892d4371c74cc3456d8d71b7f35d6028c96dfecad31"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3982b0a32d0a88b3907e4b0dc36809fda477f0757c59a505d4e9b455f384b8b"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25595ac311f20e5324d1941909b0d12933f1fd2171075fcff763e90f43e92a0d"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14fe73881cf8e4cbdaded8ca0aa671635b597e42447fec7060d0868b52d074e6"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca976884ce34070799e4dfc6fbd68cb1d181db1eefe4a3a94798ddfb34b8867f"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684d840d2c9ec5de9cb397fcb3f36d5ebb6fa0d94734f9886032dd796c1ead06"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:54764c083bbe0264f0f746cefcded6cb08fbbaaf1ad1d78fb8a4c30cff999a90"}, + {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:201713f2f462e5c015b343e86e68bd8a530a4f76609b33d8f0ec65d2b921712a"}, + {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fd1a9edb9dd9d79fbeac1ea1f9a8dd527a6113b18d2e9bcc0d541d308dae639b"}, + {file = "pydantic_core-2.18.1-cp312-none-win32.whl", hash = "sha256:d5e6b7155b8197b329dc787356cfd2684c9d6a6b1a197f6bbf45f5555a98d411"}, + {file = "pydantic_core-2.18.1-cp312-none-win_amd64.whl", hash = "sha256:9376d83d686ec62e8b19c0ac3bf8d28d8a5981d0df290196fb6ef24d8a26f0d6"}, + {file = "pydantic_core-2.18.1-cp312-none-win_arm64.whl", hash = "sha256:c562b49c96906b4029b5685075fe1ebd3b5cc2601dfa0b9e16c2c09d6cbce048"}, + {file = "pydantic_core-2.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:3e352f0191d99fe617371096845070dee295444979efb8f27ad941227de6ad09"}, + {file = "pydantic_core-2.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0295d52b012cbe0d3059b1dba99159c3be55e632aae1999ab74ae2bd86a33d7"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56823a92075780582d1ffd4489a2e61d56fd3ebb4b40b713d63f96dd92d28144"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd3f79e17b56741b5177bcc36307750d50ea0698df6aa82f69c7db32d968c1c2"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38a5024de321d672a132b1834a66eeb7931959c59964b777e8f32dbe9523f6b1"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ce426ee691319d4767748c8e0895cfc56593d725594e415f274059bcf3cb76"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2adaeea59849ec0939af5c5d476935f2bab4b7f0335b0110f0f069a41024278e"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9b6431559676a1079eac0f52d6d0721fb8e3c5ba43c37bc537c8c83724031feb"}, + {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:85233abb44bc18d16e72dc05bf13848a36f363f83757541f1a97db2f8d58cfd9"}, + {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:641a018af4fe48be57a2b3d7a1f0f5dbca07c1d00951d3d7463f0ac9dac66622"}, + {file = "pydantic_core-2.18.1-cp38-none-win32.whl", hash = "sha256:63d7523cd95d2fde0d28dc42968ac731b5bb1e516cc56b93a50ab293f4daeaad"}, + {file = "pydantic_core-2.18.1-cp38-none-win_amd64.whl", hash = "sha256:907a4d7720abfcb1c81619863efd47c8a85d26a257a2dbebdb87c3b847df0278"}, + {file = "pydantic_core-2.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:aad17e462f42ddbef5984d70c40bfc4146c322a2da79715932cd8976317054de"}, + {file = "pydantic_core-2.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:94b9769ba435b598b547c762184bcfc4783d0d4c7771b04a3b45775c3589ca44"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80e0e57cc704a52fb1b48f16d5b2c8818da087dbee6f98d9bf19546930dc64b5"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76b86e24039c35280ceee6dce7e62945eb93a5175d43689ba98360ab31eebc4a"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a05db5013ec0ca4a32cc6433f53faa2a014ec364031408540ba858c2172bb0"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:250ae39445cb5475e483a36b1061af1bc233de3e9ad0f4f76a71b66231b07f88"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a32204489259786a923e02990249c65b0f17235073149d0033efcebe80095570"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6395a4435fa26519fd96fdccb77e9d00ddae9dd6c742309bd0b5610609ad7fb2"}, + {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2533ad2883f001efa72f3d0e733fb846710c3af6dcdd544fe5bf14fa5fe2d7db"}, + {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b560b72ed4816aee52783c66854d96157fd8175631f01ef58e894cc57c84f0f6"}, + {file = "pydantic_core-2.18.1-cp39-none-win32.whl", hash = "sha256:582cf2cead97c9e382a7f4d3b744cf0ef1a6e815e44d3aa81af3ad98762f5a9b"}, + {file = "pydantic_core-2.18.1-cp39-none-win_amd64.whl", hash = "sha256:ca71d501629d1fa50ea7fa3b08ba884fe10cefc559f5c6c8dfe9036c16e8ae89"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e178e5b66a06ec5bf51668ec0d4ac8cfb2bdcb553b2c207d58148340efd00143"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:72722ce529a76a4637a60be18bd789d8fb871e84472490ed7ddff62d5fed620d"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fe0c1ce5b129455e43f941f7a46f61f3d3861e571f2905d55cdbb8b5c6f5e2c"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4284c621f06a72ce2cb55f74ea3150113d926a6eb78ab38340c08f770eb9b4d"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a0c3e718f4e064efde68092d9d974e39572c14e56726ecfaeebbe6544521f47"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2027493cc44c23b598cfaf200936110433d9caa84e2c6cf487a83999638a96ac"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:76909849d1a6bffa5a07742294f3fa1d357dc917cb1fe7b470afbc3a7579d539"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ee7ccc7fb7e921d767f853b47814c3048c7de536663e82fbc37f5eb0d532224b"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ee2794111c188548a4547eccc73a6a8527fe2af6cf25e1a4ebda2fd01cdd2e60"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a139fe9f298dc097349fb4f28c8b81cc7a202dbfba66af0e14be5cfca4ef7ce5"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d074b07a10c391fc5bbdcb37b2f16f20fcd9e51e10d01652ab298c0d07908ee2"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c69567ddbac186e8c0aadc1f324a60a564cfe25e43ef2ce81bcc4b8c3abffbae"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:baf1c7b78cddb5af00971ad5294a4583188bda1495b13760d9f03c9483bb6203"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2684a94fdfd1b146ff10689c6e4e815f6a01141781c493b97342cdc5b06f4d5d"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:73c1bc8a86a5c9e8721a088df234265317692d0b5cd9e86e975ce3bc3db62a59"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e60defc3c15defb70bb38dd605ff7e0fae5f6c9c7cbfe0ad7868582cb7e844a6"}, + {file = "pydantic_core-2.18.1.tar.gz", hash = "sha256:de9d3e8717560eb05e28739d1b35e4eac2e458553a52a301e51352a7ffc86a35"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pyflakes" +version = "3.2.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, + {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, +] + [[package]] name = "pygments" version = "2.17.2" @@ -1406,15 +2419,25 @@ files = [ plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] +[[package]] +name = "pymeta3" +version = "0.5.1" +description = "Pattern-matching language based on OMeta for Python 3 and 2" +optional = false +python-versions = "*" +files = [ + {file = "PyMeta3-0.5.1.tar.gz", hash = "sha256:18bda326d9a9bbf587bfc0ee0bc96864964d78b067288bcf55d4d98681d05bcb"}, +] + [[package]] name = "pyright" -version = "1.1.351" +version = "1.1.358" description = "Command line wrapper for pyright" optional = false python-versions = ">=3.7" files = [ - {file = "pyright-1.1.351-py3-none-any.whl", hash = "sha256:83b44b25396ae20661fc5f133c3fce30928ff1296d4f2e5ff0bca5fcf03eb89d"}, - {file = "pyright-1.1.351.tar.gz", hash = "sha256:01124099714eebd7f6525d8cbfa350626b56dfaf771cfcd55c03e69f0f1efbbd"}, + {file = "pyright-1.1.358-py3-none-any.whl", hash = "sha256:0995b6a95eb11bd26f093cd5dee3d5e7258441b1b94d4a171b5dc5b79a1d4f4e"}, + {file = "pyright-1.1.358.tar.gz", hash = "sha256:185524a8d52f6f14bbd3b290b92ad905f25b964dddc9e7148aad760bd35c9f60"}, ] [package.dependencies] @@ -1426,23 +2449,96 @@ dev = ["twine (>=3.4.1)"] [[package]] name = "pytest" -version = "7.4.4" +version = "8.1.1" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, - {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, + {file = "pytest-8.1.1-py3-none-any.whl", hash = "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7"}, + {file = "pytest-8.1.1.tar.gz", hash = "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044"}, ] [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<2.0" +pluggy = ">=1.4,<2.0" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.23.6" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-asyncio-0.23.6.tar.gz", hash = "sha256:ffe523a89c1c222598c76856e76852b787504ddb72dd5d9b6617ffa8aa2cde5f"}, + {file = "pytest_asyncio-0.23.6-py3-none-any.whl", hash = "sha256:68516fdd1018ac57b846c9846b954f0393b26f094764a28c955eabb0536a4e8a"}, +] + +[package.dependencies] +pytest = ">=7.0.0,<9" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] + +[[package]] +name = "pytest-cov" +version = "5.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pytest-httpx" +version = "0.30.0" +description = "Send responses to httpx." +optional = false +python-versions = ">=3.9" +files = [ + {file = "pytest-httpx-0.30.0.tar.gz", hash = "sha256:755b8edca87c974dd4f3605c374fda11db84631de3d163b99c0df5807023a19a"}, + {file = "pytest_httpx-0.30.0-py3-none-any.whl", hash = "sha256:6d47849691faf11d2532565d0c8e0e02b9f4ee730da31687feae315581d7520c"}, +] + +[package.dependencies] +httpx = "==0.27.*" +pytest = ">=7,<9" + +[package.extras] +testing = ["pytest-asyncio (==0.23.*)", "pytest-cov (==4.*)"] + +[[package]] +name = "pytest-mock" +version = "3.14.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, + {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, +] + +[package.dependencies] +pytest = ">=6.2.5" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] [[package]] name = "pyunormalize" @@ -1477,15 +2573,64 @@ files = [ {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, ] +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + [[package]] name = "referencing" -version = "0.33.0" +version = "0.34.0" description = "JSON Referencing + Python" optional = false python-versions = ">=3.8" files = [ - {file = "referencing-0.33.0-py3-none-any.whl", hash = "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5"}, - {file = "referencing-0.33.0.tar.gz", hash = "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7"}, + {file = "referencing-0.34.0-py3-none-any.whl", hash = "sha256:d53ae300ceddd3169f1ffa9caf2cb7b769e92657e4fafb23d34b93679116dfd4"}, + {file = "referencing-0.34.0.tar.gz", hash = "sha256:5773bd84ef41799a5a8ca72dc34590c041eb01bf9aa02632b4a973fb0181a844"}, ] [package.dependencies] @@ -1494,104 +2639,104 @@ rpds-py = ">=0.7.0" [[package]] name = "regex" -version = "2023.12.25" +version = "2024.4.16" description = "Alternative regular expression module, to replace re." optional = false python-versions = ">=3.7" files = [ - {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0694219a1d54336fd0445ea382d49d36882415c0134ee1e8332afd1529f0baa5"}, - {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b014333bd0217ad3d54c143de9d4b9a3ca1c5a29a6d0d554952ea071cff0f1f8"}, - {file = "regex-2023.12.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d865984b3f71f6d0af64d0d88f5733521698f6c16f445bb09ce746c92c97c586"}, - {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e0eabac536b4cc7f57a5f3d095bfa557860ab912f25965e08fe1545e2ed8b4c"}, - {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c25a8ad70e716f96e13a637802813f65d8a6760ef48672aa3502f4c24ea8b400"}, - {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9b6d73353f777630626f403b0652055ebfe8ff142a44ec2cf18ae470395766e"}, - {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9cc99d6946d750eb75827cb53c4371b8b0fe89c733a94b1573c9dd16ea6c9e4"}, - {file = "regex-2023.12.25-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88d1f7bef20c721359d8675f7d9f8e414ec5003d8f642fdfd8087777ff7f94b5"}, - {file = "regex-2023.12.25-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cb3fe77aec8f1995611f966d0c656fdce398317f850d0e6e7aebdfe61f40e1cd"}, - {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7aa47c2e9ea33a4a2a05f40fcd3ea36d73853a2aae7b4feab6fc85f8bf2c9704"}, - {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:df26481f0c7a3f8739fecb3e81bc9da3fcfae34d6c094563b9d4670b047312e1"}, - {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c40281f7d70baf6e0db0c2f7472b31609f5bc2748fe7275ea65a0b4601d9b392"}, - {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:d94a1db462d5690ebf6ae86d11c5e420042b9898af5dcf278bd97d6bda065423"}, - {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ba1b30765a55acf15dce3f364e4928b80858fa8f979ad41f862358939bdd1f2f"}, - {file = "regex-2023.12.25-cp310-cp310-win32.whl", hash = "sha256:150c39f5b964e4d7dba46a7962a088fbc91f06e606f023ce57bb347a3b2d4630"}, - {file = "regex-2023.12.25-cp310-cp310-win_amd64.whl", hash = "sha256:09da66917262d9481c719599116c7dc0c321ffcec4b1f510c4f8a066f8768105"}, - {file = "regex-2023.12.25-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1b9d811f72210fa9306aeb88385b8f8bcef0dfbf3873410413c00aa94c56c2b6"}, - {file = "regex-2023.12.25-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d902a43085a308cef32c0d3aea962524b725403fd9373dea18110904003bac97"}, - {file = "regex-2023.12.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d166eafc19f4718df38887b2bbe1467a4f74a9830e8605089ea7a30dd4da8887"}, - {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7ad32824b7f02bb3c9f80306d405a1d9b7bb89362d68b3c5a9be53836caebdb"}, - {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:636ba0a77de609d6510235b7f0e77ec494d2657108f777e8765efc060094c98c"}, - {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fda75704357805eb953a3ee15a2b240694a9a514548cd49b3c5124b4e2ad01b"}, - {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f72cbae7f6b01591f90814250e636065850c5926751af02bb48da94dfced7baa"}, - {file = "regex-2023.12.25-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db2a0b1857f18b11e3b0e54ddfefc96af46b0896fb678c85f63fb8c37518b3e7"}, - {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7502534e55c7c36c0978c91ba6f61703faf7ce733715ca48f499d3dbbd7657e0"}, - {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e8c7e08bb566de4faaf11984af13f6bcf6a08f327b13631d41d62592681d24fe"}, - {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:283fc8eed679758de38fe493b7d7d84a198b558942b03f017b1f94dda8efae80"}, - {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f44dd4d68697559d007462b0a3a1d9acd61d97072b71f6d1968daef26bc744bd"}, - {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:67d3ccfc590e5e7197750fcb3a2915b416a53e2de847a728cfa60141054123d4"}, - {file = "regex-2023.12.25-cp311-cp311-win32.whl", hash = "sha256:68191f80a9bad283432385961d9efe09d783bcd36ed35a60fb1ff3f1ec2efe87"}, - {file = "regex-2023.12.25-cp311-cp311-win_amd64.whl", hash = "sha256:7d2af3f6b8419661a0c421584cfe8aaec1c0e435ce7e47ee2a97e344b98f794f"}, - {file = "regex-2023.12.25-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8a0ccf52bb37d1a700375a6b395bff5dd15c50acb745f7db30415bae3c2b0715"}, - {file = "regex-2023.12.25-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c3c4a78615b7762740531c27cf46e2f388d8d727d0c0c739e72048beb26c8a9d"}, - {file = "regex-2023.12.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ad83e7545b4ab69216cef4cc47e344d19622e28aabec61574b20257c65466d6a"}, - {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7a635871143661feccce3979e1727c4e094f2bdfd3ec4b90dfd4f16f571a87a"}, - {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d498eea3f581fbe1b34b59c697512a8baef88212f92e4c7830fcc1499f5b45a5"}, - {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:43f7cd5754d02a56ae4ebb91b33461dc67be8e3e0153f593c509e21d219c5060"}, - {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51f4b32f793812714fd5307222a7f77e739b9bc566dc94a18126aba3b92b98a3"}, - {file = "regex-2023.12.25-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba99d8077424501b9616b43a2d208095746fb1284fc5ba490139651f971d39d9"}, - {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4bfc2b16e3ba8850e0e262467275dd4d62f0d045e0e9eda2bc65078c0110a11f"}, - {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8c2c19dae8a3eb0ea45a8448356ed561be843b13cbc34b840922ddf565498c1c"}, - {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:60080bb3d8617d96f0fb7e19796384cc2467447ef1c491694850ebd3670bc457"}, - {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b77e27b79448e34c2c51c09836033056a0547aa360c45eeeb67803da7b0eedaf"}, - {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:518440c991f514331f4850a63560321f833979d145d7d81186dbe2f19e27ae3d"}, - {file = "regex-2023.12.25-cp312-cp312-win32.whl", hash = "sha256:e2610e9406d3b0073636a3a2e80db05a02f0c3169b5632022b4e81c0364bcda5"}, - {file = "regex-2023.12.25-cp312-cp312-win_amd64.whl", hash = "sha256:cc37b9aeebab425f11f27e5e9e6cf580be7206c6582a64467a14dda211abc232"}, - {file = "regex-2023.12.25-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:da695d75ac97cb1cd725adac136d25ca687da4536154cdc2815f576e4da11c69"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d126361607b33c4eb7b36debc173bf25d7805847346dd4d99b5499e1fef52bc7"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4719bb05094d7d8563a450cf8738d2e1061420f79cfcc1fa7f0a44744c4d8f73"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5dd58946bce44b53b06d94aa95560d0b243eb2fe64227cba50017a8d8b3cd3e2"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22a86d9fff2009302c440b9d799ef2fe322416d2d58fc124b926aa89365ec482"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2aae8101919e8aa05ecfe6322b278f41ce2994c4a430303c4cd163fef746e04f"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e692296c4cc2873967771345a876bcfc1c547e8dd695c6b89342488b0ea55cd8"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:263ef5cc10979837f243950637fffb06e8daed7f1ac1e39d5910fd29929e489a"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d6f7e255e5fa94642a0724e35406e6cb7001c09d476ab5fce002f652b36d0c39"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:88ad44e220e22b63b0f8f81f007e8abbb92874d8ced66f32571ef8beb0643b2b"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:3a17d3ede18f9cedcbe23d2daa8a2cd6f59fe2bf082c567e43083bba3fb00347"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d15b274f9e15b1a0b7a45d2ac86d1f634d983ca40d6b886721626c47a400bf39"}, - {file = "regex-2023.12.25-cp37-cp37m-win32.whl", hash = "sha256:ed19b3a05ae0c97dd8f75a5d8f21f7723a8c33bbc555da6bbe1f96c470139d3c"}, - {file = "regex-2023.12.25-cp37-cp37m-win_amd64.whl", hash = "sha256:a6d1047952c0b8104a1d371f88f4ab62e6275567d4458c1e26e9627ad489b445"}, - {file = "regex-2023.12.25-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b43523d7bc2abd757119dbfb38af91b5735eea45537ec6ec3a5ec3f9562a1c53"}, - {file = "regex-2023.12.25-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:efb2d82f33b2212898f1659fb1c2e9ac30493ac41e4d53123da374c3b5541e64"}, - {file = "regex-2023.12.25-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7fca9205b59c1a3d5031f7e64ed627a1074730a51c2a80e97653e3e9fa0d415"}, - {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086dd15e9435b393ae06f96ab69ab2d333f5d65cbe65ca5a3ef0ec9564dfe770"}, - {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e81469f7d01efed9b53740aedd26085f20d49da65f9c1f41e822a33992cb1590"}, - {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34e4af5b27232f68042aa40a91c3b9bb4da0eeb31b7632e0091afc4310afe6cb"}, - {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9852b76ab558e45b20bf1893b59af64a28bd3820b0c2efc80e0a70a4a3ea51c1"}, - {file = "regex-2023.12.25-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff100b203092af77d1a5a7abe085b3506b7eaaf9abf65b73b7d6905b6cb76988"}, - {file = "regex-2023.12.25-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cc038b2d8b1470364b1888a98fd22d616fba2b6309c5b5f181ad4483e0017861"}, - {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:094ba386bb5c01e54e14434d4caabf6583334090865b23ef58e0424a6286d3dc"}, - {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5cd05d0f57846d8ba4b71d9c00f6f37d6b97d5e5ef8b3c3840426a475c8f70f4"}, - {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:9aa1a67bbf0f957bbe096375887b2505f5d8ae16bf04488e8b0f334c36e31360"}, - {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:98a2636994f943b871786c9e82bfe7883ecdaba2ef5df54e1450fa9869d1f756"}, - {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:37f8e93a81fc5e5bd8db7e10e62dc64261bcd88f8d7e6640aaebe9bc180d9ce2"}, - {file = "regex-2023.12.25-cp38-cp38-win32.whl", hash = "sha256:d78bd484930c1da2b9679290a41cdb25cc127d783768a0369d6b449e72f88beb"}, - {file = "regex-2023.12.25-cp38-cp38-win_amd64.whl", hash = "sha256:b521dcecebc5b978b447f0f69b5b7f3840eac454862270406a39837ffae4e697"}, - {file = "regex-2023.12.25-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f7bc09bc9c29ebead055bcba136a67378f03d66bf359e87d0f7c759d6d4ffa31"}, - {file = "regex-2023.12.25-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e14b73607d6231f3cc4622809c196b540a6a44e903bcfad940779c80dffa7be7"}, - {file = "regex-2023.12.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9eda5f7a50141291beda3edd00abc2d4a5b16c29c92daf8d5bd76934150f3edc"}, - {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc6bb9aa69aacf0f6032c307da718f61a40cf970849e471254e0e91c56ffca95"}, - {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:298dc6354d414bc921581be85695d18912bea163a8b23cac9a2562bbcd5088b1"}, - {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f4e475a80ecbd15896a976aa0b386c5525d0ed34d5c600b6d3ebac0a67c7ddf"}, - {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531ac6cf22b53e0696f8e1d56ce2396311254eb806111ddd3922c9d937151dae"}, - {file = "regex-2023.12.25-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22f3470f7524b6da61e2020672df2f3063676aff444db1daa283c2ea4ed259d6"}, - {file = "regex-2023.12.25-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:89723d2112697feaa320c9d351e5f5e7b841e83f8b143dba8e2d2b5f04e10923"}, - {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0ecf44ddf9171cd7566ef1768047f6e66975788258b1c6c6ca78098b95cf9a3d"}, - {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:905466ad1702ed4acfd67a902af50b8db1feeb9781436372261808df7a2a7bca"}, - {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:4558410b7a5607a645e9804a3e9dd509af12fb72b9825b13791a37cd417d73a5"}, - {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:7e316026cc1095f2a3e8cc012822c99f413b702eaa2ca5408a513609488cb62f"}, - {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3b1de218d5375cd6ac4b5493e0b9f3df2be331e86520f23382f216c137913d20"}, - {file = "regex-2023.12.25-cp39-cp39-win32.whl", hash = "sha256:11a963f8e25ab5c61348d090bf1b07f1953929c13bd2309a0662e9ff680763c9"}, - {file = "regex-2023.12.25-cp39-cp39-win_amd64.whl", hash = "sha256:e693e233ac92ba83a87024e1d32b5f9ab15ca55ddd916d878146f4e3406b5c91"}, - {file = "regex-2023.12.25.tar.gz", hash = "sha256:29171aa128da69afdf4bde412d5bedc335f2ca8fcfe4489038577d05f16181e5"}, + {file = "regex-2024.4.16-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb83cc090eac63c006871fd24db5e30a1f282faa46328572661c0a24a2323a08"}, + {file = "regex-2024.4.16-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8c91e1763696c0eb66340c4df98623c2d4e77d0746b8f8f2bee2c6883fd1fe18"}, + {file = "regex-2024.4.16-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:10188fe732dec829c7acca7422cdd1bf57d853c7199d5a9e96bb4d40db239c73"}, + {file = "regex-2024.4.16-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:956b58d692f235cfbf5b4f3abd6d99bf102f161ccfe20d2fd0904f51c72c4c66"}, + {file = "regex-2024.4.16-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a70b51f55fd954d1f194271695821dd62054d949efd6368d8be64edd37f55c86"}, + {file = "regex-2024.4.16-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c02fcd2bf45162280613d2e4a1ca3ac558ff921ae4e308ecb307650d3a6ee51"}, + {file = "regex-2024.4.16-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4ed75ea6892a56896d78f11006161eea52c45a14994794bcfa1654430984b22"}, + {file = "regex-2024.4.16-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd727ad276bb91928879f3aa6396c9a1d34e5e180dce40578421a691eeb77f47"}, + {file = "regex-2024.4.16-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7cbc5d9e8a1781e7be17da67b92580d6ce4dcef5819c1b1b89f49d9678cc278c"}, + {file = "regex-2024.4.16-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:78fddb22b9ef810b63ef341c9fcf6455232d97cfe03938cbc29e2672c436670e"}, + {file = "regex-2024.4.16-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:445ca8d3c5a01309633a0c9db57150312a181146315693273e35d936472df912"}, + {file = "regex-2024.4.16-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:95399831a206211d6bc40224af1c635cb8790ddd5c7493e0bd03b85711076a53"}, + {file = "regex-2024.4.16-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:7731728b6568fc286d86745f27f07266de49603a6fdc4d19c87e8c247be452af"}, + {file = "regex-2024.4.16-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4facc913e10bdba42ec0aee76d029aedda628161a7ce4116b16680a0413f658a"}, + {file = "regex-2024.4.16-cp310-cp310-win32.whl", hash = "sha256:911742856ce98d879acbea33fcc03c1d8dc1106234c5e7d068932c945db209c0"}, + {file = "regex-2024.4.16-cp310-cp310-win_amd64.whl", hash = "sha256:e0a2df336d1135a0b3a67f3bbf78a75f69562c1199ed9935372b82215cddd6e2"}, + {file = "regex-2024.4.16-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1210365faba7c2150451eb78ec5687871c796b0f1fa701bfd2a4a25420482d26"}, + {file = "regex-2024.4.16-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9ab40412f8cd6f615bfedea40c8bf0407d41bf83b96f6fc9ff34976d6b7037fd"}, + {file = "regex-2024.4.16-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fd80d1280d473500d8086d104962a82d77bfbf2b118053824b7be28cd5a79ea5"}, + {file = "regex-2024.4.16-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bb966fdd9217e53abf824f437a5a2d643a38d4fd5fd0ca711b9da683d452969"}, + {file = "regex-2024.4.16-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:20b7a68444f536365af42a75ccecb7ab41a896a04acf58432db9e206f4e525d6"}, + {file = "regex-2024.4.16-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b74586dd0b039c62416034f811d7ee62810174bb70dffcca6439f5236249eb09"}, + {file = "regex-2024.4.16-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c8290b44d8b0af4e77048646c10c6e3aa583c1ca67f3b5ffb6e06cf0c6f0f89"}, + {file = "regex-2024.4.16-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2d80a6749724b37853ece57988b39c4e79d2b5fe2869a86e8aeae3bbeef9eb0"}, + {file = "regex-2024.4.16-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3a1018e97aeb24e4f939afcd88211ace472ba566efc5bdf53fd8fd7f41fa7170"}, + {file = "regex-2024.4.16-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8d015604ee6204e76569d2f44e5a210728fa917115bef0d102f4107e622b08d5"}, + {file = "regex-2024.4.16-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:3d5ac5234fb5053850d79dd8eb1015cb0d7d9ed951fa37aa9e6249a19aa4f336"}, + {file = "regex-2024.4.16-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:0a38d151e2cdd66d16dab550c22f9521ba79761423b87c01dae0a6e9add79c0d"}, + {file = "regex-2024.4.16-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:159dc4e59a159cb8e4e8f8961eb1fa5d58f93cb1acd1701d8aff38d45e1a84a6"}, + {file = "regex-2024.4.16-cp311-cp311-win32.whl", hash = "sha256:ba2336d6548dee3117520545cfe44dc28a250aa091f8281d28804aa8d707d93d"}, + {file = "regex-2024.4.16-cp311-cp311-win_amd64.whl", hash = "sha256:8f83b6fd3dc3ba94d2b22717f9c8b8512354fd95221ac661784df2769ea9bba9"}, + {file = "regex-2024.4.16-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:80b696e8972b81edf0af2a259e1b2a4a661f818fae22e5fa4fa1a995fb4a40fd"}, + {file = "regex-2024.4.16-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d61ae114d2a2311f61d90c2ef1358518e8f05eafda76eaf9c772a077e0b465ec"}, + {file = "regex-2024.4.16-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8ba6745440b9a27336443b0c285d705ce73adb9ec90e2f2004c64d95ab5a7598"}, + {file = "regex-2024.4.16-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295004b2dd37b0835ea5c14a33e00e8cfa3c4add4d587b77287825f3418d310"}, + {file = "regex-2024.4.16-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4aba818dcc7263852aabb172ec27b71d2abca02a593b95fa79351b2774eb1d2b"}, + {file = "regex-2024.4.16-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0800631e565c47520aaa04ae38b96abc5196fe8b4aa9bd864445bd2b5848a7a"}, + {file = "regex-2024.4.16-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08dea89f859c3df48a440dbdcd7b7155bc675f2fa2ec8c521d02dc69e877db70"}, + {file = "regex-2024.4.16-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eeaa0b5328b785abc344acc6241cffde50dc394a0644a968add75fcefe15b9d4"}, + {file = "regex-2024.4.16-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4e819a806420bc010489f4e741b3036071aba209f2e0989d4750b08b12a9343f"}, + {file = "regex-2024.4.16-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:c2d0e7cbb6341e830adcbfa2479fdeebbfbb328f11edd6b5675674e7a1e37730"}, + {file = "regex-2024.4.16-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:91797b98f5e34b6a49f54be33f72e2fb658018ae532be2f79f7c63b4ae225145"}, + {file = "regex-2024.4.16-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:d2da13568eff02b30fd54fccd1e042a70fe920d816616fda4bf54ec705668d81"}, + {file = "regex-2024.4.16-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:370c68dc5570b394cbaadff50e64d705f64debed30573e5c313c360689b6aadc"}, + {file = "regex-2024.4.16-cp312-cp312-win32.whl", hash = "sha256:904c883cf10a975b02ab3478bce652f0f5346a2c28d0a8521d97bb23c323cc8b"}, + {file = "regex-2024.4.16-cp312-cp312-win_amd64.whl", hash = "sha256:785c071c982dce54d44ea0b79cd6dfafddeccdd98cfa5f7b86ef69b381b457d9"}, + {file = "regex-2024.4.16-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e2f142b45c6fed48166faeb4303b4b58c9fcd827da63f4cf0a123c3480ae11fb"}, + {file = "regex-2024.4.16-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e87ab229332ceb127a165612d839ab87795972102cb9830e5f12b8c9a5c1b508"}, + {file = "regex-2024.4.16-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:81500ed5af2090b4a9157a59dbc89873a25c33db1bb9a8cf123837dcc9765047"}, + {file = "regex-2024.4.16-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b340cccad138ecb363324aa26893963dcabb02bb25e440ebdf42e30963f1a4e0"}, + {file = "regex-2024.4.16-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c72608e70f053643437bd2be0608f7f1c46d4022e4104d76826f0839199347a"}, + {file = "regex-2024.4.16-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a01fe2305e6232ef3e8f40bfc0f0f3a04def9aab514910fa4203bafbc0bb4682"}, + {file = "regex-2024.4.16-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:03576e3a423d19dda13e55598f0fd507b5d660d42c51b02df4e0d97824fdcae3"}, + {file = "regex-2024.4.16-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:549c3584993772e25f02d0656ac48abdda73169fe347263948cf2b1cead622f3"}, + {file = "regex-2024.4.16-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:34422d5a69a60b7e9a07a690094e824b66f5ddc662a5fc600d65b7c174a05f04"}, + {file = "regex-2024.4.16-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:5f580c651a72b75c39e311343fe6875d6f58cf51c471a97f15a938d9fe4e0d37"}, + {file = "regex-2024.4.16-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:3399dd8a7495bbb2bacd59b84840eef9057826c664472e86c91d675d007137f5"}, + {file = "regex-2024.4.16-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8d1f86f3f4e2388aa3310b50694ac44daefbd1681def26b4519bd050a398dc5a"}, + {file = "regex-2024.4.16-cp37-cp37m-win32.whl", hash = "sha256:dd5acc0a7d38fdc7a3a6fd3ad14c880819008ecb3379626e56b163165162cc46"}, + {file = "regex-2024.4.16-cp37-cp37m-win_amd64.whl", hash = "sha256:ba8122e3bb94ecda29a8de4cf889f600171424ea586847aa92c334772d200331"}, + {file = "regex-2024.4.16-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:743deffdf3b3481da32e8a96887e2aa945ec6685af1cfe2bcc292638c9ba2f48"}, + {file = "regex-2024.4.16-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7571f19f4a3fd00af9341c7801d1ad1967fc9c3f5e62402683047e7166b9f2b4"}, + {file = "regex-2024.4.16-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:df79012ebf6f4efb8d307b1328226aef24ca446b3ff8d0e30202d7ebcb977a8c"}, + {file = "regex-2024.4.16-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e757d475953269fbf4b441207bb7dbdd1c43180711b6208e129b637792ac0b93"}, + {file = "regex-2024.4.16-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4313ab9bf6a81206c8ac28fdfcddc0435299dc88cad12cc6305fd0e78b81f9e4"}, + {file = "regex-2024.4.16-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d83c2bc678453646f1a18f8db1e927a2d3f4935031b9ad8a76e56760461105dd"}, + {file = "regex-2024.4.16-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9df1bfef97db938469ef0a7354b2d591a2d438bc497b2c489471bec0e6baf7c4"}, + {file = "regex-2024.4.16-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62120ed0de69b3649cc68e2965376048793f466c5a6c4370fb27c16c1beac22d"}, + {file = "regex-2024.4.16-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c2ef6f7990b6e8758fe48ad08f7e2f66c8f11dc66e24093304b87cae9037bb4a"}, + {file = "regex-2024.4.16-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8fc6976a3395fe4d1fbeb984adaa8ec652a1e12f36b56ec8c236e5117b585427"}, + {file = "regex-2024.4.16-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:03e68f44340528111067cecf12721c3df4811c67268b897fbe695c95f860ac42"}, + {file = "regex-2024.4.16-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ec7e0043b91115f427998febaa2beb82c82df708168b35ece3accb610b91fac1"}, + {file = "regex-2024.4.16-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:c21fc21a4c7480479d12fd8e679b699f744f76bb05f53a1d14182b31f55aac76"}, + {file = "regex-2024.4.16-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:12f6a3f2f58bb7344751919a1876ee1b976fe08b9ffccb4bbea66f26af6017b9"}, + {file = "regex-2024.4.16-cp38-cp38-win32.whl", hash = "sha256:479595a4fbe9ed8f8f72c59717e8cf222da2e4c07b6ae5b65411e6302af9708e"}, + {file = "regex-2024.4.16-cp38-cp38-win_amd64.whl", hash = "sha256:0534b034fba6101611968fae8e856c1698da97ce2efb5c2b895fc8b9e23a5834"}, + {file = "regex-2024.4.16-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a7ccdd1c4a3472a7533b0a7aa9ee34c9a2bef859ba86deec07aff2ad7e0c3b94"}, + {file = "regex-2024.4.16-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f2f017c5be19984fbbf55f8af6caba25e62c71293213f044da3ada7091a4455"}, + {file = "regex-2024.4.16-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:803b8905b52de78b173d3c1e83df0efb929621e7b7c5766c0843704d5332682f"}, + {file = "regex-2024.4.16-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:684008ec44ad275832a5a152f6e764bbe1914bea10968017b6feaecdad5736e0"}, + {file = "regex-2024.4.16-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65436dce9fdc0aeeb0a0effe0839cb3d6a05f45aa45a4d9f9c60989beca78b9c"}, + {file = "regex-2024.4.16-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea355eb43b11764cf799dda62c658c4d2fdb16af41f59bb1ccfec517b60bcb07"}, + {file = "regex-2024.4.16-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c1165f3809ce7774f05cb74e5408cd3aa93ee8573ae959a97a53db3ca3180d"}, + {file = "regex-2024.4.16-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cccc79a9be9b64c881f18305a7c715ba199e471a3973faeb7ba84172abb3f317"}, + {file = "regex-2024.4.16-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00169caa125f35d1bca6045d65a662af0202704489fada95346cfa092ec23f39"}, + {file = "regex-2024.4.16-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6cc38067209354e16c5609b66285af17a2863a47585bcf75285cab33d4c3b8df"}, + {file = "regex-2024.4.16-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:23cff1b267038501b179ccbbd74a821ac4a7192a1852d1d558e562b507d46013"}, + {file = "regex-2024.4.16-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:b9d320b3bf82a39f248769fc7f188e00f93526cc0fe739cfa197868633d44701"}, + {file = "regex-2024.4.16-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:89ec7f2c08937421bbbb8b48c54096fa4f88347946d4747021ad85f1b3021b3c"}, + {file = "regex-2024.4.16-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4918fd5f8b43aa7ec031e0fef1ee02deb80b6afd49c85f0790be1dc4ce34cb50"}, + {file = "regex-2024.4.16-cp39-cp39-win32.whl", hash = "sha256:684e52023aec43bdf0250e843e1fdd6febbe831bd9d52da72333fa201aaa2335"}, + {file = "regex-2024.4.16-cp39-cp39-win_amd64.whl", hash = "sha256:e697e1c0238133589e00c244a8b676bc2cfc3ab4961318d902040d099fec7483"}, + {file = "regex-2024.4.16.tar.gz", hash = "sha256:fa454d26f2e87ad661c4f0c5a5fe4cf6aab1e307d1b94f16ffdfcb089ba685c0"}, ] [[package]] @@ -1615,6 +2760,24 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "rich" +version = "13.7.1" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, + {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + [[package]] name = "rlp" version = "4.0.0" @@ -1745,45 +2908,81 @@ files = [ [[package]] name = "ruff" -version = "0.2.2" +version = "0.3.7" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0a9efb032855ffb3c21f6405751d5e147b0c6b631e3ca3f6b20f917572b97eb6"}, - {file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d450b7fbff85913f866a5384d8912710936e2b96da74541c82c1b458472ddb39"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecd46e3106850a5c26aee114e562c329f9a1fbe9e4821b008c4404f64ff9ce73"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e22676a5b875bd72acd3d11d5fa9075d3a5f53b877fe7b4793e4673499318ba"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1695700d1e25a99d28f7a1636d85bafcc5030bba9d0578c0781ba1790dbcf51c"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b0c232af3d0bd8f521806223723456ffebf8e323bd1e4e82b0befb20ba18388e"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f63d96494eeec2fc70d909393bcd76c69f35334cdbd9e20d089fb3f0640216ca"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a61ea0ff048e06de273b2e45bd72629f470f5da8f71daf09fe481278b175001"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1439c8f407e4f356470e54cdecdca1bd5439a0673792dbe34a2b0a551a2fe3"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:940de32dc8853eba0f67f7198b3e79bc6ba95c2edbfdfac2144c8235114d6726"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c126da55c38dd917621552ab430213bdb3273bb10ddb67bc4b761989210eb6e"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3b65494f7e4bed2e74110dac1f0d17dc8e1f42faaa784e7c58a98e335ec83d7e"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1ec49be4fe6ddac0503833f3ed8930528e26d1e60ad35c2446da372d16651ce9"}, - {file = "ruff-0.2.2-py3-none-win32.whl", hash = "sha256:d920499b576f6c68295bc04e7b17b6544d9d05f196bb3aac4358792ef6f34325"}, - {file = "ruff-0.2.2-py3-none-win_amd64.whl", hash = "sha256:cc9a91ae137d687f43a44c900e5d95e9617cb37d4c989e462980ba27039d239d"}, - {file = "ruff-0.2.2-py3-none-win_arm64.whl", hash = "sha256:c9d15fc41e6054bfc7200478720570078f0b41c9ae4f010bcc16bd6f4d1aacdd"}, - {file = "ruff-0.2.2.tar.gz", hash = "sha256:e62ed7f36b3068a30ba39193a14274cd706bc486fad521276458022f7bccb31d"}, + {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0e8377cccb2f07abd25e84fc5b2cbe48eeb0fea9f1719cad7caedb061d70e5ce"}, + {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:15a4d1cc1e64e556fa0d67bfd388fed416b7f3b26d5d1c3e7d192c897e39ba4b"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d28bdf3d7dc71dd46929fafeec98ba89b7c3550c3f0978e36389b5631b793663"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:379b67d4f49774ba679593b232dcd90d9e10f04d96e3c8ce4a28037ae473f7bb"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c060aea8ad5ef21cdfbbe05475ab5104ce7827b639a78dd55383a6e9895b7c51"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ebf8f615dde968272d70502c083ebf963b6781aacd3079081e03b32adfe4d58a"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d48098bd8f5c38897b03604f5428901b65e3c97d40b3952e38637b5404b739a2"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da8a4fda219bf9024692b1bc68c9cff4b80507879ada8769dc7e985755d662ea"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c44e0149f1d8b48c4d5c33d88c677a4aa22fd09b1683d6a7ff55b816b5d074f"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3050ec0af72b709a62ecc2aca941b9cd479a7bf2b36cc4562f0033d688e44fa1"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a29cc38e4c1ab00da18a3f6777f8b50099d73326981bb7d182e54a9a21bb4ff7"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b15cc59c19edca917f51b1956637db47e200b0fc5e6e1878233d3a938384b0b"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e491045781b1e38b72c91247cf4634f040f8d0cb3e6d3d64d38dcf43616650b4"}, + {file = "ruff-0.3.7-py3-none-win32.whl", hash = "sha256:bc931de87593d64fad3a22e201e55ad76271f1d5bfc44e1a1887edd0903c7d9f"}, + {file = "ruff-0.3.7-py3-none-win_amd64.whl", hash = "sha256:5ef0e501e1e39f35e03c2acb1d1238c595b8bb36cf7a170e7c1df1b73da00e74"}, + {file = "ruff-0.3.7-py3-none-win_arm64.whl", hash = "sha256:789e144f6dc7019d1f92a812891c645274ed08af6037d11fc65fcbc183b7d59f"}, + {file = "ruff-0.3.7.tar.gz", hash = "sha256:d5c1aebee5162c2226784800ae031f660c350e7a3402c4d1f8ea4e97e232e3ba"}, +] + +[[package]] +name = "safe-pysha3" +version = "1.0.4" +description = "SHA-3 (Keccak) for Python 3.9 - 3.11" +optional = false +python-versions = "*" +files = [ + {file = "safe-pysha3-1.0.4.tar.gz", hash = "sha256:e429146b1edd198b2ca934a2046a65656c5d31b0ec894bbd6055127f4deaff17"}, ] +[[package]] +name = "semantic-version" +version = "2.10.0" +description = "A library implementing the 'SemVer' scheme." +optional = false +python-versions = ">=2.7" +files = [ + {file = "semantic_version-2.10.0-py2.py3-none-any.whl", hash = "sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177"}, + {file = "semantic_version-2.10.0.tar.gz", hash = "sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c"}, +] + +[package.extras] +dev = ["Django (>=1.11)", "check-manifest", "colorama (<=0.4.1)", "coverage", "flake8", "nose2", "readme-renderer (<25.0)", "tox", "wheel", "zest.releaser[recommended]"] +doc = ["Sphinx", "sphinx-rtd-theme"] + [[package]] name = "setuptools" -version = "69.1.0" +version = "69.5.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, - {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, + {file = "setuptools-69.5.1-py3-none-any.whl", hash = "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32"}, + {file = "setuptools-69.5.1.tar.gz", hash = "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = false +python-versions = ">=3.7" +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] [[package]] name = "six" @@ -1798,13 +2997,24 @@ files = [ [[package]] name = "sniffio" -version = "1.3.0" +version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" files = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +optional = false +python-versions = "*" +files = [ + {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, + {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] [[package]] @@ -1826,6 +3036,39 @@ pure-eval = "*" [package.extras] tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "tomlkit" +version = "0.12.4" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomlkit-0.12.4-py3-none-any.whl", hash = "sha256:5cd82d48a3dd89dee1f9d64420aa20ae65cfbd00668d6f094d7578a78efbb77b"}, + {file = "tomlkit-0.12.4.tar.gz", hash = "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3"}, +] + [[package]] name = "toolz" version = "0.12.1" @@ -1839,28 +3082,68 @@ files = [ [[package]] name = "traitlets" -version = "5.14.1" +version = "5.14.2" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" files = [ - {file = "traitlets-5.14.1-py3-none-any.whl", hash = "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74"}, - {file = "traitlets-5.14.1.tar.gz", hash = "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e"}, + {file = "traitlets-5.14.2-py3-none-any.whl", hash = "sha256:fcdf85684a772ddeba87db2f398ce00b40ff550d1528c03c14dbf6a02003cd80"}, + {file = "traitlets-5.14.2.tar.gz", hash = "sha256:8cdd83c040dab7d1dee822678e5f5d100b514f7b72b01615b26fc5718916fdf9"}, ] [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.1)", "pytest-mock", "pytest-mypy-testing"] + +[[package]] +name = "trie" +version = "3.0.0" +description = "Python implementation of the Ethereum Trie structure" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "trie-3.0.0-py3-none-any.whl", hash = "sha256:a061507aa3a0076c61a65c0d70de528508a66d948f09054de51f6560fd59c454"}, + {file = "trie-3.0.0.tar.gz", hash = "sha256:180205883dc614cade519b38b3e4ffecb8184e53d594556b38f43446c5cda840"}, +] + +[package.dependencies] +eth-hash = ">=0.1.0" +eth-utils = ">=2.0.0" +hexbytes = ">=0.2.0,<0.4.0" +rlp = ">=3" +sortedcontainers = ">=2.1.0" + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash (>=0.1.0,<1.0.0)", "hypothesis (>=6.56.4,<7)", "ipython", "pre-commit (>=3.4.0)", "pycryptodome", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["towncrier (>=21,<22)"] +test = ["hypothesis (>=6.56.4,<7)", "pycryptodome", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "typer" +version = "0.12.3" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = false +python-versions = ">=3.7" +files = [ + {file = "typer-0.12.3-py3-none-any.whl", hash = "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914"}, + {file = "typer-0.12.3.tar.gz", hash = "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"}, +] + +[package.dependencies] +click = ">=8.0.0" +rich = ">=10.11.0" +shellingham = ">=1.3.0" +typing-extensions = ">=3.7.4.3" [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.11.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, + {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, ] [[package]] @@ -1880,6 +3163,26 @@ h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] +[[package]] +name = "virtualenv" +version = "20.25.1" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.25.1-py3-none-any.whl", hash = "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a"}, + {file = "virtualenv-20.25.1.tar.gz", hash = "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] + [[package]] name = "wcwidth" version = "0.2.13" @@ -1893,26 +3196,28 @@ files = [ [[package]] name = "web3" -version = "6.15.1" +version = "6.17.1" description = "web3.py" optional = false python-versions = ">=3.7.2" files = [ - {file = "web3-6.15.1-py3-none-any.whl", hash = "sha256:4e4a8313aa4556ecde61c852a62405b853b667498b07da6ff05c29fe8c79096b"}, - {file = "web3-6.15.1.tar.gz", hash = "sha256:f9e7eefc1b3c3d194868a4ef9583b625c18ea3f31a48ebe143183db74898f381"}, + {file = "web3-6.17.1-py3-none-any.whl", hash = "sha256:eabc6f0d92a59cc0968e3d98238e40df29c0bedac7760cbd08d9cb0a76741de3"}, + {file = "web3-6.17.1.tar.gz", hash = "sha256:38372fae8adfbf92407ead7396f27e233facb717e6837119a4133f045543d447"}, ] [package.dependencies] aiohttp = ">=3.7.4.post0" eth-abi = ">=4.0.0" -eth-account = ">=0.8.0" +eth-account = ">=0.8.0,<0.13" eth-hash = {version = ">=0.5.1", extras = ["pycryptodome"]} -eth-typing = ">=3.0.0" +eth-tester = {version = ">=0.11.0b1,<0.12.0b1", extras = ["py-evm"], optional = true, markers = "python_version > \"3.7\" and extra == \"tester\""} +eth-typing = ">=3.0.0,<4.2.0" eth-utils = ">=2.1.0" hexbytes = ">=0.1.0,<0.4.0" jsonschema = ">=4.0.0" lru-dict = ">=1.1.6,<1.3.0" protobuf = ">=4.21.6" +py-geth = {version = ">=3.14.0", optional = true, markers = "extra == \"tester\""} pyunormalize = ">=15.0.0" pywin32 = {version = ">=223", markers = "platform_system == \"Windows\""} requests = ">=2.16.0" @@ -1920,11 +3225,10 @@ typing-extensions = ">=4.0.1" websockets = ">=10.0.0" [package.extras] -dev = ["black (>=22.1.0)", "build (>=0.9.0)", "bumpversion", "eth-tester[py-evm] (==v0.9.1-b.2)", "flake8 (==3.8.3)", "flaky (>=3.7.0)", "hypothesis (>=3.31.2)", "importlib-metadata (<5.0)", "ipfshttpclient (==0.8.0a2)", "isort (>=5.11.0)", "mypy (==1.4.1)", "py-geth (>=3.14.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-mock (>=1.10)", "pytest-watch (>=4.2)", "pytest-xdist (>=1.29)", "setuptools (>=38.6.0)", "sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=3.18.0)", "tqdm (>4.32)", "twine (>=1.13)", "types-protobuf (==3.19.13)", "types-requests (>=2.26.1)", "types-setuptools (>=57.4.4)", "when-changed (>=0.3.0)"] +dev = ["build (>=0.9.0)", "bumpversion", "eth-tester[py-evm] (>=0.11.0b1,<0.12.0b1)", "eth-tester[py-evm] (>=0.9.0b1,<0.10.0b1)", "flaky (>=3.7.0)", "hypothesis (>=3.31.2)", "importlib-metadata (<5.0)", "ipfshttpclient (==0.8.0a2)", "pre-commit (>=2.21.0)", "py-geth (>=3.14.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-mock (>=1.10)", "pytest-watch (>=4.2)", "pytest-xdist (>=1.29)", "setuptools (>=38.6.0)", "sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=3.18.0)", "tqdm (>4.32)", "twine (>=1.13)", "when-changed (>=0.3.0)"] docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] ipfs = ["ipfshttpclient (==0.8.0a2)"] -linter = ["black (>=22.1.0)", "flake8 (==3.8.3)", "isort (>=5.11.0)", "mypy (==1.4.1)", "types-protobuf (==3.19.13)", "types-requests (>=2.26.1)", "types-setuptools (>=57.4.4)"] -tester = ["eth-tester[py-evm] (==v0.9.1-b.2)", "py-geth (>=3.14.0)"] +tester = ["eth-tester[py-evm] (>=0.11.0b1,<0.12.0b1)", "eth-tester[py-evm] (>=0.9.0b1,<0.10.0b1)", "py-geth (>=3.14.0)"] [[package]] name = "websockets" @@ -2112,5 +3416,5 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" -python-versions = "^3.12" -content-hash = "76444f424eb0438c8444db6bd51a2fd14acc8e153d71bf86be63e63739667088" +python-versions = ">=3.10,<4.0" +content-hash = "e02971366a8bd5c85b5e2c32578cd193560f4827d381c2e9341953d453120fad" diff --git a/pyproject.toml b/pyproject.toml index 806fffd..012d3ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,17 +6,53 @@ authors = ["José Ribeiro "] readme = "README.md" [tool.poetry.dependencies] -python = "^3.12" -httpx = "^0.26.0" +python = ">=3.10,<4.0" +httpx = "^0.27.0" web3 = "^6.15.1" +pybars3 = "^0.9.7" +pydantic = "^2.7.0" +pytest-mock = "^3.14.0" +backoff = "^2.2.1" +aiolimiter = "^1.1.0" [tool.poetry.group.dev.dependencies] -ruff = "^0.2.2" -pyright ="^1.1.296" -pytest ="^7.2.1" -ipython = "^8.21.0" +ruff = "^0.3.7" +pyright = "^1.1.358" +pytest = "^8.1.1" +ipython = "^8.23.0" +pre-commit = "^3.7.0" +datamodel-code-generator = "^0.25.5" +ariadne-codegen = "^0.13.0" +pytest-httpx = "^0.30.0" +pytest-asyncio = "^0.23.6" +web3 = { extras = ["tester"], version = "^6.17.0" } +pycln = "^2.4.0" +pytest-cov = "^5.0.0" + +[tool.poetry.scripts] [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" + +[tool.ariadne-codegen] +remote_schema_url = "https://api.thegraph.com/subgraphs/name/cowprotocol/cow" +queries_path = "cow_py/subgraph/queries" +target_package_name = "client" +target_package_path = "cow_py/subgraph" +client_name = "SubgraphClient" +client_file_name = "subgraph_client" + +[tool.pyright] +# NOTE: these paths are excluded but not IGNORED. They are still included in the analysis if they are referenced by source files that are not excluded. +exclude = [ + "**/node_modules", + "**/__pycache__", + "cow_py/subgraph/client/*.py", + "cow_py/order_book/generated/*.py", + ".venv/", + "**/__generated__" +] +reportIncompatibleVariableOverride = 'warning' +strictParameterNoneValue = false diff --git a/tests/subgraphs/__init__.py b/tests/codegen/__init__.py similarity index 100% rename from tests/subgraphs/__init__.py rename to tests/codegen/__init__.py diff --git a/tests/codegen/components/test_base_contract.py b/tests/codegen/components/test_base_contract.py new file mode 100644 index 0000000..8294dcb --- /dev/null +++ b/tests/codegen/components/test_base_contract.py @@ -0,0 +1,60 @@ +import pytest +from unittest.mock import patch, Mock +from cow_py.codegen.components.base_contract import ( + BaseContract, + Chain, +) + + +@patch("cow_py.codegen.components.base_contract.ContractLoader") +def test_base_contract_singleton(mock_loader): + address = "0x123" + chain = Chain.MAINNET + contract1 = BaseContract(address, chain) + contract2 = BaseContract(address, chain) + assert ( + contract1 is contract2 + ), "BaseContract should return the same instance for the same address and chain" + + +class MockWithoutAttributes(Mock): + # By default Mock objects allow access to any attribute, even if it doesn't exist. + # on the Base Contract class, we want to raise an AttributeError if the attribute doesn't exist. + def __getattr__(self, name: str): + if name == "balanceOf" or name == "nonExistentMethod": + raise AttributeError() + return super().__getattr__(name) + + +@pytest.fixture +def contract_with_abi(): + abi = [ + {"type": "function", "name": "balanceOf"}, + {"type": "event", "name": "Transfer"}, + ] + with patch("cow_py.codegen.components.base_contract.ContractLoader") as mock_loader: + mock_contract = MockWithoutAttributes() + mock_contract.abi = abi + mock_contract.functions = Mock( + balanceOf=Mock(return_value=Mock(call=Mock(return_value="1000"))), + ) + + mock_loader.return_value.get_web3_contract.return_value = mock_contract + contract = BaseContract("0x456", Chain.MAINNET, abi) + return contract + + +def test_base_contract_function_exists_in_abi(contract_with_abi): + assert contract_with_abi._function_exists_in_abi("balanceOf") + assert not contract_with_abi._function_exists_in_abi("transfer") + + +def test_base_contract_event_exists_in_abi(contract_with_abi): + assert contract_with_abi._event_exists_in_abi("Transfer") + assert not contract_with_abi._event_exists_in_abi("Approval") + + +def test_base_contract_getattr(contract_with_abi): + assert contract_with_abi.balanceOf() == "1000" + with pytest.raises(AttributeError): + _ = contract_with_abi.nonExistentMethod diff --git a/tests/codegen/components/test_contract_factory.py b/tests/codegen/components/test_contract_factory.py new file mode 100644 index 0000000..137c6eb --- /dev/null +++ b/tests/codegen/components/test_contract_factory.py @@ -0,0 +1,42 @@ +import unittest +from unittest.mock import MagicMock, patch +from cow_py.codegen.components.contract_factory import ContractFactory, BaseContract +from cow_py.common.chains import Chain + + +class TestContractFactory(unittest.TestCase): + def setUp(self): + self.contract_name = "MockContract" + self.chain = Chain.MAINNET + self.abi_loader = MagicMock() + self.abi_loader.load_abi = MagicMock( + return_value=[{"type": "function", "name": "mockFunction"}] + ) + self.address = "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d" + + def test_contract_factory_get_contract_class(self): + with patch.dict( + "cow_py.codegen.components.contract_factory.ContractFactory._contract_classes", + clear=True, + ): + first_class = ContractFactory.get_contract_class( + self.contract_name, self.chain, self.abi_loader + ) + second_class = ContractFactory.get_contract_class( + self.contract_name, self.chain, self.abi_loader + ) + + self.abi_loader.load_abi.assert_called_once() + self.assertEqual(first_class, second_class) + + def test_contract_factory_create(self): + with patch.dict( + "cow_py.codegen.components.contract_factory.ContractFactory._contract_classes", + clear=True, + ): + contract_instance = ContractFactory.create( + self.contract_name, self.chain, self.address, self.abi_loader + ) + + self.assertIsInstance(contract_instance, BaseContract) + self.assertEqual(contract_instance.address, self.address) diff --git a/tests/codegen/test_abi_handler.py b/tests/codegen/test_abi_handler.py new file mode 100644 index 0000000..6110ecb --- /dev/null +++ b/tests/codegen/test_abi_handler.py @@ -0,0 +1,210 @@ +import pytest + +from cow_py.codegen.abi_handler import ( + to_python_conventional_name, + get_filename_without_extension, + _get_template_file, + _get_partials_files, + compile_partial, + ABIHandler, + FileAbiLoader, +) + +from unittest.mock import mock_open + + +@pytest.mark.parametrize( + "input_name, expected_output", + [ + # ("GPv2Order_Data", "gp_v2_order_data"), + ("simpleTest", "simple_test"), + ("ThisIsATest", "this_is_a_test"), + ("number2IsHere", "number_2_is_here"), + ("AnotherTest123", "another_test_123"), + ("JSONData", "json_data"), + # ("GPv2Order_Data_arg_1", "gp_v2_order_data_arg_1"), + ], +) +def test_to_python_conventional_name(input_name, expected_output): + assert to_python_conventional_name(input_name) == expected_output + + +def test_compile_partial(mocker): + # Test that compile_partial correctly compiles a partial template + mocked_file_content = "test content" + mocked_compiled_content = "compiled content" + + mocker.patch("builtins.open", mock_open(read_data=mocked_file_content)) + mocker.patch("pybars.Compiler.compile", return_value=mocked_compiled_content) + result = compile_partial("fake_path") + assert result == mocked_compiled_content + + +def test_get_filename_without_extension(): + # Test that get_filename_without_extension correctly removes the extension + assert get_filename_without_extension("folder/test.py") == "test" + + +def test_get_template_file(): + # Test that _get_template_file returns the correct template file path + assert _get_template_file().endswith("contract_template.hbs") + + +def test_get_partials_files(): + # Test that _get_partials_files returns the correct list of partial files + assert all([f.endswith(".hbs") for f in _get_partials_files()]) + + +@pytest.fixture +def abi_handler(): + return ABIHandler("TestContract", "/fake/path/to/abi.json") + + +def test_abi_handler_generate(mocker, abi_handler): + # Test that ABIHandler.generate correctly generates Python code from an ABI + mocked_abi_data = [ + {"type": "function", "name": "doSomething", "inputs": [], "outputs": []} + ] + mocker.patch( + "cow_py.codegen.abi_handler.FileAbiLoader.load_abi", + return_value=mocked_abi_data, + ) + mocker.patch( + "cow_py.codegen.abi_handler.ABIHandler._prepare_template_data", + return_value={"methods": []}, + ) + mocker.patch( + "cow_py.codegen.abi_handler.ABIHandler._render_template", + return_value="class MyContract:\n pass", + ) + + # Run the method + result = abi_handler.generate() + + # Verify the output + assert ( + result == "class MyContract:\n pass" + ), "Generated Python code does not match expected output." + + +def test_abi_handler_prepare_template_data(mocker, abi_handler): + # Test that ABIHandler._prepare_template_data correctly processes the ABI + sample_abi = [ + { + "type": "function", + "name": "setValue", + "inputs": [{"name": "value", "type": "uint256"}], + "outputs": [], + }, + { + "type": "event", + "name": "ValueChanged", + "inputs": [{"name": "value", "type": "uint256"}], + }, + ] + + mocker.patch.object(FileAbiLoader, "load_abi", return_value=sample_abi) + + mocker.patch.object( + abi_handler, + "_process_function", + return_value={ + "name": "set_value", + "inputs": ["uint256"], + "outputType": "None", + "originalName": "setValue", + }, + ) + mocker.patch.object(abi_handler, "_process_parameters", autospec=True) + + result = abi_handler._prepare_template_data() + + assert result["abiPath"] == "/fake/path/to/abi.json" + assert result["contractName"] == "TestContract" + assert len(result["methods"]) == 1 + assert result["methods"][0]["name"] == "set_value" + assert "dataClasses" in result + assert "enums" in result + + +def test_abi_handler_process_parameters(abi_handler): + # Test that ABIHandler._process_parameters correctly processes function parameters + param = { + "type": "tuple", + "internalType": "struct Value", + "components": [ + {"name": "x", "type": "uint256", "internalType": "uint256"}, + {"name": "y", "type": "uint256", "internalType": "uint256"}, + ], + } + data_classes = [] + enums = [] + generated_structs = set() + generated_enums = set() + + expected_data_class = { + "name": "Value", + "properties": [ + {"name": "x", "type": "int"}, + {"name": "y", "type": "int"}, + ], + } + + abi_handler._process_parameters( + param, data_classes, enums, generated_structs, generated_enums + ) + + assert "struct Value" in generated_structs + assert data_classes[0] == expected_data_class + + +def test_abi_handler_process_function(abi_handler, mocker): + # Test that ABIHandler._process_function correctly processes a function item + function_item = { + "type": "function", + "name": "getValue", + "inputs": [{"name": "key", "type": "uint256", "internalType": "uint256"}], + "outputs": [{"name": "result", "type": "uint256", "internalType": "uint256"}], + } + + result = abi_handler._process_function(function_item) + + expected_result = { + "name": "get_value", + "inputs": [{"name": "key", "type": "int", "isTuple": False}], + "outputType": "int", + "originalName": "getValue", + } + + assert result == expected_result + + +def test_abi_handler_render_template(abi_handler, mocker): + # Test that ABIHandler._render_template correctly renders the template with data + template_data = { + "abiPath": "/fake/path/to/abi.json", + "contractName": "TestContract", + "methods": [ + { + "name": "set_value", + "inputs": ["uint256"], + "outputType": "uint256", + "originalName": "setValue", + } + ], + "dataClasses": [], + "enums": [], + } + template_string = "class {{ contractName }}:\n pass" + expected_rendered_output = "class TestContract:\n pass" + + mocker.patch("builtins.open", mocker.mock_open(read_data=template_string)) + + mocker.patch( + "pybars.Compiler.compile", + return_value=lambda x, **kwargs: expected_rendered_output, + ) + + result = abi_handler._render_template(template_data) + + assert result == expected_rendered_output diff --git a/tests/codegen/test_solidity_converter.py b/tests/codegen/test_solidity_converter.py new file mode 100644 index 0000000..8324b2d --- /dev/null +++ b/tests/codegen/test_solidity_converter.py @@ -0,0 +1,84 @@ +import pytest + +from cow_py.codegen.solidity_converter import SolidityConverter, SolidityConverterError + + +def test_solidity_converter_get_struct_name(): + internal_type = "struct MyStruct" + expected_result = "MyStruct" + result = SolidityConverter._get_struct_name(internal_type) + assert result == expected_result + + +def test_solidity_converter_get_struct_name_invalid_internal_type(): + internal_type = "uint256" + with pytest.raises(SolidityConverterError): + SolidityConverter._get_struct_name(internal_type) + + +def test_solidity_converter_convert_type_enum(): + solidity_type = "enum MyEnum" + internal_type = "" + expected_result = "MyEnum" + result = SolidityConverter.convert_type(solidity_type, internal_type) + assert result == expected_result + + +def test_solidity_converter_convert_type_array(): + solidity_type = "uint256[]" + internal_type = "" + expected_result = "List[int]" + result = SolidityConverter.convert_type(solidity_type, internal_type) + assert result == expected_result + + +def test_solidity_converter_convert_type_tuple(): + solidity_type = "tuple" + internal_type = "struct MyStruct" + expected_result = "MyStruct" + result = SolidityConverter.convert_type(solidity_type, internal_type) + assert result == expected_result + + +def test_solidity_converter_convert_type_fixed_size_array(): + solidity_type = "uint256[3]" + internal_type = "" + expected_result = "Tuple[int, int, int]" + result = SolidityConverter.convert_type(solidity_type, internal_type) + assert result == expected_result + + +def test_solidity_converter_convert_type_unknown_type(): + solidity_type = "unknown_type" + internal_type = "" + expected_result = "Any" + result = SolidityConverter.convert_type(solidity_type, internal_type) + assert result == expected_result + + +def test_solidity_converter_extract_enum_name(): + internal_type = "enum MyEnum.Option" + expected_result = "MyEnum_Option" + result = SolidityConverter._extract_enum_name(internal_type) + assert result == expected_result + + +def test_solidity_converter_convert_array_or_basic_type_dynamic_array(): + solidity_type = "address[]" + expected_result = "List[str]" + result = SolidityConverter._convert_array_or_basic_type(solidity_type) + assert result == expected_result + + +def test_solidity_converter_convert_array_or_basic_type_fixed_size_array(): + solidity_type = "bool[5]" + expected_result = "Tuple[bool, bool, bool, bool, bool]" + result = SolidityConverter._convert_array_or_basic_type(solidity_type) + assert result == expected_result + + +def test_solidity_converter_convert_array_or_basic_type_basic_type(): + solidity_type = "bytes32" + expected_result = "HexBytes" + result = SolidityConverter._convert_array_or_basic_type(solidity_type) + assert result == expected_result diff --git a/tests/common/__init__.py b/tests/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/common/api/test_api_base.py b/tests/common/api/test_api_base.py new file mode 100644 index 0000000..1c3dd9f --- /dev/null +++ b/tests/common/api/test_api_base.py @@ -0,0 +1,129 @@ +from unittest.mock import AsyncMock, Mock, patch + +import httpx +import pytest + +from cow_py.common.api.api_base import ApiBase, APIConfig +from cow_py.common.api.decorators import DEFAULT_BACKOFF_OPTIONS +from cow_py.common.config import SupportedChainId +from httpx import Request + +ERROR_MESSAGE = "💣💥 Booom!" +OK_RESPONSE = {"status": 200, "ok": True, "content": {"some": "data"}} + + +@pytest.fixture +def sut(): + class MyConfig(APIConfig): + def __init__(self): + super().__init__(SupportedChainId.SEPOLIA, None) + + def get_base_url(self): + return "http://localhost" + + class MyAPI(ApiBase): + @staticmethod + def get_config(context): + return Mock( + chain_id="mainnet", get_base_url=Mock(return_value="http://localhost") + ) + + async def get_version(self, context_override={}): + return await self._fetch( + path="/api/v1/version", context_override=context_override + ) + + return MyAPI(config=MyConfig()) + + +@pytest.fixture +def mock_success_response(): + return AsyncMock( + status_code=200, + headers={"content-type": "application/json"}, + json=Mock(return_value=OK_RESPONSE), + ) + + +@pytest.fixture +def mock_http_status_error(): + return httpx.HTTPStatusError( + message=ERROR_MESSAGE, + request=Request("GET", "http://example.com"), + response=httpx.Response(500), + ) + + +@pytest.mark.asyncio +async def test_no_re_attempt_if_success(sut, mock_success_response): + with patch( + "httpx.AsyncClient.send", side_effect=[mock_success_response] + ) as mock_request: + response = await sut.get_version() + assert mock_request.awaited_once() + assert response["content"]["some"] == "data" + + +@pytest.mark.asyncio +async def test_re_attempts_if_fails_then_succeeds( + sut, mock_success_response, mock_http_status_error +): + with patch( + "httpx.AsyncClient.send", + side_effect=[ + *([mock_http_status_error] * 3), + mock_success_response, + ], + ) as mock_request: + response = await sut.get_version() + + assert response["ok"] is True + assert mock_request.call_count == 4 + + +@pytest.mark.asyncio +async def test_succeeds_last_attempt( + sut, mock_success_response, mock_http_status_error +): + with patch( + "httpx.AsyncClient.send", + side_effect=[ + mock_http_status_error, + mock_http_status_error, + mock_success_response, + ], + ) as mock_send: + response = await sut.get_version() + assert response["ok"] is True + assert mock_send.call_count == 3 + + +@pytest.mark.asyncio +async def test_does_not_reattempt_after_max_failures(sut, mock_http_status_error): + with patch( + "httpx.AsyncClient.request", side_effect=[mock_http_status_error] * 3 + ) as mock_call: + with pytest.raises(httpx.HTTPStatusError): + await sut.get_version(context_override={"backoff_opts": {"max_tries": 3}}) + + assert mock_call.call_count == 3 + + +@pytest.mark.asyncio +async def test_backoff_uses_function_options_instead_of_default( + sut, mock_http_status_error +): + max_tries = 1 + + assert max_tries != DEFAULT_BACKOFF_OPTIONS["max_tries"] + + with patch( + "httpx.AsyncClient.request", + side_effect=[mock_http_status_error] * max_tries, + ) as mock_call: + with pytest.raises(httpx.HTTPStatusError): + await sut.get_version( + context_override={"backoff_opts": {"max_tries": max_tries}} + ) + + assert mock_call.call_count == max_tries diff --git a/tests/common/api/test_rate_limiter.py b/tests/common/api/test_rate_limiter.py new file mode 100644 index 0000000..1e6ca12 --- /dev/null +++ b/tests/common/api/test_rate_limiter.py @@ -0,0 +1,28 @@ +import asyncio + +import pytest + +from cow_py.common.api.decorators import rate_limitted + + +@pytest.mark.asyncio +async def test_call_intervals(): + async def test_function(): + return "called" + + # Set the rate limit for easy calculation (e.g., 2 calls per second) + decorated_function = rate_limitted(2, 1)(test_function) + + call_times = [] + + # Perform a number of calls and record the time each was completed + for _ in range(6): + await decorated_function() + call_times.append(asyncio.get_event_loop().time()) + + # Verify intervals between calls are as expected (at least 0.5 seconds apart after the first batch of 2) + intervals = [call_times[i] - call_times[i - 1] for i in range(1, len(call_times))] + for interval in intervals[2:]: # Ignore the first two immediate calls + assert ( + interval >= 0.5 + ), f"Interval of {interval} too short, should be at least 0.5" diff --git a/tests/common/test_core_api.py b/tests/common/test_core_api.py new file mode 100644 index 0000000..992d22d --- /dev/null +++ b/tests/common/test_core_api.py @@ -0,0 +1,8 @@ +import pytest + +from cow_py.common import chains, config, constants, cow_error + + +@pytest.mark.parametrize("module", [constants, cow_error, chains, config]) +def test_module_existence(module): + assert module is not None diff --git a/tests/core/test_cow_error.py b/tests/common/test_cow_error.py similarity index 61% rename from tests/core/test_cow_error.py rename to tests/common/test_cow_error.py index d97e8ea..31c3aaa 100644 --- a/tests/core/test_cow_error.py +++ b/tests/common/test_cow_error.py @@ -1,16 +1,11 @@ -import pytest -from cow_py.core.cow_error import ( - CowError, -) # Adjust the import path according to your project structure +from cow_py.common.cow_error import CowError def test_cow_error_inheritance(): - # Test that CowError is a subclass of Exception assert issubclass(CowError, Exception) def test_cow_error_initialization(): - # Test CowError initialization with a message and error_code message = "An error occurred" error_code = 1001 error = CowError(message, error_code) @@ -20,7 +15,6 @@ def test_cow_error_initialization(): def test_cow_error_initialization_without_error_code(): - # Test CowError initialization with only a message message = "An error occurred" error = CowError(message) diff --git a/tests/contracts/conftest.py b/tests/contracts/conftest.py new file mode 100644 index 0000000..98af89f --- /dev/null +++ b/tests/contracts/conftest.py @@ -0,0 +1,39 @@ +from eth_utils.conversions import to_hex +from eth_utils.crypto import keccak +from eth_utils.currency import to_wei + +from cow_py.contracts.order import Order + + +def fill_bytes(count, byte): + return to_hex(bytearray([byte] * count)) + + +def fill_distinct_bytes(count, start): + return to_hex(bytearray([(start + i) % 256 for i in range(count)])) + + +def fill_uint(bits, byte): + return int(fill_bytes(bits // 8, byte), 16) + + +def ceil_div(p, q): + return (p + q - 1) // q + + +ORDER_KIND_SELL = "SELL" + +SAMPLE_ORDER = Order( + **{ + "sellToken": fill_bytes(20, 0x01), + "buyToken": fill_bytes(20, 0x02), + "receiver": fill_bytes(20, 0x03), + "sellAmount": to_wei("42", "ether"), + "buyAmount": to_wei("13.37", "ether"), + "validTo": 0xFFFFFFFF, + "appData": keccak(text="")[0:20], + "feeAmount": to_wei("1.0", "ether"), + "kind": ORDER_KIND_SELL, + "partiallyFillable": False, + } +) diff --git a/tests/contracts/test_orders.py b/tests/contracts/test_orders.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/contracts/test_sign.py b/tests/contracts/test_sign.py new file mode 100644 index 0000000..a15e47b --- /dev/null +++ b/tests/contracts/test_sign.py @@ -0,0 +1,76 @@ +import pytest +from eth_account.messages import SignableMessage +from eth_account.signers.local import LocalAccount +from eth_utils.conversions import to_hex +from web3 import EthereumTesterProvider, Web3 + +from cow_py.contracts.order import hash_order_cancellation + +from cow_py.contracts.sign import SigningScheme, sign_order, sign_order_cancellation + +from .conftest import SAMPLE_ORDER + +w3 = Web3(EthereumTesterProvider()) + + +def patched_sign_message_builder(account: LocalAccount): + def sign_message(message): + # Determine the correct message format + if isinstance(message, SignableMessage): + message_to_hash = message.body + elif isinstance(message, (bytes, str)): + message_to_hash = message + else: + raise TypeError("Unsupported message type for signing.") + + # Hash and sign the message + message_hash = Web3.solidity_keccak(["bytes"], [message_to_hash]) + signature = account.signHash(message_hash) + r, s, v = signature["r"], signature["s"], signature["v"] + + # Adjust v to be 27 or 28 + v_adjusted = v + 27 if v < 27 else v + + # Concatenate the signature components into a hex string + signature_hex = to_hex(r)[2:] + to_hex(s)[2:] + hex(v_adjusted)[2:] + + return signature_hex + + return sign_message + + +@pytest.mark.asyncio +@pytest.mark.parametrize("scheme", [SigningScheme.EIP712, SigningScheme.ETHSIGN]) +async def test_sign_order(monkeypatch, scheme): + signer = w3.eth.account.create() + + patched_sign_message = patched_sign_message_builder(signer) + + # Use monkeypatch to temporarily replace sign_message + monkeypatch.setattr(signer, "sign_message", patched_sign_message) + + domain = {"name": "test"} + signed_order = sign_order(domain, SAMPLE_ORDER, signer, scheme) + + # Extract 'v' value from the last two characters of the signature + v = signed_order.data[-2:] + + assert v in ["1b", "1c"] + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "scheme", [SigningScheme.EIP712.value, SigningScheme.ETHSIGN.value] +) +async def test_sign_order_cancellation(scheme): + signer = w3.eth.account.create() + domain = {"name": "test"} + order_uid = "0x" + "2a" * 56 + + signature_data = sign_order_cancellation(domain, order_uid, signer, scheme) + order_hash = hash_order_cancellation(domain, order_uid) + + assert ( + w3.eth.account._recover_hash(order_hash, signature=signature_data.data) + == signer.address + ) diff --git a/tests/core/test_abis.py b/tests/core/test_abis.py deleted file mode 100644 index 3b90f61..0000000 --- a/tests/core/test_abis.py +++ /dev/null @@ -1,10 +0,0 @@ -import pytest -from cow_py.core import abis - - -@pytest.mark.parametrize( - "variable", [item for item in dir(abis) if not item.startswith("__")] -) -def test_all_variables_are_abis(variable): - # TODO: verify that they're all valid ABIs - assert vars(abis)[variable] is not None diff --git a/tests/core/test_core_api.py b/tests/core/test_core_api.py deleted file mode 100644 index a9ba8ba..0000000 --- a/tests/core/test_core_api.py +++ /dev/null @@ -1,7 +0,0 @@ -import pytest -from cow_py.core import constants, cow_error, abis, chains, config, utils - - -@pytest.mark.parametrize("module", [constants, cow_error, abis, chains, config, utils]) -def test_module_existence(module): - assert module is not None diff --git a/tests/order_book/test_api.py b/tests/order_book/test_api.py new file mode 100644 index 0000000..72f5d22 --- /dev/null +++ b/tests/order_book/test_api.py @@ -0,0 +1,147 @@ +from unittest.mock import AsyncMock, Mock, patch + +import pytest + +from cow_py.order_book.api import OrderBookApi +from cow_py.order_book.generated.model import OrderQuoteSide1 +from cow_py.order_book.generated.model import OrderQuoteSideKindSell +from cow_py.order_book.generated.model import TokenAmount +from cow_py.order_book.generated.model import ( + OrderQuoteRequest, + OrderQuoteResponse, + Trade, + OrderCreation, +) + + +@pytest.fixture +def order_book_api(): + return OrderBookApi() + + +@pytest.mark.asyncio +async def test_get_version(order_book_api): + expected_version = "1.0.0" + with patch("httpx.AsyncClient.request", new_callable=AsyncMock) as mock_request: + mock_request.return_value = AsyncMock( + status_code=200, + text=expected_version, + ) + version = await order_book_api.get_version() + + mock_request.assert_awaited_once() + assert version == expected_version + + +@pytest.mark.asyncio +async def test_get_trades_by_order_uid(order_book_api): + mock_trade_data = [ + { + "blockNumber": 123456, + "logIndex": 789, + "orderUid": "mock_order_uid", + "owner": "mock_owner_address", + "sellToken": "mock_sell_token_address", + "buyToken": "mock_buy_token_address", + "sellAmount": "100", + "sellAmountBeforeFees": "120", + "buyAmount": "200", + "txHash": "mock_transaction_hash", + } + ] + mock_trade = Trade(**mock_trade_data[0]) + with patch("httpx.AsyncClient.request", new_callable=AsyncMock) as mock_request: + mock_request.return_value = AsyncMock( + status_code=200, + headers={"content-type": "application/json"}, + json=Mock(return_value=mock_trade_data), + ) + trades = await order_book_api.get_trades_by_order_uid("mock_order_uid") + mock_request.assert_awaited_once() + assert trades == [mock_trade] + + +@pytest.mark.asyncio +async def test_post_quote(order_book_api): + mock_order_quote_request = OrderQuoteRequest( + **{ + "sellToken": "0x", + "buyToken": "0x", + "receiver": "0x", + "appData": "app_data_object", + "appDataHash": "0x", + "from": "0x", + "priceQuality": "verified", + "signingScheme": "eip712", + "onchainOrder": False, + } + ) + + mock_order_quote_side = OrderQuoteSide1( + sellAmountBeforeFee=TokenAmount("0"), kind=OrderQuoteSideKindSell.sell + ) + mock_order_quote_response_data = { + "quote": { + "sellToken": "0x", + "buyToken": "0x", + "receiver": "0x", + "sellAmount": "0", + "buyAmount": "0", + "feeAmount": "0", + "validTo": 0, + "appData": "0x", + "partiallyFillable": True, + "sellTokenBalance": "erc20", + "buyTokenBalance": "erc20", + "kind": "buy", + }, + "verified": True, + "from": "0x", + "expiration": "0", + } + mock_order_quote_response = OrderQuoteResponse(**mock_order_quote_response_data) + with patch("httpx.AsyncClient.request", new_callable=AsyncMock) as mock_request: + mock_request.return_value = AsyncMock( + status_code=200, + headers={"content-type": "application/json"}, + json=Mock(return_value=mock_order_quote_response_data), + ) + response = await order_book_api.post_quote( + mock_order_quote_request, mock_order_quote_side + ) + mock_request.assert_awaited_once() + assert response == mock_order_quote_response + + +@pytest.mark.asyncio +async def test_post_order(order_book_api): + mock_response = "mock_uid" + mock_order_creation = OrderCreation( + **{ + "sellToken": "0x", + "buyToken": "0x", + "sellAmount": "0", + "buyAmount": "0", + "validTo": 0, + "feeAmount": "0", + "kind": "buy", + "partiallyFillable": True, + "appData": "0x", + "signingScheme": "eip712", + "signature": "0x", + "receiver": "0x", + "sellTokenBalance": "erc20", + "buyTokenBalance": "erc20", + "quoteId": 0, + "appDataHash": "0x", + "from_": "0x", + } + ) + with patch("httpx.AsyncClient.request", new_callable=AsyncMock) as mock_request: + mock_request.return_value = AsyncMock( + status_code=200, + text=mock_response, + ) + response = await order_book_api.post_order(mock_order_creation) + mock_request.assert_awaited_once() + assert response.root == mock_response diff --git a/tests/subgraph/__init__.py b/tests/subgraph/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/subgraph/client/test_subgraph_client.py b/tests/subgraph/client/test_subgraph_client.py new file mode 100644 index 0000000..6bc57e4 --- /dev/null +++ b/tests/subgraph/client/test_subgraph_client.py @@ -0,0 +1,466 @@ +import pytest +from pytest_httpx import HTTPXMock + +from cow_py.subgraph.client import SubgraphClient +from cow_py.subgraph.client.exceptions import GraphQLClientGraphQLMultiError +from cow_py.subgraph.client.last_days_volume import ( + LastDaysVolume, + LastDaysVolumeDailyTotals, +) +from cow_py.subgraph.client.last_hours_volume import ( + LastHoursVolume, + LastHoursVolumeHourlyTotals, +) +from cow_py.subgraph.client.totals import Totals, TotalsTotals + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "query_method, variables, mocked_response, expected_response", + [ + ( + "totals", + dict(), + { + "data": { + "totals": [ + { + "tokens": "192", + "orders": "365210", + "traders": "50731", + "settlements": "160092", + "volumeUsd": "49548634.23978489392550883815112596", + "volumeEth": "20349080.82753326160179174564685693", + "feesUsd": "1495.18088540037791409373835505834", + "feesEth": "632.7328748466552906975758491191759", + } + ] + } + }, + Totals( + totals=[ + TotalsTotals( + tokens="192", + orders="365210", + traders="50731", + settlements="160092", + volumeUsd="49548634.23978489392550883815112596", + volumeEth="20349080.82753326160179174564685693", + feesUsd="1495.18088540037791409373835505834", + feesEth="632.7328748466552906975758491191759", + ) + ] + ), + ), + ( + "last_days_volume", + dict(days=7), + { + "data": { + "dailyTotals": [ + { + "timestamp": "1651104000", + "volumeUsd": "32085.1639220805155999650325844739", + }, + { + "timestamp": "1651017600", + "volumeUsd": "34693.62007717297749801092930059675", + }, + { + "timestamp": "1650931200", + "volumeUsd": "33122.5365226034644783539316622137", + }, + { + "timestamp": "1650844800", + "volumeUsd": "44339.87713137673812392999146686429", + }, + { + "timestamp": "1650758400", + "volumeUsd": "33152.20678736108925012284114682263", + }, + { + "timestamp": "1650672000", + "volumeUsd": "74499.81969341967474378140565634503", + }, + { + "timestamp": "1650585600", + "volumeUsd": "55696.47839632449194353566942457261", + }, + ] + } + }, + LastDaysVolume( + dailyTotals=[ + LastDaysVolumeDailyTotals( + timestamp=1651104000, + volumeUsd="32085.1639220805155999650325844739", + ), + LastDaysVolumeDailyTotals( + timestamp=1651017600, + volumeUsd="34693.62007717297749801092930059675", + ), + LastDaysVolumeDailyTotals( + timestamp=1650931200, + volumeUsd="33122.5365226034644783539316622137", + ), + LastDaysVolumeDailyTotals( + timestamp=1650844800, + volumeUsd="44339.87713137673812392999146686429", + ), + LastDaysVolumeDailyTotals( + timestamp=1650758400, + volumeUsd="33152.20678736108925012284114682263", + ), + LastDaysVolumeDailyTotals( + timestamp=1650672000, + volumeUsd="74499.81969341967474378140565634503", + ), + LastDaysVolumeDailyTotals( + timestamp=1650585600, + volumeUsd="55696.47839632449194353566942457261", + ), + ] + ), + ), + ( + "last_hours_volume", + dict(hours=24), + { + "data": { + "hourlyTotals": [ + { + "timestamp": "1651186800", + "volumeUsd": "190.9404913756501392195019404899438", + }, + { + "timestamp": "1651183200", + "volumeUsd": "529.9946238000561779423929757743504", + }, + { + "timestamp": "1651179600", + "volumeUsd": "645.3587505699802324165958548720157", + }, + { + "timestamp": "1651176000", + "volumeUsd": "1708.483608648853800630669110444808", + }, + { + "timestamp": "1651172400", + "volumeUsd": "7121.457330823292680300996744986044", + }, + { + "timestamp": "1651168800", + "volumeUsd": "1821.297602760111978245784985569166", + }, + { + "timestamp": "1651165200", + "volumeUsd": "2785.484680212634326873580046251588", + }, + { + "timestamp": "1651161600", + "volumeUsd": "1969.469152211506355791899301692229", + }, + { + "timestamp": "1651158000", + "volumeUsd": "2162.897300873319012826008286358389", + }, + { + "timestamp": "1651154400", + "volumeUsd": "1513.553639465779399627761684465762", + }, + { + "timestamp": "1651150800", + "volumeUsd": "187.4730505008263524958136028913312", + }, + { + "timestamp": "1651147200", + "volumeUsd": "1003.733903282400166632845200890861", + }, + { + "timestamp": "1651143600", + "volumeUsd": "430.0861170487354094851133346726692", + }, + { + "timestamp": "1651140000", + "volumeUsd": "332.7800791403069749429589009477125", + }, + { + "timestamp": "1651136400", + "volumeUsd": "97.63235373438852625638744867165181", + }, + { + "timestamp": "1651132800", + "volumeUsd": "30.59818396279718981525514608110329", + }, + { + "timestamp": "1651129200", + "volumeUsd": "4891.57094852254524822966041865283", + }, + { + "timestamp": "1651125600", + "volumeUsd": "0.2822502035827220060153182158280592", + }, + { + "timestamp": "1651122000", + "volumeUsd": "2618.536314756480243120625177213215", + }, + { + "timestamp": "1651118400", + "volumeUsd": "188.6060152287524476251961231904293", + }, + { + "timestamp": "1651114800", + "volumeUsd": "1081.900497533608727191602938189487", + }, + { + "timestamp": "1651111200", + "volumeUsd": "189.2511347347182236433877630220942", + }, + { + "timestamp": "1651107600", + "volumeUsd": "443.7262478626930371100298278690119", + }, + { + "timestamp": "1651104000", + "volumeUsd": "240.7104588694898118223893758683719", + }, + ] + } + }, + LastHoursVolume( + hourlyTotals=[ + LastHoursVolumeHourlyTotals( + timestamp=1651186800, + volumeUsd="190.9404913756501392195019404899438", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651183200, + volumeUsd="529.9946238000561779423929757743504", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651179600, + volumeUsd="645.3587505699802324165958548720157", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651176000, + volumeUsd="1708.483608648853800630669110444808", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651172400, + volumeUsd="7121.457330823292680300996744986044", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651168800, + volumeUsd="1821.297602760111978245784985569166", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651165200, + volumeUsd="2785.484680212634326873580046251588", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651161600, + volumeUsd="1969.469152211506355791899301692229", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651158000, + volumeUsd="2162.897300873319012826008286358389", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651154400, + volumeUsd="1513.553639465779399627761684465762", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651150800, + volumeUsd="187.4730505008263524958136028913312", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651147200, + volumeUsd="1003.733903282400166632845200890861", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651143600, + volumeUsd="430.0861170487354094851133346726692", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651140000, + volumeUsd="332.7800791403069749429589009477125", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651136400, + volumeUsd="97.63235373438852625638744867165181", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651132800, + volumeUsd="30.59818396279718981525514608110329", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651129200, + volumeUsd="4891.57094852254524822966041865283", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651125600, + volumeUsd="0.2822502035827220060153182158280592", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651122000, + volumeUsd="2618.536314756480243120625177213215", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651118400, + volumeUsd="188.6060152287524476251961231904293", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651114800, + volumeUsd="1081.900497533608727191602938189487", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651111200, + volumeUsd="189.2511347347182236433877630220942", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651107600, + volumeUsd="443.7262478626930371100298278690119", + ), + LastHoursVolumeHourlyTotals( + timestamp=1651104000, + volumeUsd="240.7104588694898118223893758683719", + ), + ] + ), + ), + ], +) +async def test_subgraph_client_existing_queries( + httpx_mock: HTTPXMock, query_method, variables, mocked_response, expected_response +): + httpx_mock.add_response(json=mocked_response) + + client = SubgraphClient(url="https://test_url") + query = await getattr(client, query_method)(*variables) + + assert query == expected_response + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "query, mocked_response, expected_response", + [ + ( + """ + query TokensByVolume { + tokens(first: 5, orderBy: totalVolumeUsd, orderDirection: desc) { + address + symbol + totalVolumeUsd + priceUsd + } + } + """, + { + "data": { + "tokens": [ + { + "address": "0xe91d153e0b41518a2ce8dd3d7944fa863463a97d", + "symbol": "WXDAI", + "totalVolumeUsd": "32889034.621839712648167717", + "priceUsd": "1", + }, + { + "address": "0xddafbb505ad214d7b80b1f830fccc89b60fb7a83", + "symbol": "USDC", + "totalVolumeUsd": "31296380.98818012532887553375630894", + "priceUsd": "0.9983008873217955125012875742815512", + }, + { + "address": "0x6a023ccd1ff6f2045c3309768ead9e68f978f6e1", + "symbol": "WETH", + "totalVolumeUsd": "11313677.56406394346907690670613874", + "priceUsd": "2930.058705030603523831034274967579", + }, + { + "address": "0x4ecaba5870353805a9f068101a40e0f32ed605c6", + "symbol": "USDT", + "totalVolumeUsd": "9390602.813697073697851431730404586", + "priceUsd": "1.00560814041993584287438922806966", + }, + { + "address": "0x9c58bacc331c9aa871afd802db6379a98e80cedb", + "symbol": "GNO", + "totalVolumeUsd": "5667965.685777522243148118842046968", + "priceUsd": "327.4436350035803489070442497891915", + }, + ] + } + }, + { + "tokens": [ + { + "address": "0xe91d153e0b41518a2ce8dd3d7944fa863463a97d", + "symbol": "WXDAI", + "totalVolumeUsd": "32889034.621839712648167717", + "priceUsd": "1", + }, + { + "address": "0xddafbb505ad214d7b80b1f830fccc89b60fb7a83", + "symbol": "USDC", + "totalVolumeUsd": "31296380.98818012532887553375630894", + "priceUsd": "0.9983008873217955125012875742815512", + }, + { + "address": "0x6a023ccd1ff6f2045c3309768ead9e68f978f6e1", + "symbol": "WETH", + "totalVolumeUsd": "11313677.56406394346907690670613874", + "priceUsd": "2930.058705030603523831034274967579", + }, + { + "address": "0x4ecaba5870353805a9f068101a40e0f32ed605c6", + "symbol": "USDT", + "totalVolumeUsd": "9390602.813697073697851431730404586", + "priceUsd": "1.00560814041993584287438922806966", + }, + { + "address": "0x9c58bacc331c9aa871afd802db6379a98e80cedb", + "symbol": "GNO", + "totalVolumeUsd": "5667965.685777522243148118842046968", + "priceUsd": "327.4436350035803489070442497891915", + }, + ] + }, + ) + ], +) +async def test_subgraph_client_custom_query( + httpx_mock: HTTPXMock, query, mocked_response, expected_response +): + httpx_mock.add_response(json=mocked_response) + client = SubgraphClient(url="https://test_url") + response = await client.execute(query=query) + + assert client.get_data(response) == expected_response + + +@pytest.mark.asyncio +async def test_subgraph_client_invalid_query(httpx_mock: HTTPXMock): + httpx_mock.add_response( + json={ + "errors": [ + { + "locations": [{"line": 2, "column": 9}], + "message": "Type `Query` has no field `invalidQuery`", + } + ] + } + ) + query = """ + query InvalidQuery { + invalidQuery { + field1 + field2 + } + } + """ + client = SubgraphClient(url="https://test_url") + response = await client.execute(query=query) + + with pytest.raises(GraphQLClientGraphQLMultiError): + client.get_data(response) diff --git a/tests/subgraphs/deployments.py b/tests/subgraph/test_deployments.py similarity index 94% rename from tests/subgraphs/deployments.py rename to tests/subgraph/test_deployments.py index cca32d0..2fd097b 100644 --- a/tests/subgraphs/deployments.py +++ b/tests/subgraph/test_deployments.py @@ -1,10 +1,11 @@ import pytest -from cow_py.core.chains import Chain -from cow_py.subgraphs.deployments import ( - build_subgraph_url, + +from cow_py.common.chains import Chain +from cow_py.subgraph.deployments import ( + SUBGRAPH_BASE_URL, SubgraphConfig, SubgraphEnvironment, - SUBGRAPH_BASE_URL, + build_subgraph_url, )