From baa205377fc9cc46211dfbb3ced990a39d10e530 Mon Sep 17 00:00:00 2001 From: Bogdan Opanchuk Date: Sat, 25 May 2024 22:33:01 -0700 Subject: [PATCH] Move RPC types to their own package --- .github/workflows/tests.yml | 7 +- README.md | 4 +- docs/api.rst | 61 +-- docs/changelog.rst | 68 ++-- pdm.lock | 344 +++++++++-------- pons/__init__.py | 12 +- pons/_abi_types.py | 4 +- pons/_client.py | 124 +++--- pons/_compiler.py | 23 +- pons/_contract.py | 3 +- pons/_contract_abi.py | 5 +- pons/_entities.py | 548 --------------------------- pons/_fallback_provider.py | 3 +- pons/_http_provider_server.py | 7 +- pons/_local_provider.py | 8 +- pons/_provider.py | 5 +- pons/_serialization.py | 177 --------- pons/_signer.py | 4 +- pyproject.toml | 5 +- tests/conftest.py | 3 +- tests/test_abi_types.py | 4 +- tests/test_client.py | 45 ++- tests/test_contract.py | 5 +- tests/test_contract_abi.py | 4 +- tests/test_contract_functionality.py | 4 +- tests/test_entities.py | 123 ------ tests/test_fallback_provider.py | 4 +- tests/test_http_provider_server.py | 3 +- tests/test_local_provider.py | 3 +- tests/test_provider.py | 7 +- tests/test_serialization.py | 38 -- tests/test_signer.py | 3 +- 32 files changed, 396 insertions(+), 1262 deletions(-) delete mode 100644 pons/_entities.py delete mode 100644 pons/_serialization.py delete mode 100644 tests/test_entities.py delete mode 100644 tests/test_serialization.py diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 17718cd..6223d40 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -39,10 +39,9 @@ jobs: pdm run py.test --cov=pons --cov-report=xml tests - name: Upload coverage if: matrix.python-version == '3.10' - run: | - curl -Os https://uploader.codecov.io/latest/linux/codecov - chmod +x codecov - ./codecov + uses: codecov/codecov-action@v4.0.1 + with: + token: ${{ secrets.CODECOV_TOKEN }} doctest: runs-on: ubuntu-latest diff --git a/README.md b/README.md index a5d249e..9fa3108 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ For more information see [the documentation](https://pons.readthedocs.io/en/late [pypi-license-image]: https://img.shields.io/pypi/l/pons [rtd-image]: https://readthedocs.org/projects/pons/badge/?version=latest [rtd-link]: https://pons.readthedocs.io/en/latest/ -[cov-image]: https://codecov.io/gh/fjarri/pons/branch/master/graph/badge.svg?token=RZP1LK1HB2 -[cov-link]: https://codecov.io/gh/fjarri/pons +[cov-image]: https://codecov.io/gh/fjarri-eth/pons/branch/master/graph/badge.svg?token=RZP1LK1HB2 +[cov-link]: https://codecov.io/gh/fjarri-eth/pons [black-image]: https://img.shields.io/badge/code%20style-black-000000.svg [black-link]: https://github.com/psf/black diff --git a/docs/api.rst b/docs/api.rst index f4093b5..5b01898 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -131,6 +131,9 @@ Testing utilities ``pons`` exposes several types useful for testing applications that connect to Ethereum RPC servers. Not intended for the production environment. +Install with the feature ``local-provider`` for it to be available. + + .. autoclass:: LocalProvider :show-inheritance: :members: disable_auto_mine_transactions, enable_auto_mine_transactions, take_snapshot, revert_to_snapshot @@ -140,6 +143,18 @@ Testing utilities :special-members: __call__ +Compiler +-------- + +Install with the feature ``compiler`` for it to be available. + + +.. autofunction:: compile_contract_file + +.. autoclass:: EVMVersion + :members: + + Secondary classes ----------------- @@ -205,40 +220,8 @@ Compiled and deployed contracts :members: -Entities --------- - -.. autoclass:: Amount - :members: - -.. class:: pons._entities.CustomAmount - - A type derived from :py:class:`Amount`. - -.. autoclass:: Address - :members: - -.. class:: pons._entities.CustomAddress - - A type derived from :py:class:`Address`. - -.. autoclass:: Block() - :members: - -.. autoclass:: TxHash - :members: - -.. autoclass:: BlockHash - :members: - -.. autoclass:: pons._entities.TxReceipt() - :members: - -.. autoclass:: pons._entities.BlockInfo() - :members: - -.. autoclass:: pons._entities.TxInfo() - :members: +Filter objects +-------------- .. autoclass:: pons._entities.BlockFilter() @@ -246,16 +229,6 @@ Entities .. autoclass:: pons._entities.LogFilter() -.. autoclass:: pons._entities.LogTopic() - -.. autoclass:: pons._entities.LogEntry() - :members: - -.. class:: JSON - - A JSON-ifiable object (``bool``, ``int``, ``float``, ``str``, ``None``, - iterable of ``JSON``, or mapping of ``str`` to ``JSON``). - Solidity types -------------- diff --git a/docs/changelog.rst b/docs/changelog.rst index bd1c429..515c419 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -52,23 +52,23 @@ Fixed - Expect the block number to be non-null even for pending blocks, since that's what providers return. (PR_70_) -.. _PR_51: https://github.com/fjarri/pons/pull/51 -.. _PR_52: https://github.com/fjarri/pons/pull/52 -.. _PR_54: https://github.com/fjarri/pons/pull/54 -.. _PR_56: https://github.com/fjarri/pons/pull/56 -.. _PR_57: https://github.com/fjarri/pons/pull/57 -.. _PR_59: https://github.com/fjarri/pons/pull/59 -.. _PR_61: https://github.com/fjarri/pons/pull/61 -.. _PR_62: https://github.com/fjarri/pons/pull/62 -.. _PR_63: https://github.com/fjarri/pons/pull/63 -.. _PR_64: https://github.com/fjarri/pons/pull/64 -.. _PR_65: https://github.com/fjarri/pons/pull/65 -.. _PR_67: https://github.com/fjarri/pons/pull/67 -.. _PR_68: https://github.com/fjarri/pons/pull/68 -.. _PR_70: https://github.com/fjarri/pons/pull/70 -.. _PR_72: https://github.com/fjarri/pons/pull/72 -.. _PR_75: https://github.com/fjarri/pons/pull/75 -.. _PR_76: https://github.com/fjarri/pons/pull/76 +.. _PR_51: https://github.com/fjarri-eth/pons/pull/51 +.. _PR_52: https://github.com/fjarri-eth/pons/pull/52 +.. _PR_54: https://github.com/fjarri-eth/pons/pull/54 +.. _PR_56: https://github.com/fjarri-eth/pons/pull/56 +.. _PR_57: https://github.com/fjarri-eth/pons/pull/57 +.. _PR_59: https://github.com/fjarri-eth/pons/pull/59 +.. _PR_61: https://github.com/fjarri-eth/pons/pull/61 +.. _PR_62: https://github.com/fjarri-eth/pons/pull/62 +.. _PR_63: https://github.com/fjarri-eth/pons/pull/63 +.. _PR_64: https://github.com/fjarri-eth/pons/pull/64 +.. _PR_65: https://github.com/fjarri-eth/pons/pull/65 +.. _PR_67: https://github.com/fjarri-eth/pons/pull/67 +.. _PR_68: https://github.com/fjarri-eth/pons/pull/68 +.. _PR_70: https://github.com/fjarri-eth/pons/pull/70 +.. _PR_72: https://github.com/fjarri-eth/pons/pull/72 +.. _PR_75: https://github.com/fjarri-eth/pons/pull/75 +.. _PR_76: https://github.com/fjarri-eth/pons/pull/76 0.7.0 (09-07-2023) @@ -88,9 +88,9 @@ Added - ``Mutability`` enum for defining contract method mutability. (PR_50_) -.. _PR_48: https://github.com/fjarri/pons/pull/48 -.. _PR_49: https://github.com/fjarri/pons/pull/49 -.. _PR_50: https://github.com/fjarri/pons/pull/50 +.. _PR_48: https://github.com/fjarri-eth/pons/pull/48 +.. _PR_49: https://github.com/fjarri-eth/pons/pull/49 +.. _PR_50: https://github.com/fjarri-eth/pons/pull/50 @@ -115,7 +115,7 @@ Fixed - Support the existence of outputs in the JSON ABI of a mutating method. (PR_47_) -.. _PR_47: https://github.com/fjarri/pons/pull/47 +.. _PR_47: https://github.com/fjarri-eth/pons/pull/47 0.5.1 (14-11-2022) @@ -127,7 +127,7 @@ Fixed - A bug in processing keyword arguments to contract calls. (PR_42_) -.. _PR_42: https://github.com/fjarri/pons/pull/42 +.. _PR_42: https://github.com/fjarri-eth/pons/pull/42 0.5.0 (14-09-2022) @@ -145,8 +145,8 @@ Fixed - Return type of classmethods of ``Amount`` and ``Address`` now provides correct information to ``mypy`` in dependent projects. (PR_37_) -.. _PR_37: https://github.com/fjarri/pons/pull/37 -.. _PR_40: https://github.com/fjarri/pons/pull/40 +.. _PR_37: https://github.com/fjarri-eth/pons/pull/37 +.. _PR_40: https://github.com/fjarri-eth/pons/pull/40 0.4.2 (05-06-2022) @@ -170,8 +170,8 @@ Fixed - Removed ``TxReceipt`` export (making an exception here and not counting it as a breaking change, since nobody would have any use for creating one manually). (PR_32_) -.. _PR_32: https://github.com/fjarri/pons/pull/32 -.. _PR_33: https://github.com/fjarri/pons/pull/33 +.. _PR_32: https://github.com/fjarri-eth/pons/pull/32 +.. _PR_33: https://github.com/fjarri-eth/pons/pull/33 0.4.1 (01-05-2022) @@ -185,9 +185,9 @@ Added - Support for gas overrides in ``transfer()``, ``transact()``, and ``deploy()``. (PR_30_) -.. _PR_27: https://github.com/fjarri/pons/pull/27 -.. _PR_29: https://github.com/fjarri/pons/pull/29 -.. _PR_30: https://github.com/fjarri/pons/pull/30 +.. _PR_27: https://github.com/fjarri-eth/pons/pull/27 +.. _PR_29: https://github.com/fjarri-eth/pons/pull/29 +.. _PR_30: https://github.com/fjarri-eth/pons/pull/30 0.4.0 (23-04-2022) @@ -214,8 +214,8 @@ Added - ``RemoteError`` and ``Unreachable`` exception types to report errors from client sessions in a standardized way. (PR_5_) -.. _PR_4: https://github.com/fjarri/pons/pull/4 -.. _PR_5: https://github.com/fjarri/pons/pull/5 +.. _PR_4: https://github.com/fjarri-eth/pons/pull/4 +.. _PR_5: https://github.com/fjarri-eth/pons/pull/5 0.3.0 (03-04-2022) @@ -236,9 +236,9 @@ Fixed - Replaced assertions with more informative exceptions. (PR_3_) -.. _PR_1: https://github.com/fjarri/pons/pull/1 -.. _PR_2: https://github.com/fjarri/pons/pull/2 -.. _PR_3: https://github.com/fjarri/pons/pull/3 +.. _PR_1: https://github.com/fjarri-eth/pons/pull/1 +.. _PR_2: https://github.com/fjarri-eth/pons/pull/2 +.. _PR_3: https://github.com/fjarri-eth/pons/pull/3 0.2.0 (19-03-2022) diff --git a/pdm.lock b/pdm.lock index 5f9a824..d272197 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "compiler", "docs", "lint", "local-provider", "tests"] strategy = ["cross_platform"] lock_version = "4.4.1" -content_hash = "sha256:57a998a92675579ce4a5ad91e6a7583de34487a1ec97d4904b29311994a4558d" +content_hash = "sha256:6ea4da48b4d0ab54eb58cc18dd73c9a061085f5ee0c6f98da1fc37ba4bd9ec8a" [[package]] name = "alabaster" @@ -19,7 +19,7 @@ files = [ [[package]] name = "alysis" -version = "0.4.0" +version = "0.5.0" requires_python = ">=3.10" summary = "Ethereum testerchain" dependencies = [ @@ -27,13 +27,14 @@ dependencies = [ "eth-keys>=0.5", "eth-typing>=4", "eth-utils>=3", - "py-evm==0.9.0b1", + "ethereum-rpc>=0.1", + "py-evm==0.10.1b1", "rlp>=4", "setuptools", ] files = [ - {file = "alysis-0.4.0-py3-none-any.whl", hash = "sha256:b282d5b0d7167041c10c7d9c9c3074e9142afdc4b5389dc51e7f0c194dda1dc4"}, - {file = "alysis-0.4.0.tar.gz", hash = "sha256:5112f6fb60e559c27bdfe32dc3ded3be9581ebeb355b50c72233967ad7a08eeb"}, + {file = "alysis-0.5.0-py3-none-any.whl", hash = "sha256:19f4e111c374844a9f72b6bda59025be931748113f21bf879b6e2bf784492b4a"}, + {file = "alysis-0.5.0.tar.gz", hash = "sha256:cfc664f590260e89d9f2ab9c81d65a3d3bb93fc50d98f2876fd34d696f1db6b7"}, ] [[package]] @@ -48,7 +49,7 @@ files = [ [[package]] name = "anyio" -version = "4.3.0" +version = "4.4.0" requires_python = ">=3.8" summary = "High level compatibility layer for multiple asynchronous event loop implementations" dependencies = [ @@ -58,8 +59,8 @@ dependencies = [ "typing-extensions>=4.1; python_version < \"3.11\"", ] files = [ - {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, - {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, + {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, + {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, ] [[package]] @@ -376,87 +377,87 @@ files = [ [[package]] name = "coverage" -version = "7.5.1" +version = "7.5.3" requires_python = ">=3.8" summary = "Code coverage measurement for Python" files = [ - {file = "coverage-7.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0884920835a033b78d1c73b6d3bbcda8161a900f38a488829a83982925f6c2e"}, - {file = "coverage-7.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:39afcd3d4339329c5f58de48a52f6e4e50f6578dd6099961cf22228feb25f38f"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7b0ceee8147444347da6a66be737c9d78f3353b0681715b668b72e79203e4a"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a9ca3f2fae0088c3c71d743d85404cec8df9be818a005ea065495bedc33da35"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd215c0c7d7aab005221608a3c2b46f58c0285a819565887ee0b718c052aa4e"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4bf0655ab60d754491004a5efd7f9cccefcc1081a74c9ef2da4735d6ee4a6223"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:61c4bf1ba021817de12b813338c9be9f0ad5b1e781b9b340a6d29fc13e7c1b5e"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:db66fc317a046556a96b453a58eced5024af4582a8dbdc0c23ca4dbc0d5b3146"}, - {file = "coverage-7.5.1-cp310-cp310-win32.whl", hash = "sha256:b016ea6b959d3b9556cb401c55a37547135a587db0115635a443b2ce8f1c7228"}, - {file = "coverage-7.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:df4e745a81c110e7446b1cc8131bf986157770fa405fe90e15e850aaf7619bc8"}, - {file = "coverage-7.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:796a79f63eca8814ca3317a1ea443645c9ff0d18b188de470ed7ccd45ae79428"}, - {file = "coverage-7.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fc84a37bfd98db31beae3c2748811a3fa72bf2007ff7902f68746d9757f3746"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6175d1a0559986c6ee3f7fccfc4a90ecd12ba0a383dcc2da30c2b9918d67d8a3"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fc81d5878cd6274ce971e0a3a18a8803c3fe25457165314271cf78e3aae3aa2"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556cf1a7cbc8028cb60e1ff0be806be2eded2daf8129b8811c63e2b9a6c43bca"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9981706d300c18d8b220995ad22627647be11a4276721c10911e0e9fa44c83e8"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d7fed867ee50edf1a0b4a11e8e5d0895150e572af1cd6d315d557758bfa9c057"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef48e2707fb320c8f139424a596f5b69955a85b178f15af261bab871873bb987"}, - {file = "coverage-7.5.1-cp311-cp311-win32.whl", hash = "sha256:9314d5678dcc665330df5b69c1e726a0e49b27df0461c08ca12674bcc19ef136"}, - {file = "coverage-7.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:5fa567e99765fe98f4e7d7394ce623e794d7cabb170f2ca2ac5a4174437e90dd"}, - {file = "coverage-7.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b6cf3764c030e5338e7f61f95bd21147963cf6aa16e09d2f74f1fa52013c1206"}, - {file = "coverage-7.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ec92012fefebee89a6b9c79bc39051a6cb3891d562b9270ab10ecfdadbc0c34"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16db7f26000a07efcf6aea00316f6ac57e7d9a96501e990a36f40c965ec7a95d"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beccf7b8a10b09c4ae543582c1319c6df47d78fd732f854ac68d518ee1fb97fa"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8748731ad392d736cc9ccac03c9845b13bb07d020a33423fa5b3a36521ac6e4e"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7352b9161b33fd0b643ccd1f21f3a3908daaddf414f1c6cb9d3a2fd618bf2572"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7a588d39e0925f6a2bff87154752481273cdb1736270642aeb3635cb9b4cad07"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:68f962d9b72ce69ea8621f57551b2fa9c70509af757ee3b8105d4f51b92b41a7"}, - {file = "coverage-7.5.1-cp312-cp312-win32.whl", hash = "sha256:f152cbf5b88aaeb836127d920dd0f5e7edff5a66f10c079157306c4343d86c19"}, - {file = "coverage-7.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:5a5740d1fb60ddf268a3811bcd353de34eb56dc24e8f52a7f05ee513b2d4f596"}, - {file = "coverage-7.5.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:6537e7c10cc47c595828b8a8be04c72144725c383c4702703ff4e42e44577312"}, - {file = "coverage-7.5.1.tar.gz", hash = "sha256:54de9ef3a9da981f7af93eafde4ede199e0846cd819eb27c88e2b712aae9708c"}, + {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"}, + {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"}, + {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"}, + {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"}, + {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"}, + {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"}, + {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"}, + {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"}, + {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"}, + {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"}, + {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"}, + {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"}, + {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"}, + {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"}, ] [[package]] name = "coverage" -version = "7.5.1" +version = "7.5.3" extras = ["toml"] requires_python = ">=3.8" summary = "Code coverage measurement for Python" dependencies = [ - "coverage==7.5.1", + "coverage==7.5.3", "tomli; python_full_version <= \"3.11.0a6\"", ] files = [ - {file = "coverage-7.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0884920835a033b78d1c73b6d3bbcda8161a900f38a488829a83982925f6c2e"}, - {file = "coverage-7.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:39afcd3d4339329c5f58de48a52f6e4e50f6578dd6099961cf22228feb25f38f"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7b0ceee8147444347da6a66be737c9d78f3353b0681715b668b72e79203e4a"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a9ca3f2fae0088c3c71d743d85404cec8df9be818a005ea065495bedc33da35"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd215c0c7d7aab005221608a3c2b46f58c0285a819565887ee0b718c052aa4e"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4bf0655ab60d754491004a5efd7f9cccefcc1081a74c9ef2da4735d6ee4a6223"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:61c4bf1ba021817de12b813338c9be9f0ad5b1e781b9b340a6d29fc13e7c1b5e"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:db66fc317a046556a96b453a58eced5024af4582a8dbdc0c23ca4dbc0d5b3146"}, - {file = "coverage-7.5.1-cp310-cp310-win32.whl", hash = "sha256:b016ea6b959d3b9556cb401c55a37547135a587db0115635a443b2ce8f1c7228"}, - {file = "coverage-7.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:df4e745a81c110e7446b1cc8131bf986157770fa405fe90e15e850aaf7619bc8"}, - {file = "coverage-7.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:796a79f63eca8814ca3317a1ea443645c9ff0d18b188de470ed7ccd45ae79428"}, - {file = "coverage-7.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fc84a37bfd98db31beae3c2748811a3fa72bf2007ff7902f68746d9757f3746"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6175d1a0559986c6ee3f7fccfc4a90ecd12ba0a383dcc2da30c2b9918d67d8a3"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fc81d5878cd6274ce971e0a3a18a8803c3fe25457165314271cf78e3aae3aa2"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556cf1a7cbc8028cb60e1ff0be806be2eded2daf8129b8811c63e2b9a6c43bca"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9981706d300c18d8b220995ad22627647be11a4276721c10911e0e9fa44c83e8"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d7fed867ee50edf1a0b4a11e8e5d0895150e572af1cd6d315d557758bfa9c057"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef48e2707fb320c8f139424a596f5b69955a85b178f15af261bab871873bb987"}, - {file = "coverage-7.5.1-cp311-cp311-win32.whl", hash = "sha256:9314d5678dcc665330df5b69c1e726a0e49b27df0461c08ca12674bcc19ef136"}, - {file = "coverage-7.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:5fa567e99765fe98f4e7d7394ce623e794d7cabb170f2ca2ac5a4174437e90dd"}, - {file = "coverage-7.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b6cf3764c030e5338e7f61f95bd21147963cf6aa16e09d2f74f1fa52013c1206"}, - {file = "coverage-7.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ec92012fefebee89a6b9c79bc39051a6cb3891d562b9270ab10ecfdadbc0c34"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16db7f26000a07efcf6aea00316f6ac57e7d9a96501e990a36f40c965ec7a95d"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beccf7b8a10b09c4ae543582c1319c6df47d78fd732f854ac68d518ee1fb97fa"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8748731ad392d736cc9ccac03c9845b13bb07d020a33423fa5b3a36521ac6e4e"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7352b9161b33fd0b643ccd1f21f3a3908daaddf414f1c6cb9d3a2fd618bf2572"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7a588d39e0925f6a2bff87154752481273cdb1736270642aeb3635cb9b4cad07"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:68f962d9b72ce69ea8621f57551b2fa9c70509af757ee3b8105d4f51b92b41a7"}, - {file = "coverage-7.5.1-cp312-cp312-win32.whl", hash = "sha256:f152cbf5b88aaeb836127d920dd0f5e7edff5a66f10c079157306c4343d86c19"}, - {file = "coverage-7.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:5a5740d1fb60ddf268a3811bcd353de34eb56dc24e8f52a7f05ee513b2d4f596"}, - {file = "coverage-7.5.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:6537e7c10cc47c595828b8a8be04c72144725c383c4702703ff4e42e44577312"}, - {file = "coverage-7.5.1.tar.gz", hash = "sha256:54de9ef3a9da981f7af93eafde4ede199e0846cd819eb27c88e2b712aae9708c"}, + {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"}, + {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"}, + {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"}, + {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"}, + {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"}, + {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"}, + {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"}, + {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"}, + {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"}, + {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"}, + {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"}, + {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"}, + {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"}, + {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"}, ] [[package]] @@ -689,6 +690,20 @@ files = [ {file = "eth_utils-4.1.1.tar.gz", hash = "sha256:71c8d10dec7494aeed20fa7a4d52ec2ce4a2e52fdce80aab4f5c3c19f3648b25"}, ] +[[package]] +name = "ethereum-rpc" +version = "0.1.0" +requires_python = ">=3.10" +summary = "Ethereum RPC types" +dependencies = [ + "compages>=0.3", + "pycryptodome>=3", +] +files = [ + {file = "ethereum-rpc-0.1.0.tar.gz", hash = "sha256:dcc97da63a0448b00404ab258bed421a6c55787877541dfd7e4d6d25e3368d15"}, + {file = "ethereum_rpc-0.1.0-py3-none-any.whl", hash = "sha256:23dcfa730fd719dffa290f9bfcbe0cdaa8575455f04c0a9dfc73d94e4e22452c"}, +] + [[package]] name = "exceptiongroup" version = "1.2.1" @@ -792,20 +807,22 @@ files = [ [[package]] name = "hypercorn" -version = "0.16.0" +version = "0.17.3" requires_python = ">=3.8" summary = "A ASGI Server based on Hyper libraries and inspired by Gunicorn" dependencies = [ + "exceptiongroup>=1.1.0; python_version < \"3.11\"", "h11", "h2>=3.1.0", "priority", "taskgroup; python_version < \"3.11\"", "tomli; python_version < \"3.11\"", + "typing-extensions; python_version < \"3.11\"", "wsproto>=0.14.0", ] files = [ - {file = "hypercorn-0.16.0-py3-none-any.whl", hash = "sha256:929e45c4acde3fbf7c58edf55336d30a009d2b4cb1f1eb96e6a515d61b663f58"}, - {file = "hypercorn-0.16.0.tar.gz", hash = "sha256:3b17d1dcf4992c1f262d9f9dd799c374125d0b9a8e40e1e2d11e2938b0adfe03"}, + {file = "hypercorn-0.17.3-py3-none-any.whl", hash = "sha256:059215dec34537f9d40a69258d323f56344805efb462959e727152b0aa504547"}, + {file = "hypercorn-0.17.3.tar.gz", hash = "sha256:1b37802ee3ac52d2d85270700d565787ab16cf19e1462ccfa9f089ca17574165"}, ] [[package]] @@ -1088,11 +1105,12 @@ files = [ [[package]] name = "py-evm" -version = "0.9.0b1" -requires_python = ">=3.8, <4" +version = "0.10.1b1" +requires_python = "<4,>=3.8" summary = "Python implementation of the Ethereum Virtual Machine" 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", @@ -1103,8 +1121,8 @@ dependencies = [ "trie>=2.0.0", ] files = [ - {file = "py-evm-0.9.0b1.tar.gz", hash = "sha256:59c1aa5c179d00067452a0b2347c9cc895c86b8b17595d2fa0cfd81f6346ad90"}, - {file = "py_evm-0.9.0b1-py3-none-any.whl", hash = "sha256:bc63c84df2cff6b194e71b1256ce5f7894ae6cd3113e0e12ddde477b245ce473"}, + {file = "py_evm-0.10.1b1-py3-none-any.whl", hash = "sha256:f0fc4a4b904917b40e6a06f87925017dc48ea6582e95f88d28be38f3566e2bae"}, + {file = "py_evm-0.10.1b1.tar.gz", hash = "sha256:aeb889514af12b6a8cb5091fe93008642eadf7c19999859dad3191eaf451647c"}, ] [[package]] @@ -1162,83 +1180,83 @@ files = [ [[package]] name = "pydantic" -version = "2.7.1" +version = "2.7.2" requires_python = ">=3.8" summary = "Data validation using Python type hints" dependencies = [ "annotated-types>=0.4.0", - "pydantic-core==2.18.2", + "pydantic-core==2.18.3", "typing-extensions>=4.6.1", ] files = [ - {file = "pydantic-2.7.1-py3-none-any.whl", hash = "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5"}, - {file = "pydantic-2.7.1.tar.gz", hash = "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"}, + {file = "pydantic-2.7.2-py3-none-any.whl", hash = "sha256:834ab954175f94e6e68258537dc49402c4a5e9d0409b9f1b86b7e934a8372de7"}, + {file = "pydantic-2.7.2.tar.gz", hash = "sha256:71b2945998f9c9b7919a45bde9a50397b289937d215ae141c1d0903ba7149fd7"}, ] [[package]] name = "pydantic-core" -version = "2.18.2" +version = "2.18.3" requires_python = ">=3.8" summary = "Core functionality for Pydantic validation and serialization" dependencies = [ "typing-extensions!=4.7.0,>=4.6.0", ] files = [ - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81"}, - {file = "pydantic_core-2.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af"}, - {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563"}, - {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38"}, - {file = "pydantic_core-2.18.2-cp310-none-win32.whl", hash = "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027"}, - {file = "pydantic_core-2.18.2-cp310-none-win_amd64.whl", hash = "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3"}, - {file = "pydantic_core-2.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6"}, - {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0"}, - {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664"}, - {file = "pydantic_core-2.18.2-cp311-none-win32.whl", hash = "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e"}, - {file = "pydantic_core-2.18.2-cp311-none-win_amd64.whl", hash = "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3"}, - {file = "pydantic_core-2.18.2-cp311-none-win_arm64.whl", hash = "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"}, - {file = "pydantic_core-2.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72"}, - {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241"}, - {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3"}, - {file = "pydantic_core-2.18.2-cp312-none-win32.whl", hash = "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038"}, - {file = "pydantic_core-2.18.2-cp312-none-win_amd64.whl", hash = "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438"}, - {file = "pydantic_core-2.18.2-cp312-none-win_arm64.whl", hash = "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b"}, - {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae"}, - {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374"}, - {file = "pydantic_core-2.18.2.tar.gz", hash = "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e"}, + {file = "pydantic_core-2.18.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:744697428fcdec6be5670460b578161d1ffe34743a5c15656be7ea82b008197c"}, + {file = "pydantic_core-2.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37b40c05ced1ba4218b14986fe6f283d22e1ae2ff4c8e28881a70fb81fbfcda7"}, + {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:544a9a75622357076efb6b311983ff190fbfb3c12fc3a853122b34d3d358126c"}, + {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e2e253af04ceaebde8eb201eb3f3e3e7e390f2d275a88300d6a1959d710539e2"}, + {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:855ec66589c68aa367d989da5c4755bb74ee92ccad4fdb6af942c3612c067e34"}, + {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d3e42bb54e7e9d72c13ce112e02eb1b3b55681ee948d748842171201a03a98a"}, + {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6ac9ffccc9d2e69d9fba841441d4259cb668ac180e51b30d3632cd7abca2b9b"}, + {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c56eca1686539fa0c9bda992e7bd6a37583f20083c37590413381acfc5f192d6"}, + {file = "pydantic_core-2.18.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:17954d784bf8abfc0ec2a633108207ebc4fa2df1a0e4c0c3ccbaa9bb01d2c426"}, + {file = "pydantic_core-2.18.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:98ed737567d8f2ecd54f7c8d4f8572ca7c7921ede93a2e52939416170d357812"}, + {file = "pydantic_core-2.18.3-cp310-none-win32.whl", hash = "sha256:9f9e04afebd3ed8c15d67a564ed0a34b54e52136c6d40d14c5547b238390e779"}, + {file = "pydantic_core-2.18.3-cp310-none-win_amd64.whl", hash = "sha256:45e4ffbae34f7ae30d0047697e724e534a7ec0a82ef9994b7913a412c21462a0"}, + {file = "pydantic_core-2.18.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b9ebe8231726c49518b16b237b9fe0d7d361dd221302af511a83d4ada01183ab"}, + {file = "pydantic_core-2.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b8e20e15d18bf7dbb453be78a2d858f946f5cdf06c5072453dace00ab652e2b2"}, + {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0d9ff283cd3459fa0bf9b0256a2b6f01ac1ff9ffb034e24457b9035f75587cb"}, + {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f7ef5f0ebb77ba24c9970da18b771711edc5feaf00c10b18461e0f5f5949231"}, + {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73038d66614d2e5cde30435b5afdced2b473b4c77d4ca3a8624dd3e41a9c19be"}, + {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6afd5c867a74c4d314c557b5ea9520183fadfbd1df4c2d6e09fd0d990ce412cd"}, + {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd7df92f28d351bb9f12470f4c533cf03d1b52ec5a6e5c58c65b183055a60106"}, + {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:80aea0ffeb1049336043d07799eace1c9602519fb3192916ff525b0287b2b1e4"}, + {file = "pydantic_core-2.18.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaee40f25bba38132e655ffa3d1998a6d576ba7cf81deff8bfa189fb43fd2bbe"}, + {file = "pydantic_core-2.18.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9128089da8f4fe73f7a91973895ebf2502539d627891a14034e45fb9e707e26d"}, + {file = "pydantic_core-2.18.3-cp311-none-win32.whl", hash = "sha256:fec02527e1e03257aa25b1a4dcbe697b40a22f1229f5d026503e8b7ff6d2eda7"}, + {file = "pydantic_core-2.18.3-cp311-none-win_amd64.whl", hash = "sha256:58ff8631dbab6c7c982e6425da8347108449321f61fe427c52ddfadd66642af7"}, + {file = "pydantic_core-2.18.3-cp311-none-win_arm64.whl", hash = "sha256:3fc1c7f67f34c6c2ef9c213e0f2a351797cda98249d9ca56a70ce4ebcaba45f4"}, + {file = "pydantic_core-2.18.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f0928cde2ae416a2d1ebe6dee324709c6f73e93494d8c7aea92df99aab1fc40f"}, + {file = "pydantic_core-2.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bee9bb305a562f8b9271855afb6ce00223f545de3d68560b3c1649c7c5295e9"}, + {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e862823be114387257dacbfa7d78547165a85d7add33b446ca4f4fae92c7ff5c"}, + {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6a36f78674cbddc165abab0df961b5f96b14461d05feec5e1f78da58808b97e7"}, + {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba905d184f62e7ddbb7a5a751d8a5c805463511c7b08d1aca4a3e8c11f2e5048"}, + {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fdd362f6a586e681ff86550b2379e532fee63c52def1c666887956748eaa326"}, + {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24b214b7ee3bd3b865e963dbed0f8bc5375f49449d70e8d407b567af3222aae4"}, + {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:691018785779766127f531674fa82bb368df5b36b461622b12e176c18e119022"}, + {file = "pydantic_core-2.18.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:60e4c625e6f7155d7d0dcac151edf5858102bc61bf959d04469ca6ee4e8381bd"}, + {file = "pydantic_core-2.18.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4e651e47d981c1b701dcc74ab8fec5a60a5b004650416b4abbef13db23bc7be"}, + {file = "pydantic_core-2.18.3-cp312-none-win32.whl", hash = "sha256:ffecbb5edb7f5ffae13599aec33b735e9e4c7676ca1633c60f2c606beb17efc5"}, + {file = "pydantic_core-2.18.3-cp312-none-win_amd64.whl", hash = "sha256:2c8333f6e934733483c7eddffdb094c143b9463d2af7e6bd85ebcb2d4a1b82c6"}, + {file = "pydantic_core-2.18.3-cp312-none-win_arm64.whl", hash = "sha256:7a20dded653e516a4655f4c98e97ccafb13753987434fe7cf044aa25f5b7d417"}, + {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:77319771a026f7c7d29c6ebc623de889e9563b7087911b46fd06c044a12aa5e9"}, + {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:df11fa992e9f576473038510d66dd305bcd51d7dd508c163a8c8fe148454e059"}, + {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d531076bdfb65af593326ffd567e6ab3da145020dafb9187a1d131064a55f97c"}, + {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d33ce258e4e6e6038f2b9e8b8a631d17d017567db43483314993b3ca345dcbbb"}, + {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1f9cd7f5635b719939019be9bda47ecb56e165e51dd26c9a217a433e3d0d59a9"}, + {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cd4a032bb65cc132cae1fe3e52877daecc2097965cd3914e44fbd12b00dae7c5"}, + {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f2718430098bcdf60402136c845e4126a189959d103900ebabb6774a5d9fdb"}, + {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c0037a92cf0c580ed14e10953cdd26528e8796307bb8bb312dc65f71547df04d"}, + {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b95a0972fac2b1ff3c94629fc9081b16371dad870959f1408cc33b2f78ad347a"}, + {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a62e437d687cc148381bdd5f51e3e81f5b20a735c55f690c5be94e05da2b0d5c"}, + {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b367a73a414bbb08507da102dc2cde0fa7afe57d09b3240ce82a16d608a7679c"}, + {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ecce4b2360aa3f008da3327d652e74a0e743908eac306198b47e1c58b03dd2b"}, + {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd4435b8d83f0c9561a2a9585b1de78f1abb17cb0cef5f39bf6a4b47d19bafe3"}, + {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:616221a6d473c5b9aa83fa8982745441f6a4a62a66436be9445c65f241b86c94"}, + {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:7e6382ce89a92bc1d0c0c5edd51e931432202b9080dc921d8d003e616402efd1"}, + {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff58f379345603d940e461eae474b6bbb6dab66ed9a851ecd3cb3709bf4dcf6a"}, + {file = "pydantic_core-2.18.3.tar.gz", hash = "sha256:432e999088d85c8f36b9a3f769a8e2b57aabd817bbb729a90d1fe7f18f6f1f39"}, ] [[package]] @@ -1384,27 +1402,27 @@ files = [ [[package]] name = "ruff" -version = "0.4.5" +version = "0.4.6" requires_python = ">=3.7" summary = "An extremely fast Python linter and code formatter, written in Rust." files = [ - {file = "ruff-0.4.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8f58e615dec58b1a6b291769b559e12fdffb53cc4187160a2fc83250eaf54e96"}, - {file = "ruff-0.4.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:84dd157474e16e3a82745d2afa1016c17d27cb5d52b12e3d45d418bcc6d49264"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25f483ad9d50b00e7fd577f6d0305aa18494c6af139bce7319c68a17180087f4"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:63fde3bf6f3ad4e990357af1d30e8ba2730860a954ea9282c95fc0846f5f64af"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e3ba4620dee27f76bbcad97067766026c918ba0f2d035c2fc25cbdd04d9c97"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:441dab55c568e38d02bbda68a926a3d0b54f5510095c9de7f95e47a39e0168aa"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1169e47e9c4136c997f08f9857ae889d614c5035d87d38fda9b44b4338909cdf"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:755ac9ac2598a941512fc36a9070a13c88d72ff874a9781493eb237ab02d75df"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4b02a65985be2b34b170025a8b92449088ce61e33e69956ce4d316c0fe7cce0"}, - {file = "ruff-0.4.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:75a426506a183d9201e7e5664de3f6b414ad3850d7625764106f7b6d0486f0a1"}, - {file = "ruff-0.4.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6e1b139b45e2911419044237d90b60e472f57285950e1492c757dfc88259bb06"}, - {file = "ruff-0.4.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6f29a8221d2e3d85ff0c7b4371c0e37b39c87732c969b4d90f3dad2e721c5b1"}, - {file = "ruff-0.4.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d6ef817124d72b54cc923f3444828ba24fa45c3164bc9e8f1813db2f3d3a8a11"}, - {file = "ruff-0.4.5-py3-none-win32.whl", hash = "sha256:aed8166c18b1a169a5d3ec28a49b43340949e400665555b51ee06f22813ef062"}, - {file = "ruff-0.4.5-py3-none-win_amd64.whl", hash = "sha256:b0b03c619d2b4350b4a27e34fd2ac64d0dabe1afbf43de57d0f9d8a05ecffa45"}, - {file = "ruff-0.4.5-py3-none-win_arm64.whl", hash = "sha256:9d15de3425f53161b3f5a5658d4522e4eee5ea002bf2ac7aa380743dd9ad5fba"}, - {file = "ruff-0.4.5.tar.gz", hash = "sha256:286eabd47e7d4d521d199cab84deca135557e6d1e0f0d01c29e757c3cb151b54"}, + {file = "ruff-0.4.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ef995583a038cd4a7edf1422c9e19118e2511b8ba0b015861b4abd26ec5367c5"}, + {file = "ruff-0.4.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:602ebd7ad909eab6e7da65d3c091547781bb06f5f826974a53dbe563d357e53c"}, + {file = "ruff-0.4.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f9ced5cbb7510fd7525448eeb204e0a22cabb6e99a3cb160272262817d49786"}, + {file = "ruff-0.4.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04a80acfc862e0e1630c8b738e70dcca03f350bad9e106968a8108379e12b31f"}, + {file = "ruff-0.4.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be47700ecb004dfa3fd4dcdddf7322d4e632de3c06cd05329d69c45c0280e618"}, + {file = "ruff-0.4.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1ff930d6e05f444090a0139e4e13e1e2e1f02bd51bb4547734823c760c621e79"}, + {file = "ruff-0.4.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f13410aabd3b5776f9c5699f42b37a3a348d65498c4310589bc6e5c548dc8a2f"}, + {file = "ruff-0.4.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0cf5cc02d3ae52dfb0c8a946eb7a1d6ffe4d91846ffc8ce388baa8f627e3bd50"}, + {file = "ruff-0.4.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea3424793c29906407e3cf417f28fc33f689dacbbadfb52b7e9a809dd535dcef"}, + {file = "ruff-0.4.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1fa8561489fadf483ffbb091ea94b9c39a00ed63efacd426aae2f197a45e67fc"}, + {file = "ruff-0.4.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4d5b914818d8047270308fe3e85d9d7f4a31ec86c6475c9f418fbd1624d198e0"}, + {file = "ruff-0.4.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4f02284335c766678778475e7698b7ab83abaf2f9ff0554a07b6f28df3b5c259"}, + {file = "ruff-0.4.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3a6a0a4f4b5f54fff7c860010ab3dd81425445e37d35701a965c0248819dde7a"}, + {file = "ruff-0.4.6-py3-none-win32.whl", hash = "sha256:9018bf59b3aa8ad4fba2b1dc0299a6e4e60a4c3bc62bbeaea222679865453062"}, + {file = "ruff-0.4.6-py3-none-win_amd64.whl", hash = "sha256:a769ae07ac74ff1a019d6bd529426427c3e30d75bdf1e08bb3d46ac8f417326a"}, + {file = "ruff-0.4.6-py3-none-win_arm64.whl", hash = "sha256:735a16407a1a8f58e4c5b913ad6102722e80b562dd17acb88887685ff6f20cf6"}, + {file = "ruff-0.4.6.tar.gz", hash = "sha256:a797a87da50603f71e6d0765282098245aca6e3b94b7c17473115167d8dfb0b7"}, ] [[package]] @@ -1717,10 +1735,10 @@ files = [ [[package]] name = "zipp" -version = "3.18.2" +version = "3.19.0" requires_python = ">=3.8" summary = "Backport of pathlib-compatible object wrapper for zip files" files = [ - {file = "zipp-3.18.2-py3-none-any.whl", hash = "sha256:dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e"}, - {file = "zipp-3.18.2.tar.gz", hash = "sha256:6278d9ddbcfb1f1089a88fde84481528b07b0e10474e09dcfe53dad4069fa059"}, + {file = "zipp-3.19.0-py3-none-any.whl", hash = "sha256:96dc6ad62f1441bcaccef23b274ec471518daf4fbbc580341204936a5a3dddec"}, + {file = "zipp-3.19.0.tar.gz", hash = "sha256:952df858fb3164426c976d9338d3961e8e8b3758e2e059e0f754b8c4262625ee"}, ] diff --git a/pons/__init__.py b/pons/__init__.py index 95f5cf3..7ee6a7a 100644 --- a/pons/__init__.py +++ b/pons/__init__.py @@ -38,7 +38,6 @@ Mutability, Receive, ) -from ._entities import Address, Amount, Block, BlockHash, RPCError, RPCErrorCode, TxHash from ._fallback_provider import ( CycleFallback, FallbackProvider, @@ -49,16 +48,11 @@ from ._http_provider_server import HTTPProviderServer from ._local_provider import LocalProvider, SnapshotID from ._provider import HTTPProvider, ProtocolError, Provider, Unreachable -from ._serialization import JSON from ._signer import AccountSigner, Signer __all__ = [ "ABIDecodingError", "AccountSigner", - "Address", - "Amount", - "Block", - "BlockHash", "BoundConstructor", "BoundConstructorCall", "BoundEvent", @@ -78,16 +72,15 @@ "DeployedContract", "Either", "Error", + "EVMVersion", "LocalProvider", "Event", "EventFilter", - "EVMVersion", "Fallback", "FallbackProvider", "FallbackStrategy", "FallbackStrategyFactory", "HTTPProvider", - "JSON", "Method", "MethodCall", "MultiMethod", @@ -98,13 +91,10 @@ "Provider", "Receive", "RemoteError", - "RPCError", - "RPCErrorCode", "HTTPProviderServer", "Signer", "SnapshotID", "TransactionFailed", - "TxHash", "Unreachable", "abi", "compile_contract_file", diff --git a/pons/_abi_types.py b/pons/_abi_types.py index 204c5a9..bf45882 100644 --- a/pons/_abi_types.py +++ b/pons/_abi_types.py @@ -10,9 +10,7 @@ import eth_abi from eth_abi.exceptions import DecodingError -from eth_utils import keccak - -from ._entities import Address +from ethereum_rpc import Address, keccak # Maximum bits in an `int` or `uint` type in Solidity. MAX_INTEGER_BITS = 256 diff --git a/pons/_client.py b/pons/_client.py index 7fdbbde..3a9bea6 100644 --- a/pons/_client.py +++ b/pons/_client.py @@ -1,53 +1,70 @@ from collections.abc import AsyncIterator, Iterable, Iterator, Sequence from contextlib import asynccontextmanager, contextmanager +from dataclasses import dataclass from enum import Enum from typing import Any, ParamSpec, TypeVar, cast import anyio - -from ._contract import ( - BoundConstructorCall, - BoundEvent, - BoundEventFilter, - BoundMethodCall, - DeployedContract, -) -from ._contract_abi import ( - LEGACY_ERROR, - PANIC_ERROR, - ContractABI, - Error, - EventFilter, - UnknownError, -) -from ._entities import ( +from compages import StructuringError +from ethereum_rpc import ( + JSON, Address, Amount, Block, - BlockFilter, - BlockFilterId, BlockHash, BlockInfo, + BlockLabel, EstimateGasParams, EthCallParams, FilterParams, LogEntry, - LogFilter, - LogFilterId, - PendingTransactionFilter, - PendingTransactionFilterId, RPCError, RPCErrorCode, TxHash, TxInfo, TxReceipt, Type2Transaction, + structure, + unstructure, +) + +from ._contract import ( + BoundConstructorCall, + BoundEvent, + BoundEventFilter, + BoundMethodCall, + DeployedContract, +) +from ._contract_abi import ( + LEGACY_ERROR, + PANIC_ERROR, + ContractABI, + Error, + EventFilter, + UnknownError, ) from ._provider import InvalidResponse, Provider, ProviderSession -from ._serialization import JSON, StructuringError, structure, unstructure from ._signer import Signer +@dataclass +class BlockFilter: + id_: int + provider_path: tuple[int, ...] + + +@dataclass +class PendingTransactionFilter: + id_: int + provider_path: tuple[int, ...] + + +@dataclass +class LogFilter: + id_: int + provider_path: tuple[int, ...] + + class Client: """An Ethereum RPC client.""" @@ -90,8 +107,8 @@ class ProviderError(RemoteError): raw_code: int """The error code returned by the server.""" - code: RPCErrorCode - """The parsed error code.""" + code: None | RPCErrorCode + """The parsed error code (if known).""" message: str """The error message.""" @@ -101,10 +118,11 @@ class ProviderError(RemoteError): @classmethod def from_rpc_error(cls, exc: RPCError) -> "ProviderError": - parsed_code = RPCErrorCode.from_int(exc.code) - return cls(exc.code, parsed_code, exc.message, exc.data) + return cls(exc.code, exc.parsed_code, exc.message, exc.data) - def __init__(self, raw_code: int, code: RPCErrorCode, message: str, data: None | bytes = None): + def __init__( + self, raw_code: int, code: None | RPCErrorCode, message: str, data: None | bytes = None + ): super().__init__(raw_code, code, message, data) self.raw_code = raw_code self.code = code @@ -113,7 +131,7 @@ def __init__(self, raw_code: int, code: RPCErrorCode, message: str, data: None | def __str__(self) -> str: # Substitute the known code if any, or report the raw integer value otherwise - code = self.raw_code if self.code == RPCErrorCode.UNKNOWN_REASON else self.code.name + code = self.code or self.raw_code return f"Provider error ({code}): {self.message}" + ( f" (data: {self.data.hex()})" if self.data else "" ) @@ -302,7 +320,7 @@ async def eth_chain_id(self) -> int: self._chain_id = await rpc_call(self._provider_session, "eth_chainId", int) return self._chain_id - async def eth_get_balance(self, address: Address, block: int | Block = Block.LATEST) -> Amount: + async def eth_get_balance(self, address: Address, block: Block = BlockLabel.LATEST) -> Amount: """Calls the ``eth_getBalance`` RPC method.""" return await rpc_call(self._provider_session, "eth_getBalance", Amount, address, block) @@ -335,7 +353,7 @@ async def eth_get_transaction_receipt(self, tx_hash: TxHash) -> None | TxReceipt ) async def eth_get_transaction_count( - self, address: Address, block: int | Block = Block.LATEST + self, address: Address, block: Block = BlockLabel.LATEST ) -> int: """Calls the ``eth_getTransactionCount`` RPC method.""" return await rpc_call( @@ -346,12 +364,12 @@ async def eth_get_transaction_count( block, ) - async def eth_get_code(self, address: Address, block: int | Block = Block.LATEST) -> bytes: + async def eth_get_code(self, address: Address, block: Block = BlockLabel.LATEST) -> bytes: """Calls the ``eth_getCode`` RPC method.""" return await rpc_call(self._provider_session, "eth_getCode", bytes, address, block) async def eth_get_storage_at( - self, address: Address, position: int, block: int | Block = Block.LATEST + self, address: Address, position: int, block: Block = BlockLabel.LATEST ) -> bytes: """Calls the ``eth_getCode`` RPC method.""" return await rpc_call( @@ -376,7 +394,7 @@ async def wait_for_transaction_receipt( async def eth_call( self, call: BoundMethodCall, - block: int | Block = Block.LATEST, + block: Block = BlockLabel.LATEST, sender_address: None | Address = None, ) -> Any: """ @@ -401,7 +419,7 @@ async def _eth_send_raw_transaction(self, tx_bytes: bytes) -> TxHash: """Sends a signed and serialized transaction.""" return await rpc_call(self._provider_session, "eth_sendRawTransaction", TxHash, tx_bytes) - async def _estimate_gas(self, params: EstimateGasParams, block: int | Block) -> int: + async def _estimate_gas(self, params: EstimateGasParams, block: Block) -> int: return await rpc_call(self._provider_session, "eth_estimateGas", int, params, block) async def estimate_deploy( @@ -409,7 +427,7 @@ async def estimate_deploy( sender_address: Address, call: BoundConstructorCall, amount: None | Amount = None, - block: int | Block = Block.LATEST, + block: Block = BlockLabel.LATEST, ) -> int: """ Estimates the amount of gas required to deploy the contract with the given args. @@ -433,7 +451,7 @@ async def estimate_transfer( source_address: Address, destination_address: Address, amount: Amount, - block: int | Block = Block.LATEST, + block: Block = BlockLabel.LATEST, ) -> int: """ Estimates the amount of gas required to transfer ``amount``. @@ -449,7 +467,7 @@ async def estimate_transact( sender_address: Address, call: BoundMethodCall, amount: None | Amount = None, - block: int | Block = Block.LATEST, + block: Block = BlockLabel.LATEST, ) -> int: """ Estimates the amount of gas required to transact with a contract. @@ -498,7 +516,7 @@ async def eth_get_block_by_hash( ) async def eth_get_block_by_number( - self, block: int | Block = Block.LATEST, *, with_transactions: bool = False + self, block: Block = BlockLabel.LATEST, *, with_transactions: bool = False ) -> None | BlockInfo: """Calls the ``eth_getBlockByNumber`` RPC method.""" # Need an explicit cast, mypy doesn't work with union types correctly. @@ -532,7 +550,7 @@ async def broadcast_transfer( # TODO (#19): implement gas strategies max_gas_price = await self.eth_gas_price() max_tip = min(Amount.gwei(1), max_gas_price) - nonce = await self.eth_get_transaction_count(signer.address, Block.PENDING) + nonce = await self.eth_get_transaction_count(signer.address, BlockLabel.PENDING) tx = cast( dict[str, JSON], unstructure( @@ -602,7 +620,7 @@ async def deploy( # TODO (#19): implement gas strategies max_gas_price = await self.eth_gas_price() max_tip = min(Amount.gwei(1), max_gas_price) - nonce = await self.eth_get_transaction_count(signer.address, Block.PENDING) + nonce = await self.eth_get_transaction_count(signer.address, BlockLabel.PENDING) tx = cast( dict[str, JSON], unstructure( @@ -655,12 +673,12 @@ async def broadcast_transact( chain_id = await self.eth_chain_id() if gas is None: gas = await self.estimate_transact( - signer.address, call, amount=amount, block=Block.PENDING + signer.address, call, amount=amount, block=BlockLabel.PENDING ) # TODO (#19): implement gas strategies max_gas_price = await self.eth_gas_price() max_tip = min(Amount.gwei(1), max_gas_price) - nonce = await self.eth_get_transaction_count(signer.address, Block.PENDING) + nonce = await self.eth_get_transaction_count(signer.address, BlockLabel.PENDING) tx = cast( dict[str, JSON], unstructure( @@ -737,8 +755,8 @@ async def eth_get_logs( self, source: None | Address | Iterable[Address] = None, event_filter: None | EventFilter = None, - from_block: int | Block = Block.LATEST, - to_block: int | Block = Block.LATEST, + from_block: Block = BlockLabel.LATEST, + to_block: Block = BlockLabel.LATEST, ) -> tuple[LogEntry, ...]: """Calls the ``eth_getLogs`` RPC method.""" if isinstance(source, Iterable): @@ -754,14 +772,14 @@ async def eth_get_logs( async def eth_new_block_filter(self) -> BlockFilter: """Calls the ``eth_newBlockFilter`` RPC method.""" result, provider_path = await rpc_call_pin( - self._provider_session, "eth_newBlockFilter", BlockFilterId + self._provider_session, "eth_newBlockFilter", int ) return BlockFilter(id_=result, provider_path=provider_path) async def eth_new_pending_transaction_filter(self) -> PendingTransactionFilter: """Calls the ``eth_newPendingTransactionFilter`` RPC method.""" result, provider_path = await rpc_call_pin( - self._provider_session, "eth_newPendingTransactionFilter", PendingTransactionFilterId + self._provider_session, "eth_newPendingTransactionFilter", int ) return PendingTransactionFilter(id_=result, provider_path=provider_path) @@ -769,8 +787,8 @@ async def eth_new_filter( self, source: None | Address | Iterable[Address] = None, event_filter: None | EventFilter = None, - from_block: int | Block = Block.LATEST, - to_block: int | Block = Block.LATEST, + from_block: Block = BlockLabel.LATEST, + to_block: Block = BlockLabel.LATEST, ) -> LogFilter: """Calls the ``eth_newFilter`` RPC method.""" if isinstance(source, Iterable): @@ -782,7 +800,7 @@ async def eth_new_filter( topics=event_filter.topics if event_filter is not None else None, ) result, provider_path = await rpc_call_pin( - self._provider_session, "eth_newFilter", LogFilterId, params + self._provider_session, "eth_newFilter", int, params ) return LogFilter(id_=result, provider_path=provider_path) @@ -854,8 +872,8 @@ async def iter_events( self, event_filter: BoundEventFilter, poll_interval: int = 1, - from_block: int | Block = Block.LATEST, - to_block: int | Block = Block.LATEST, + from_block: Block = BlockLabel.LATEST, + to_block: Block = BlockLabel.LATEST, ) -> AsyncIterator[dict[str, Any]]: """ Yields decoded log entries produced by the filter. diff --git a/pons/_compiler.py b/pons/_compiler.py index 728e42a..7190f3a 100644 --- a/pons/_compiler.py +++ b/pons/_compiler.py @@ -14,16 +14,37 @@ class EVMVersion(Enum): """ HOMESTEAD = "homestead" + """Homestead fork, Mar 14, 2016.""" + TANGERINE_WHISTLE = "tangerineWhistle" + """Tangerine Whistle fork, Oct 18, 2016.""" + SPURIOUS_DRAGON = "spuriousDragon" + """Spurious Dragon fork, Nov 22, 2016.""" + BYZANTIUM = "byzantium" + """Byzantium fork, Oct 16, 2017.""" + CONSTANTINOPLE = "constantinople" - PETERSBURG = "petersburg" + """Constantinople fork, Feb 28, 2019.""" + ISTANBUL = "istanbul" + """Istanbul fork, Dec 8, 2019.""" + BERLIN = "berlin" + """Berlin fork, Apr 15, 2021.""" + LONDON = "london" + """London fork, Aug 5, 2021.""" + PARIS = "paris" + """Paris fork, Sep 15, 2022.""" + SHANGHAI = "shanghai" + """Shanghai fork, Apr 12, 2023.""" + + CANCUN = "cancun" + """Cancun fork, Mar 13, 2024.""" def compile_contract_file( diff --git a/pons/_contract.py b/pons/_contract.py index 3db5d15..047aa0f 100644 --- a/pons/_contract.py +++ b/pons/_contract.py @@ -1,5 +1,7 @@ from typing import Any +from ethereum_rpc import Address, LogEntry, LogTopic + from ._contract_abi import ( ContractABI, Error, @@ -9,7 +11,6 @@ Methods, MultiMethod, ) -from ._entities import Address, LogEntry, LogTopic from ._provider import JSON diff --git a/pons/_contract_abi.py b/pons/_contract_abi.py index a6ef7de..e78c37b 100644 --- a/pons/_contract_abi.py +++ b/pons/_contract_abi.py @@ -8,9 +8,10 @@ from keyword import iskeyword from typing import Any, Generic, TypeVar +from ethereum_rpc import LogEntry, LogTopic, keccak + from . import abi -from ._abi_types import Type, decode_args, dispatch_type, dispatch_types, encode_args, keccak -from ._entities import LogEntry, LogTopic +from ._abi_types import Type, decode_args, dispatch_type, dispatch_types, encode_args from ._provider import JSON # Anonymous events can have at most 4 indexed fields diff --git a/pons/_entities.py b/pons/_entities.py deleted file mode 100644 index 5eed47e..0000000 --- a/pons/_entities.py +++ /dev/null @@ -1,548 +0,0 @@ -from abc import ABC, abstractmethod -from dataclasses import dataclass -from enum import Enum -from functools import cached_property -from typing import Any, NewType, TypeVar, cast - -from eth_utils import to_canonical_address, to_checksum_address - -TypedDataLike = TypeVar("TypedDataLike", bound="TypedData") - - -TypedQuantityLike = TypeVar("TypedQuantityLike", bound="TypedQuantity") - - -class TypedData(ABC): - def __init__(self, value: bytes): - self._value = value - if not isinstance(value, bytes): - raise TypeError( - f"{self.__class__.__name__} must be a bytestring, got {type(value).__name__}" - ) - if len(value) != self._length(): - raise ValueError( - f"{self.__class__.__name__} must be {self._length()} bytes long, got {len(value)}" - ) - - @abstractmethod - def _length(self) -> int: - """Returns the length of this type's values representation in bytes.""" - - def __bytes__(self) -> bytes: - return self._value - - def __hash__(self) -> int: - return hash(self._value) - - def _check_type(self: TypedDataLike, other: Any) -> TypedDataLike: - if type(self) != type(other): - raise TypeError(f"Incompatible types: {type(self).__name__} and {type(other).__name__}") - return cast(TypedDataLike, other) - - def __eq__(self, other: object) -> bool: - return self._value == self._check_type(other)._value - - def __repr__(self) -> str: - return f'{self.__class__.__name__}(bytes.fromhex("{self._value.hex()}"))' - - -class TypedQuantity: - def __init__(self, value: int): - if not isinstance(value, int): - raise TypeError( - f"{self.__class__.__name__} must be an integer, got {type(value).__name__}" - ) - if value < 0: - raise ValueError(f"{self.__class__.__name__} must be non-negative, got {value}") - self._value = value - - def __hash__(self) -> int: - return hash(self._value) - - def __int__(self) -> int: - return self._value - - def _check_type(self: TypedQuantityLike, other: Any) -> TypedQuantityLike: - if type(self) != type(other): - raise TypeError(f"Incompatible types: {type(self).__name__} and {type(other).__name__}") - return cast(TypedQuantityLike, other) - - def __eq__(self, other: object) -> bool: - return self._value == self._check_type(other)._value - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self._value})" - - -# This is force-documented as :py:class in ``api.rst`` -# because Sphinx cannot resolve typevars correctly. -# See https://github.com/sphinx-doc/sphinx/issues/9705 -CustomAmount = TypeVar("CustomAmount", bound="Amount") -"""A subclass of :py:class:`Amount`.""" - - -class Amount(TypedQuantity): - """ - Represents a sum in the chain's native currency. - - Can be subclassed to represent specific currencies of different networks (ETH, MATIC etc). - Arithmetic and comparison methods perform strict type checking, - so different currency objects cannot be compared or added to each other. - """ - - @classmethod - def wei(cls: type[CustomAmount], value: int) -> CustomAmount: - """Creates a sum from the amount in wei (``10^(-18)`` of the main unit).""" - return cls(value) - - @classmethod - def gwei(cls: type[CustomAmount], value: float) -> CustomAmount: - """Creates a sum from the amount in gwei (``10^(-9)`` of the main unit).""" - return cls(int(10**9 * value)) - - @classmethod - def ether(cls: type[CustomAmount], value: float) -> CustomAmount: - """Creates a sum from the amount in the main currency unit.""" - return cls(int(10**18 * value)) - - def as_wei(self) -> int: - """Returns the amount in wei.""" - return self._value - - def as_gwei(self) -> float: - """Returns the amount in gwei.""" - return self._value / 10**9 - - def as_ether(self) -> float: - """Returns the amount in the main currency unit.""" - return self._value / 10**18 - - def __add__(self: CustomAmount, other: Any) -> CustomAmount: - return self.wei(self._value + self._check_type(other)._value) - - def __sub__(self: CustomAmount, other: Any) -> CustomAmount: - return self.wei(self._value - self._check_type(other)._value) - - def __mul__(self: CustomAmount, other: int) -> CustomAmount: - if not isinstance(other, int): - raise TypeError(f"Expected an integer, got {type(other).__name__}") - return self.wei(self._value * other) - - def __floordiv__(self: CustomAmount, other: int) -> CustomAmount: - if not isinstance(other, int): - raise TypeError(f"Expected an integer, got {type(other).__name__}") - return self.wei(self._value // other) - - def __gt__(self, other: Any) -> bool: - return self._value > self._check_type(other)._value - - def __ge__(self, other: Any) -> bool: - return self._value >= self._check_type(other)._value - - def __lt__(self, other: Any) -> bool: - return self._value < self._check_type(other)._value - - def __le__(self, other: Any) -> bool: - return self._value <= self._check_type(other)._value - - -# This is force-documented as :py:class in ``api.rst`` -# because Sphinx cannot resolve typevars correctly. -# See https://github.com/sphinx-doc/sphinx/issues/9705 -CustomAddress = TypeVar("CustomAddress", bound="Address") -"""A subclass of :py:class:`Address`.""" - - -class Address(TypedData): - """Represents an Ethereum address.""" - - def _length(self) -> int: - return 20 - - @classmethod - def from_hex(cls: type[CustomAddress], address_str: str) -> CustomAddress: - """ - Creates the address from a hex representation - (with or without the ``0x`` prefix, checksummed or not). - """ - return cls(to_canonical_address(address_str)) - - @cached_property - def checksum(self) -> str: - """Retunrs the checksummed hex representation of the address.""" - return to_checksum_address(self._value) - - def __str__(self) -> str: - return self.checksum - - def __repr__(self) -> str: - return f"{self.__class__.__name__}.from_hex({self.checksum})" - - -class Block(Enum): - """Block aliases supported by Ethereum RPC.""" - - LATEST = "latest" - """The latest confirmed block""" - - EARLIEST = "earliest" - """The earliest block""" - - PENDING = "pending" - """Currently pending block""" - - SAFE = "safe" - """The latest safe head block""" - - FINALIZED = "finalized" - """The latest finalized block""" - - -class BlockFilterId(TypedQuantity): - """A block filter identifier (returned by ``eth_newBlockFilter``).""" - - -class PendingTransactionFilterId(TypedQuantity): - """A pending transaction filter identifier (returned by ``eth_newPendingTransactionFilter``).""" - - -class LogFilterId(TypedQuantity): - """A log filter identifier (returned by ``eth_newFilter``).""" - - -@dataclass -class BlockFilter: - id_: BlockFilterId - provider_path: tuple[int, ...] - - -@dataclass -class PendingTransactionFilter: - id_: PendingTransactionFilterId - provider_path: tuple[int, ...] - - -@dataclass -class LogFilter: - id_: LogFilterId - provider_path: tuple[int, ...] - - -class LogTopic(TypedData): - """A log topic for log filtering.""" - - def _length(self) -> int: - return 32 - - -class BlockHash(TypedData): - """A wrapper for the block hash.""" - - def _length(self) -> int: - return 32 - - -class TxHash(TypedData): - """A wrapper for the transaction hash.""" - - def _length(self) -> int: - return 32 - - -@dataclass -class TxInfo: - """Transaction info.""" - - # TODO: make an enum? - type_: int - """Transaction type: 0 for legacy transactions, 2 for EIP1559 transactions.""" - - hash_: TxHash - """Transaction hash.""" - - input_: None | bytes - """The data sent along with the transaction.""" - - block_hash: None | BlockHash - """The hash of the block this transaction belongs to. ``None`` for pending transactions.""" - - block_number: int - """The number of the block this transaction belongs to. May be a pending block.""" - - transaction_index: None | int - """Transaction index. ``None`` for pending transactions.""" - - from_: Address - """Transaction sender.""" - - to: None | Address - """ - Transaction recipient. - ``None`` when it's a contract creation transaction. - """ - - value: Amount - """Associated funds.""" - - nonce: int - """Transaction nonce.""" - - gas: int - """Gas used by the transaction.""" - - gas_price: Amount - """Gas price used by the transaction.""" - - # TODO: we may want to have a separate derived class for EIP1559 transactions, - # but for now this will do. - - max_fee_per_gas: None | Amount - """``maxFeePerGas`` value specified by the sender. Only for EIP1559 transactions.""" - - max_priority_fee_per_gas: None | Amount - """``maxPriorityFeePerGas`` value specified by the sender. Only for EIP1559 transactions.""" - - -@dataclass -class BlockInfo: - """Block info.""" - - number: int - """Block number.""" - - hash_: None | BlockHash - """Block hash. ``None`` for pending blocks.""" - - parent_hash: BlockHash - """Parent block's hash.""" - - nonce: None | int - """Block's nonce. ``None`` for pending blocks.""" - - miner: None | Address - """Block's miner. ``None`` for pending blocks.""" - - difficulty: int - """Block's difficulty.""" - - total_difficulty: None | int - """Block's totat difficulty. ``None`` for pending blocks.""" - - size: int - """Block size.""" - - gas_limit: int - """Block's gas limit.""" - - gas_used: int - """Gas used for the block.""" - - base_fee_per_gas: Amount - """Base fee per gas in this block.""" - - timestamp: int - """Block's timestamp.""" - - transactions: tuple[TxInfo, ...] | tuple[TxHash, ...] - """ - A list of transaction hashes in this block, or a list of details of transactions in this block, - depending on what was requested. - """ - - -@dataclass -class LogEntry: - """Log entry metadata.""" - - removed: bool - """ - ``True`` if log was removed, due to a chain reorganization. - ``False`` if it is a valid log. - """ - - address: Address - """ - The contract address from which this log originated. - """ - - data: bytes - """ABI-packed non-indexed arguments of the event.""" - - topics: tuple[LogTopic, ...] - """ - Values of indexed event fields. - For a named event, the first topic is the event's selector. - """ - - # In the docs of major providers (Infura, Alchemy, Quicknode) it is claimed - # that the following fields can be null if "it is a pending log". - # I could not reproduce such behavior, so for now they're staying non-nullable. - - log_index: int - """Log's position in the block.""" - - transaction_index: int - """Transaction's position in the block.""" - - transaction_hash: TxHash - """Hash of the transactions this log was created from.""" - - block_hash: BlockHash - """Hash of the block where this log was in.""" - - block_number: int - """The block number where this log was.""" - - -@dataclass -class TxReceipt: - """Transaction receipt.""" - - block_hash: BlockHash - """Hash of the block including this transaction.""" - - block_number: int - """Block number including this transaction.""" - - contract_address: None | Address - """ - If it was a successful deployment transaction, - contains the address of the deployed contract. - """ - - cumulative_gas_used: int - """The total amount of gas used when this transaction was executed in the block.""" - - effective_gas_price: Amount - """The actual value per gas deducted from the sender's account.""" - - from_: Address - """Address of the sender.""" - - gas_used: int - """The amount of gas used by the transaction.""" - - to: None | Address - """ - Address of the receiver. - ``None`` when the transaction is a contract creation transaction. - """ - - transaction_hash: TxHash - """Hash of the transaction.""" - - transaction_index: int - """Integer of the transaction's index position in the block.""" - - # TODO: make an enum? - type_: int - """Transaction type: 0 for legacy transactions, 2 for EIP1559 transactions.""" - - status: int - """1 if the transaction was successful, 0 otherwise.""" - - logs: tuple[LogEntry, ...] - """An array of log objects generated by this transaction.""" - - @property - def succeeded(self) -> bool: - """``True`` if the transaction succeeded.""" - return self.status == 1 - - -class RPCErrorCode(Enum): - """Known RPC error codes returned by providers.""" - - # This is our placeholder value, shouldn't be encountered in a remote server response - UNKNOWN_REASON = 0 - """An error code whose description is not present in this enum.""" - - SERVER_ERROR = -32000 - """Reserved for implementation-defined server-errors. See the message for details.""" - - INVALID_REQUEST = -32600 - """The JSON sent is not a valid Request object.""" - - METHOD_NOT_FOUND = -32601 - """The method does not exist / is not available.""" - - INVALID_PARAMETER = -32602 - """Invalid method parameter(s).""" - - EXECUTION_ERROR = 3 - """Contract transaction failed during execution. See the data for details.""" - - @classmethod - def from_int(cls, val: int) -> "RPCErrorCode": - try: - return cls(val) - except ValueError: - return cls.UNKNOWN_REASON - - -# Need a newtype because unlike all other integers, this one is not hexified on serialization. -ErrorCode = NewType("ErrorCode", int) - - -@dataclass -class RPCError(Exception): - """A wrapper for a call execution error returned as a proper RPC response.""" - - # Taking an integer and not `RPCErrorCode` here - # since the codes may differ between providers. - code: ErrorCode - message: str - data: None | bytes = None - - @classmethod - def invalid_request(cls) -> "RPCError": - return cls(ErrorCode(RPCErrorCode.INVALID_REQUEST.value), "invalid json request") - - -# EIP-2930 transaction -@dataclass -class Type2Transaction: - # "type": 2 - chain_id: int - value: Amount - gas: int - max_fee_per_gas: Amount - max_priority_fee_per_gas: Amount - nonce: int - to: None | Address = None - data: None | bytes = None - - -@dataclass -class EthCallParams: - """Transaction fields for ``eth_call``.""" - - to: Address - from_: None | Address = None - gas: None | int = None - gas_price: int = 0 - value: Amount = Amount(0) - data: None | bytes = None - - -@dataclass -class EstimateGasParams: - """Transaction fields for ``eth_estimateGas``.""" - - from_: Address - to: None | Address = None - gas: None | int = None - gas_price: int = 0 - nonce: None | int = None - value: Amount = Amount(0) - data: None | bytes = None - - -@dataclass -class FilterParams: - """Filter parameters for ``eth_getLogs`` or ``eth_newFilter``.""" - - from_block: None | int | Block = None - to_block: None | int | Block = None - address: None | Address | tuple[Address, ...] = None - topics: None | tuple[None | LogTopic | tuple[LogTopic, ...], ...] = None diff --git a/pons/_fallback_provider.py b/pons/_fallback_provider.py index 8b2ec53..90e5d35 100644 --- a/pons/_fallback_provider.py +++ b/pons/_fallback_provider.py @@ -2,7 +2,8 @@ from collections.abc import AsyncIterator, Iterable from contextlib import AsyncExitStack, asynccontextmanager -from ._entities import RPCError +from ethereum_rpc import RPCError + from ._provider import JSON, InvalidResponse, Provider, ProviderSession diff --git a/pons/_http_provider_server.py b/pons/_http_provider_server.py index 26ad2b5..92fe530 100644 --- a/pons/_http_provider_server.py +++ b/pons/_http_provider_server.py @@ -2,6 +2,7 @@ from typing import cast import trio +from ethereum_rpc import RPCError, RPCErrorCode, unstructure from hypercorn.config import Config from hypercorn.trio import serve from hypercorn.typing import ASGIFramework @@ -11,9 +12,7 @@ from starlette.routing import Route from trio_typing import TaskStatus -from ._entities import RPCError from ._provider import JSON, HTTPProvider, Provider -from ._serialization import unstructure def parse_request(request: JSON) -> tuple[JSON, str, list[JSON]]: @@ -32,7 +31,9 @@ async def process_request_inner(provider: Provider, request: JSON) -> tuple[JSON try: request_id, method, params = parse_request(request) except (KeyError, TypeError) as exc: - raise RPCError.invalid_request() from exc + raise RPCError.with_code( + RPCErrorCode.INVALID_REQUEST, "Cannot parse the request as JSON" + ) from exc async with provider.session() as session: result = await session.rpc(method, *params) diff --git a/pons/_local_provider.py b/pons/_local_provider.py index a6b0d28..8e7a0cd 100644 --- a/pons/_local_provider.py +++ b/pons/_local_provider.py @@ -7,10 +7,9 @@ from typing import Any from alysis import Node, RPCNode -from alysis import RPCError as AlysisRPCError from eth_account import Account +from ethereum_rpc import Amount -from ._entities import Amount, ErrorCode, RPCError from ._provider import JSON, Provider, ProviderSession from ._signer import AccountSigner, Signer @@ -59,10 +58,7 @@ def revert_to_snapshot(self, snapshot_id: SnapshotID) -> None: self._rpc_node = RPCNode(self._local_node) def rpc(self, method: str, *args: Any) -> JSON: - try: - return self._rpc_node.rpc(method, *args) - except AlysisRPCError as exc: - raise RPCError(ErrorCode(exc.code), exc.message, exc.data) from exc + return self._rpc_node.rpc(method, *args) @asynccontextmanager async def session(self) -> AsyncIterator["LocalProviderSession"]: diff --git a/pons/_provider.py b/pons/_provider.py index 5c612dc..0ea1bf8 100644 --- a/pons/_provider.py +++ b/pons/_provider.py @@ -6,9 +6,8 @@ from typing import cast import httpx - -from ._entities import RPCError -from ._serialization import JSON, StructuringError, structure +from compages import StructuringError +from ethereum_rpc import JSON, RPCError, structure class InvalidResponse(Exception): diff --git a/pons/_serialization.py b/pons/_serialization.py deleted file mode 100644 index 156c715..0000000 --- a/pons/_serialization.py +++ /dev/null @@ -1,177 +0,0 @@ -"""Ethereum RPC schema.""" - -from collections.abc import Generator, Mapping, Sequence -from types import MappingProxyType, NoneType, UnionType -from typing import Any, TypeVar, Union, cast - -from compages import ( - StructureDictIntoDataclass, - Structurer, - StructuringError, - UnstructureDataclassToDict, - Unstructurer, - simple_structure, - simple_typechecked_unstructure, - structure_into_bool, - structure_into_int, - structure_into_list, - structure_into_none, - structure_into_str, - structure_into_tuple, - structure_into_union, - unstructure_as_bool, - unstructure_as_int, - unstructure_as_list, - unstructure_as_none, - unstructure_as_str, - unstructure_as_tuple, - unstructure_as_union, -) - -from ._entities import ( - Address, - Block, - ErrorCode, - Type2Transaction, - TypedData, - TypedQuantity, -) - -# TODO: the doc entry had to be written manually for this type because of Sphinx limitations. -JSON = None | bool | int | float | str | Sequence["JSON"] | Mapping[str, "JSON"] -"""Values serializable to JSON.""" - - -def _structure_into_bytes(_structurer: Structurer, _structure_into: Any, val: Any) -> bytes: - if not isinstance(val, str) or not val.startswith("0x"): - raise StructuringError("The value must be a 0x-prefixed hex-encoded data") - try: - return bytes.fromhex(val[2:]) - except ValueError as exc: - raise StructuringError(str(exc)) from exc - - -def _structure_into_typed_data( - _structurer: Structurer, structure_into: type[TypedData], val: Any -) -> TypedData: - data = _structure_into_bytes(_structurer, structure_into, val) - return structure_into(data) - - -def _structure_into_typed_quantity( - _structurer: Structurer, structure_into: type[TypedQuantity], val: Any -) -> TypedQuantity: - if not isinstance(val, str) or not val.startswith("0x"): - raise StructuringError("The value must be a 0x-prefixed hex-encoded integer") - int_val = int(val, 0) - return structure_into(int_val) - - -def _structure_into_int_common(val: Any) -> int: - if not isinstance(val, str) or not val.startswith("0x"): - raise StructuringError("The value must be a 0x-prefixed hex-encoded integer") - return int(val, 0) - - -@simple_structure -def _structure_into_int(val: Any) -> int: - return _structure_into_int_common(val) - - -def _unstructure_type2tx( - unstructurer: Unstructurer, _unstructure_as: type[Type2Transaction], obj: Type2Transaction -) -> Generator[Type2Transaction, dict[str, JSON], JSON]: - json = yield obj - json["type"] = unstructurer.unstructure_as(int, 2) - return json - - -@simple_typechecked_unstructure -def _unstructure_typed_quantity(obj: TypedQuantity) -> str: - return hex(int(obj)) - - -@simple_typechecked_unstructure -def _unstructure_typed_data(obj: TypedData) -> str: - return "0x" + bytes(obj).hex() - - -@simple_typechecked_unstructure -def _unstructure_address(obj: Address) -> str: - return obj.checksum - - -@simple_typechecked_unstructure -def _unstructure_block(obj: Block) -> str: - return obj.value - - -@simple_typechecked_unstructure -def _unstructure_int_to_hex(obj: int) -> str: - return hex(obj) - - -@simple_typechecked_unstructure -def _unstructure_bytes_to_hex(obj: bytes) -> str: - return "0x" + obj.hex() - - -def _to_camel_case(name: str, _metadata: MappingProxyType[Any, Any]) -> str: - if name.endswith("_"): - name = name[:-1] - parts = name.split("_") - return parts[0] + "".join(part.capitalize() for part in parts[1:]) - - -STRUCTURER = Structurer( - { - TypedData: _structure_into_typed_data, - TypedQuantity: _structure_into_typed_quantity, - ErrorCode: structure_into_int, - int: _structure_into_int, - str: structure_into_str, - bool: structure_into_bool, - bytes: _structure_into_bytes, - list: structure_into_list, - tuple: structure_into_tuple, - UnionType: structure_into_union, - Union: structure_into_union, - NoneType: structure_into_none, - }, - [StructureDictIntoDataclass(_to_camel_case)], -) - -UNSTRUCTURER = Unstructurer( - { - TypedData: _unstructure_typed_data, - TypedQuantity: _unstructure_typed_quantity, - Address: _unstructure_address, - Block: _unstructure_block, - ErrorCode: unstructure_as_int, - Type2Transaction: _unstructure_type2tx, - int: _unstructure_int_to_hex, - bytes: _unstructure_bytes_to_hex, - bool: unstructure_as_bool, - str: unstructure_as_str, - NoneType: unstructure_as_none, - list: unstructure_as_list, - UnionType: unstructure_as_union, - Union: unstructure_as_union, - tuple: unstructure_as_tuple, - }, - [UnstructureDataclassToDict(_to_camel_case)], -) - - -_T = TypeVar("_T") - - -def structure(structure_into: type[_T], obj: JSON) -> _T: - """Structures incoming JSON data.""" - return STRUCTURER.structure_into(structure_into, obj) - - -def unstructure(obj: Any, unstructure_as: Any = None) -> JSON: - """Unstructures data into JSON-serializable values.""" - # The result is `JSON` by virtue of the hooks we defined - return cast(JSON, UNSTRUCTURER.unstructure_as(unstructure_as or type(obj), obj)) diff --git a/pons/_signer.py b/pons/_signer.py index ff249b6..3a2ce77 100644 --- a/pons/_signer.py +++ b/pons/_signer.py @@ -4,9 +4,7 @@ from eth_account import Account from eth_account.signers.local import LocalAccount - -from ._entities import Address -from ._provider import JSON +from ethereum_rpc import JSON, Address class Signer(ABC): diff --git a/pyproject.toml b/pyproject.toml index adbbcef..ac51e93 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,20 +14,21 @@ dependencies = [ "setuptools", # required by eth-utils, but it just assumes that it's already installed "trio-typing>=0.9.0", "compages>=0.3", + "ethereum-rpc>=0.1", ] requires-python = ">=3.10" license = "MIT" readme = "README.md" [project.urls] -homepage = "https://github.com/fjarri/pons" +homepage = "https://github.com/fjarri-eth/pons" [project.optional-dependencies] compiler = [ "py-solc-x>=2", ] local-provider = [ - "alysis>=0.4.0", + "alysis>=0.5.0", "starlette", "hypercorn", ] diff --git a/tests/conftest.py b/tests/conftest.py index 52da137..a0e575b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,7 @@ import pytest +from ethereum_rpc import Amount -from pons import AccountSigner, Amount, Client, LocalProvider +from pons import AccountSigner, Client, LocalProvider @pytest.fixture diff --git a/tests/test_abi_types.py b/tests/test_abi_types.py index b09ad00..cb7d3ad 100644 --- a/tests/test_abi_types.py +++ b/tests/test_abi_types.py @@ -1,15 +1,15 @@ import os import pytest +from ethereum_rpc import Address, keccak -from pons import Address, abi +from pons import abi from pons._abi_types import ( ABIDecodingError, decode_args, dispatch_type, dispatch_types, encode_args, - keccak, type_from_abi_string, ) diff --git a/tests/test_client.py b/tests/test_client.py index 5b35c5c..e9d92c9 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -4,13 +4,20 @@ import pytest import trio - -from pons import ( - ABIDecodingError, +from ethereum_rpc import ( Address, Amount, - Block, BlockHash, + BlockLabel, + RPCError, + RPCErrorCode, + TxHash, + TxInfo, + keccak, +) + +from pons import ( + ABIDecodingError, Client, ContractABI, ContractError, @@ -21,15 +28,12 @@ LocalProvider, Method, Mutability, - RPCErrorCode, - TxHash, abi, compile_contract_file, ) -from pons._abi_types import encode_args, keccak +from pons._abi_types import encode_args from pons._client import BadResponseFormat, ProviderError, TransactionFailed from pons._contract_abi import PANIC_ERROR -from pons._entities import RPCError, TxInfo @pytest.fixture @@ -131,7 +135,7 @@ async def test_eth_get_transaction_count(local_provider, session, root_signer, a # Check that pending transactions are accounted for local_provider.disable_auto_mine_transactions() await session.broadcast_transfer(root_signer, another_signer.address, Amount.ether(10)) - assert await session.eth_get_transaction_count(root_signer.address, Block.PENDING) == 2 + assert await session.eth_get_transaction_count(root_signer.address, BlockLabel.PENDING) == 2 async def test_wait_for_transaction_receipt( @@ -180,7 +184,7 @@ async def test_eth_call(session, compiled_contracts, root_signer, another_signer # With a real provider, if `sender_address` is not given, it will default to the zero address. result = await session.eth_call(deployed_contract.method.getSender()) - assert result == (Address.from_hex(b"\x00" * 20),) + assert result == (Address(b"\x00" * 20),) # Seems to be another tester chain limitation: even though `eth_call` does not spend gas, # the `sender_address` still needs to be funded. @@ -204,7 +208,7 @@ async def test_eth_call_pending(local_provider, session, compiled_contracts, roo assert result == (123,) # This also uses the state change introduced by the pending transaction - result = await session.eth_call(deployed_contract.method.getState(0), block=Block.PENDING) + result = await session.eth_call(deployed_contract.method.getState(0), block=BlockLabel.PENDING) assert result == (456,) @@ -520,7 +524,7 @@ async def test_get_block_pending(local_provider, session, root_signer, another_s root_signer, another_signer.address, Amount.ether(10) ) - block_info = await session.eth_get_block_by_number(Block.PENDING, with_transactions=True) + block_info = await session.eth_get_block_by_number(BlockLabel.PENDING, with_transactions=True) assert block_info.number == 2 assert block_info.hash_ is None assert block_info.nonce is None @@ -530,7 +534,7 @@ async def test_get_block_pending(local_provider, session, root_signer, another_s assert block_info.transactions[0].hash_ == tx_hash assert block_info.transactions[0].value == Amount.ether(10) - block_info = await session.eth_get_block_by_number(Block.PENDING, with_transactions=False) + block_info = await session.eth_get_block_by_number(BlockLabel.PENDING, with_transactions=False) assert len(block_info.transactions) == 1 assert block_info.transactions[0] == tx_hash @@ -559,7 +563,7 @@ async def test_eth_get_transaction_by_hash(local_provider, session, root_signer, async def test_eth_get_code(session, root_signer, compiled_contracts): compiled_contract = compiled_contracts["EmptyContract"] deployed_contract = await session.deploy(root_signer, compiled_contract.constructor(123)) - bytecode = await session.eth_get_code(deployed_contract.address, block=Block.LATEST) + bytecode = await session.eth_get_code(deployed_contract.address, block=BlockLabel.LATEST) # The bytecode being deployed is not the code that will be stored on chain, # but some code that, having been executed, returns the code that will be stored on chain. @@ -578,7 +582,9 @@ async def test_eth_get_storage_at(session, root_signer, compiled_contracts): ) # Get the regular stored value - storage = await session.eth_get_storage_at(deployed_contract.address, 0, block=Block.LATEST) + storage = await session.eth_get_storage_at( + deployed_contract.address, 0, block=BlockLabel.LATEST + ) assert storage == b"\x00" * 31 + x.to_bytes(1, byteorder="big") # Get the value of the mapping @@ -594,7 +600,7 @@ async def test_eth_get_storage_at(session, root_signer, compiled_contracts): byteorder="big", ) storage = await session.eth_get_storage_at( - deployed_contract.address, position, block=Block.LATEST + deployed_contract.address, position, block=BlockLabel.LATEST ) assert storage == b"\x00" * 31 + y_val.to_bytes(1, byteorder="big") @@ -624,7 +630,7 @@ async def test_block_filter(session, root_signer, another_signer): await session.transfer(root_signer, another_signer.address, to_transfer) await session.transfer(root_signer, another_signer.address, to_transfer) - last_block = await session.eth_get_block_by_number(Block.LATEST) + last_block = await session.eth_get_block_by_number(BlockLabel.LATEST) prev_block = await session.eth_get_block_by_number(last_block.number - 1) block_hashes = await session.eth_get_filter_changes(block_filter) @@ -633,7 +639,7 @@ async def test_block_filter(session, root_signer, another_signer): await session.transfer(root_signer, another_signer.address, to_transfer) block_hashes = await session.eth_get_filter_changes(block_filter) - last_block = await session.eth_get_block_by_number(Block.LATEST) + last_block = await session.eth_get_block_by_number(BlockLabel.LATEST) assert block_hashes == (last_block.hash_,) block_hashes = await session.eth_get_filter_changes(block_filter) @@ -1133,7 +1139,8 @@ def mock_rpc(method, *args): with monkeypatched(local_provider, "rpc", mock_rpc): with pytest.raises( - ProviderError, match=r"Provider error \(EXECUTION_ERROR\): execution reverted" + ProviderError, + match=r"Provider error \(RPCErrorCode\.EXECUTION_ERROR\): execution reverted", ): await session.estimate_transact(root_signer.address, contract.method.transactPanic(999)) diff --git a/tests/test_contract.py b/tests/test_contract.py index d4f175a..4ee7a7d 100644 --- a/tests/test_contract.py +++ b/tests/test_contract.py @@ -2,9 +2,9 @@ from typing import NamedTuple import pytest +from ethereum_rpc import Address, LogTopic, keccak from pons import ( - Address, Constructor, Event, Fallback, @@ -13,9 +13,8 @@ abi, compile_contract_file, ) -from pons._abi_types import encode_args, keccak +from pons._abi_types import encode_args from pons._contract import BoundMethod, DeployedContract -from pons._entities import LogTopic @pytest.fixture diff --git a/tests/test_contract_abi.py b/tests/test_contract_abi.py index 65e9b69..72d575f 100644 --- a/tests/test_contract_abi.py +++ b/tests/test_contract_abi.py @@ -2,6 +2,7 @@ from typing import NamedTuple import pytest +from ethereum_rpc import LogTopic, keccak from pons import ( Constructor, @@ -16,7 +17,7 @@ Receive, abi, ) -from pons._abi_types import encode_args, keccak +from pons._abi_types import encode_args from pons._contract_abi import ( LEGACY_ERROR, PANIC_ERROR, @@ -24,7 +25,6 @@ Signature, UnknownError, ) -from pons._entities import LogTopic def test_signature_from_dict(): diff --git a/tests/test_contract_functionality.py b/tests/test_contract_functionality.py index 92090b3..b00491d 100644 --- a/tests/test_contract_functionality.py +++ b/tests/test_contract_functionality.py @@ -1,17 +1,17 @@ from pathlib import Path import pytest +from ethereum_rpc import Amount from pons import ( - Amount, Constructor, ContractABI, DeployedContract, Method, Mutability, abi, + compile_contract_file, ) -from pons._compiler import compile_contract_file @pytest.fixture diff --git a/tests/test_entities.py b/tests/test_entities.py deleted file mode 100644 index c447723..0000000 --- a/tests/test_entities.py +++ /dev/null @@ -1,123 +0,0 @@ -import os - -import pytest - -from pons import Address, Amount, BlockHash, TxHash -from pons._entities import LogTopic - - -def test_amount(): - # Conversions - val = 100 - assert Amount.wei(val).as_wei() == val - assert Amount.wei(val).as_gwei() == val / 10**9 - assert Amount.wei(val).as_ether() == val / 10**18 - assert Amount.gwei(val).as_wei() == val * 10**9 - assert Amount.ether(val).as_wei() == val * 10**18 - - with pytest.raises(TypeError, match="Amount must be an integer, got float"): - Amount.wei(100.0) - - # other constructors cast to integer - assert Amount.gwei(100.0).as_wei() == 100 * 10**9 - assert Amount.ether(100.0).as_wei() == 100 * 10**18 - - with pytest.raises(ValueError, match="Amount must be non-negative, got -100"): - Amount.wei(-100) - - assert Amount.wei(100) + Amount.wei(50) == Amount.wei(150) - assert Amount.wei(100) - Amount.wei(50) == Amount.wei(50) - assert Amount.wei(100) * 2 == Amount.wei(200) - assert Amount.wei(100) // 2 == Amount.wei(50) - assert Amount.wei(100) > Amount.wei(50) - assert not Amount.wei(50) > Amount.wei(50) - assert Amount.wei(100) >= Amount.wei(50) - assert Amount.wei(50) >= Amount.wei(50) - assert Amount.wei(50) < Amount.wei(100) - assert not Amount.wei(50) < Amount.wei(50) - assert Amount.wei(50) <= Amount.wei(100) - assert Amount.wei(50) <= Amount.wei(50) - - # The type is hashable - amount_set = {Amount.wei(100), Amount.wei(100), Amount.wei(50)} - assert amount_set == {Amount.wei(100), Amount.wei(50)} - - class MyAmount(Amount): - pass - - assert repr(Amount.wei(100)) == "Amount(100)" - assert repr(MyAmount.wei(100)) == "MyAmount(100)" - - with pytest.raises(TypeError, match="Incompatible types: Amount and int"): - Amount.wei(100) + 100 - - # Type checking is strict, subclasses are considered different types - with pytest.raises(TypeError, match="Incompatible types: Amount and MyAmount"): - Amount.wei(100) + MyAmount.wei(100) - - with pytest.raises(TypeError, match="Expected an integer, got float"): - Amount.wei(100) * 2.0 - - with pytest.raises(TypeError, match="Expected an integer, got float"): - Amount.wei(100) // 2.0 - - -def test_address(): - random_addr = b"dv\xbbCQ,\xfe\xd0\xbfF\x8aq\x07OK\xf9\xa1i\x88(" - random_addr_checksum = "0x6476Bb43512CFed0bF468a71074F4bF9A1698828" - - random_addr2 = os.urandom(20) - - assert bytes(Address(random_addr)) == random_addr - assert bytes(Address.from_hex(random_addr_checksum)) == random_addr - assert bytes(Address.from_hex(random_addr_checksum.lower())) == random_addr - - assert Address(random_addr).checksum == random_addr_checksum - - assert Address(random_addr) == Address(random_addr) - assert Address(random_addr) != Address(os.urandom(20)) - - class MyAddress(Address): - pass - - assert str(Address(random_addr)) == random_addr_checksum - assert repr(Address(random_addr)) == f"Address.from_hex({random_addr_checksum})" - assert repr(MyAddress(random_addr)) == f"MyAddress.from_hex({random_addr_checksum})" - - # The type is hashable - addr_set = {Address(random_addr), Address(random_addr2), Address(random_addr)} - assert addr_set == {Address(random_addr), Address(random_addr2)} - - with pytest.raises(TypeError, match="Address must be a bytestring, got str"): - Address(random_addr_checksum) - - with pytest.raises(ValueError, match="Address must be 20 bytes long, got 19"): - Address(random_addr[:-1]) - - with pytest.raises(ValueError, match="Address must be 20 bytes long, got 19"): - Address(random_addr[:-1]) - - with pytest.raises(TypeError, match="Incompatible types: MyAddress and Address"): - # For whatever reason the the values are switched places in `__eq__()` - assert Address(random_addr) == MyAddress(random_addr) - - # This error comes from eth_utils, we don't care about the phrasing, - # but want to detect if the type changes. - with pytest.raises(ValueError): # noqa: PT011 - Address.from_hex(random_addr_checksum[:-1]) - - -def test_typed_data(): - # This is not covered by Address tests, since it overrides those methods - data = os.urandom(32) - tx_hash = TxHash(data) - assert repr(tx_hash) == f'TxHash(bytes.fromhex("{data.hex()}"))' - - -def test_typed_data_lengths(): - # Just try to create the corresponding types, - # it will cover their respective length methods. - # Everything else is in the base class which is tested elsewhere - TxHash(os.urandom(32)) - BlockHash(os.urandom(32)) - LogTopic(os.urandom(32)) diff --git a/tests/test_fallback_provider.py b/tests/test_fallback_provider.py index 2105f48..f97cb08 100644 --- a/tests/test_fallback_provider.py +++ b/tests/test_fallback_provider.py @@ -4,11 +4,11 @@ from enum import Enum import pytest +from ethereum_rpc import JSON, RPCError from pons import CycleFallback, FallbackProvider, PriorityFallback, Unreachable -from pons._entities import RPCError from pons._fallback_provider import PriorityFallbackStrategy -from pons._provider import JSON, InvalidResponse, Provider, ProviderSession +from pons._provider import InvalidResponse, Provider, ProviderSession def random_request(): diff --git a/tests/test_http_provider_server.py b/tests/test_http_provider_server.py index a4b925d..842b66f 100644 --- a/tests/test_http_provider_server.py +++ b/tests/test_http_provider_server.py @@ -2,8 +2,9 @@ # and don't use high-level API. import pytest +from ethereum_rpc import RPCError, RPCErrorCode -from pons import HTTPProviderServer, RPCError, RPCErrorCode +from pons import HTTPProviderServer @pytest.fixture diff --git a/tests/test_local_provider.py b/tests/test_local_provider.py index 8ff0bff..d3d034e 100644 --- a/tests/test_local_provider.py +++ b/tests/test_local_provider.py @@ -1,8 +1,9 @@ # TODO (#60): expand the tests so that this file covered 100% of the respective submodule. import pytest +from ethereum_rpc import Amount, RPCError -from pons import AccountSigner, Amount, Client, LocalProvider, RPCError +from pons import AccountSigner, Client, LocalProvider # Masking the global fixtures to make this test self-contained diff --git a/tests/test_provider.py b/tests/test_provider.py index 1cb4f3c..8692cb6 100644 --- a/tests/test_provider.py +++ b/tests/test_provider.py @@ -3,9 +3,9 @@ import pytest import trio +from ethereum_rpc import Amount from pons import ( - Amount, Client, HTTPProvider, HTTPProviderServer, @@ -13,7 +13,6 @@ _http_provider_server, # For monkeypatching purposes ) from pons._client import BadResponseFormat, ProviderError -from pons._entities import RPCErrorCode from pons._provider import HTTPError, Provider, ProviderSession @@ -208,7 +207,3 @@ async def rpc(self, method, *_args): with pytest.raises(ValueError, match=r"Unexpected provider path: \(1,\)"): await session.rpc_at_pin((1,), "3") - - -def test_unknown_rpc_error_code(): - assert RPCErrorCode.from_int(-12345) == RPCErrorCode.UNKNOWN_REASON diff --git a/tests/test_serialization.py b/tests/test_serialization.py deleted file mode 100644 index 40d1ac2..0000000 --- a/tests/test_serialization.py +++ /dev/null @@ -1,38 +0,0 @@ -import os - -import pytest - -from pons import Address, Amount -from pons._serialization import StructuringError, structure - - -def test_structure_into_typed_quantity(): - assert structure(Amount, "0x123") == Amount(0x123) - - with pytest.raises( - StructuringError, match="The value must be a 0x-prefixed hex-encoded integer" - ): - structure(Amount, "abc") - - -def test_structure_into_int(): - assert structure(int, "0x123") == 0x123 - - with pytest.raises( - StructuringError, match="The value must be a 0x-prefixed hex-encoded integer" - ): - structure(int, "abc") - - -def test_structure_into_typed_data(): - address = os.urandom(20) - assert structure(Address, "0x" + address.hex()) == Address(address) - - with pytest.raises(StructuringError, match="The value must be a 0x-prefixed hex-encoded data"): - structure(Address, "abc") - - # The error text is weird - with pytest.raises( - StructuringError, match=r"non-hexadecimal number found in fromhex\(\) arg at position 0" - ): - structure(Address, "0xzz") diff --git a/tests/test_signer.py b/tests/test_signer.py index 4eec8ec..1dfe478 100644 --- a/tests/test_signer.py +++ b/tests/test_signer.py @@ -1,6 +1,7 @@ from eth_account import Account +from ethereum_rpc import Address -from pons import AccountSigner, Address +from pons import AccountSigner def check_signer(signer):