From c27cf1445417f6aaa4c58546ff2a209390fab696 Mon Sep 17 00:00:00 2001 From: Felix Henneke Date: Tue, 14 Jan 2025 00:52:38 +0100 Subject: [PATCH] Update dependencies (#490) This PR aims to update dependencies and closes #489. Main changes: - Use latest version of safe-eth-py. This required some changes to imports. The name of the Base network had to be changed. Also, the output type of some function changed to `bytes` which required updating the corresponding test, and some input changed trom a string to a checksumed string. - Use SQLAlchemy 2.0. This required some changes to executing statements which change the database. instead of executing on the engine object, the executions is called on the connection object. An additional `with` block was required to close the connection. Alternatively, one could have explicitly called a commit function. I will probably bound from below some of the packages we use. I also want to understand why web3 is still held back to 6.X instead of the latest stable version 7.X. I have tested the changes with the main payout in the accounting week 2024-12-31 to 2025-01-07. I tested that the base code does not crash at the point where it did before. Actually posting a transaction has not been done. --- requirements.in | 33 ++++--- requirements.txt | 131 ++++++++++++---------------- src/config.py | 4 +- src/data_sync/sync_data.py | 2 +- src/fetch/payouts.py | 6 +- src/fetch/transfer_file.py | 2 +- src/models/transfer.py | 4 +- src/multisend.py | 14 +-- src/pg_client.py | 15 ++-- tests/e2e/test_post_transaction.py | 6 +- tests/queries/test_batch_rewards.py | 5 +- tests/queries/test_quote_rewards.py | 5 +- tests/unit/test_models.py | 7 +- tests/unit/test_multisend.py | 91 ++++++++++--------- 14 files changed, 165 insertions(+), 160 deletions(-) diff --git a/requirements.in b/requirements.in index 174689af..56fd2dfa 100644 --- a/requirements.in +++ b/requirements.in @@ -1,20 +1,19 @@ -certifi>=2022.6.15 -duneapi>=8.0.0 -dune-client>=1.1.1 -psycopg2-binary>=2.9.6 -python-dotenv>=0.20.0 -coinpaprika>=0.1.0 -requests>=2.28.1 -safe-eth-py>=5.5.0 -slackclient>=2.9.4 -web3<7.0.0 -SQLAlchemy<2.0.0 -sqlalchemy-stubs>=0.4 -pandas==2.0.3 -pandas-stubs==2.0.2.230605 -numpy==1.26.4 -pip-tools==7.4.1 -python-dateutil>=2.9.0.post0 +certifi +coinpaprika +duneapi +dune-client +psycopg2-binary +python-dotenv +requests +safe-eth-py +slackclient +web3 +SQLAlchemy +sqlalchemy-stubs +pandas +numpy +python-dateutil +# dev dependencies black mypy pylint diff --git a/requirements.txt b/requirements.txt index b1224b40..3c4003aa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,60 +4,56 @@ # # pip-compile # -aiohappyeyeballs==2.4.0 +aiohappyeyeballs==2.4.4 # via aiohttp -aiohttp==3.10.5 +aiohttp==3.11.11 # via # dune-client # slackclient # web3 -aiosignal==1.3.1 +aiosignal==1.3.2 # via aiohttp -astroid==3.2.4 +astroid==3.3.8 # via pylint -attrs==24.2.0 +attrs==24.3.0 # via # aiohttp # jsonschema # referencing -bitarray==2.9.2 +bitarray==3.0.0 # via eth-account -black==24.8.0 +black==24.10.0 # via -r requirements.in -build==1.2.1 - # via pip-tools -cached-property==1.5.2 +cached-property==2.0.1 # via # py-ecc # py-evm -certifi==2024.7.4 +certifi==2024.12.14 # via # -r requirements.in # requests -charset-normalizer==3.3.2 +charset-normalizer==3.4.1 # via requests ckzg==1.0.2 # via # eth-account # py-evm # web3 -click==8.1.7 - # via - # black - # pip-tools +click==8.1.8 + # via black coinpaprika==0.1.0 # via -r requirements.in -cytoolz==0.12.3 +cytoolz==1.0.1 # via eth-utils dataclasses-json==0.6.7 # via dune-client -deprecated==1.2.14 +deprecated==1.2.15 # via # dune-client # duneapi -dill==0.3.8 +dill==0.3.9 # via pylint -dune-client==1.7.5 +dune-client==1.7.8 # via -r requirements.in duneapi==8.0.0 # via -r requirements.in @@ -67,7 +63,7 @@ eth-abi==5.1.0 # web3 eth-account==0.11.3 # via web3 -eth-bloom==3.0.1 +eth-bloom==3.1.0 # via py-evm eth-hash[pycryptodome]==0.7.0 # via @@ -77,7 +73,7 @@ eth-hash[pycryptodome]==0.7.0 # web3 eth-keyfile==0.8.1 # via eth-account -eth-keys==0.5.1 +eth-keys==0.6.0 # via # eth-account # eth-keyfile @@ -104,11 +100,11 @@ eth-utils==4.1.1 # rlp # trie # web3 -frozenlist==1.4.1 +frozenlist==1.5.0 # via # aiohttp # aiosignal -greenlet==3.0.3 +greenlet==3.1.1 # via sqlalchemy hexbytes==0.3.1 # via @@ -116,7 +112,7 @@ hexbytes==0.3.1 # eth-rlp # trie # web3 -idna==3.8 +idna==3.10 # via # requests # yarl @@ -126,21 +122,21 @@ isort==5.13.2 # via pylint jsonschema==4.23.0 # via web3 -jsonschema-specifications==2023.12.1 +jsonschema-specifications==2024.10.1 # via jsonschema lru-dict==1.2.0 # via # py-evm # web3 -marshmallow==3.22.0 +marshmallow==3.25.1 # via dataclasses-json mccabe==0.7.0 # via pylint -multidict==6.0.5 +multidict==6.1.0 # via # aiohttp # yarl -mypy==1.11.2 +mypy==1.14.1 # via # -r requirements.in # sqlalchemy-stubs @@ -151,53 +147,47 @@ mypy-extensions==1.0.0 # typing-inspect ndjson==0.3.1 # via dune-client -numpy==1.26.4 +numpy==2.2.1 # via # -r requirements.in # pandas - # pandas-stubs -packaging==24.1 +packaging==24.2 # via # black - # build # marshmallow # pytest # safe-eth-py -pandas==2.0.3 - # via -r requirements.in -pandas-stubs==2.0.2.230605 +pandas==2.2.3 # via -r requirements.in parsimonious==0.10.0 # via eth-abi pathspec==0.12.1 # via black -pip-tools==7.4.1 - # via -r requirements.in -platformdirs==4.2.2 +platformdirs==4.3.6 # via # black # pylint pluggy==1.5.0 # via pytest -protobuf==5.27.4 +propcache==0.2.1 + # via + # aiohttp + # yarl +protobuf==5.29.3 # via web3 -psycopg2-binary==2.9.9 +psycopg2-binary==2.9.10 # via -r requirements.in py-ecc==7.0.1 # via py-evm py-evm==0.10.1b1 # via safe-eth-py -pycryptodome==3.20.0 +pycryptodome==3.21.0 # via # eth-hash # eth-keyfile -pylint==3.2.6 +pylint==3.3.3 # via -r requirements.in -pyproject-hooks==1.1.0 - # via - # build - # pip-tools -pytest==8.3.2 +pytest==8.3.4 # via -r requirements.in python-dateutil==2.9.0.post0 # via @@ -208,15 +198,15 @@ python-dotenv==1.0.1 # via # -r requirements.in # duneapi -pytz==2024.1 +pytz==2024.2 # via pandas -pyunormalize==15.1.0 +pyunormalize==16.0.0 # via web3 referencing==0.35.1 # via # jsonschema # jsonschema-specifications -regex==2024.7.24 +regex==2024.11.6 # via parsimonious requests==2.32.3 # via @@ -232,58 +222,57 @@ rlp==4.0.1 # eth-rlp # py-evm # trie -rpds-py==0.20.0 +rpds-py==0.22.3 # via # jsonschema # referencing -safe-eth-py==5.8.0 +safe-eth-py==6.2.0 # via -r requirements.in safe-pysha3==1.0.4 # via safe-eth-py -six==1.16.0 +six==1.17.0 # via python-dateutil slackclient==2.9.4 # via -r requirements.in sortedcontainers==2.4.0 # via trie -sqlalchemy==1.4.53 +sqlalchemy==2.0.37 # via -r requirements.in sqlalchemy-stubs==0.4 # via -r requirements.in tomlkit==0.13.2 # via pylint -toolz==0.12.1 +toolz==1.0.0 # via cytoolz trie==3.0.1 # via py-evm -types-deprecated==1.2.9.20240311 +types-deprecated==1.2.15.20241117 # via # dune-client # duneapi -types-python-dateutil==2.9.0.20240821 +types-python-dateutil==2.9.0.20241206 # via dune-client -types-pytz==2024.1.0.20240417 - # via pandas-stubs -types-pyyaml==6.0.12.20240808 +types-pyyaml==6.0.12.20241230 # via dune-client -types-requests==2.32.0.20240712 +types-requests==2.32.0.20241016 # via # dune-client # duneapi -types-setuptools==73.0.0.20240822 +types-setuptools==75.8.0.20250110 # via dune-client typing-extensions==4.12.2 # via # eth-typing # mypy + # sqlalchemy # sqlalchemy-stubs # typing-inspect # web3 typing-inspect==0.9.0 # via dataclasses-json -tzdata==2024.1 +tzdata==2024.2 # via pandas -urllib3==2.2.2 +urllib3==2.3.0 # via # requests # types-requests @@ -292,15 +281,9 @@ web3==6.20.3 # -r requirements.in # duneapi # safe-eth-py -websockets==13.0 +websockets==14.1 # via web3 -wheel==0.44.0 - # via pip-tools -wrapt==1.16.0 +wrapt==1.17.1 # via deprecated -yarl==1.9.4 +yarl==1.18.3 # via aiohttp - -# The following packages are considered to be unsafe in a requirements file: -# pip -# setuptools diff --git a/src/config.py b/src/config.py index 3a9bf7fb..f30ebf67 100644 --- a/src/config.py +++ b/src/config.py @@ -11,7 +11,7 @@ from eth_typing.evm import ChecksumAddress from dotenv import load_dotenv from dune_client.types import Address -from gnosis.eth.ethereum_network import EthereumNetwork +from safe_eth.eth.ethereum_network import EthereumNetwork from web3 import Web3 load_dotenv() @@ -304,7 +304,7 @@ def from_network(network: Network) -> PaymentConfig: min_cow_transfer = 10**18 # 1 COW case Network.BASE: - payment_network = EthereumNetwork.BASE_MAINNET + payment_network = EthereumNetwork.BASE short_name = "base" cow_token_address = Address( diff --git a/src/data_sync/sync_data.py b/src/data_sync/sync_data.py index b499e516..f2160909 100644 --- a/src/data_sync/sync_data.py +++ b/src/data_sync/sync_data.py @@ -91,7 +91,7 @@ def __init__(self) -> None: self.end_time = self.end_time.replace(tzinfo=datetime.timezone.utc) -async def sync_data_to_db( # pylint: disable=too-many-arguments +async def sync_data_to_db( # pylint: disable=too-many-arguments, too-many-positional-arguments type_of_data: str, node: Web3, orderbook: OrderbookFetcher, diff --git a/src/fetch/payouts.py b/src/fetch/payouts.py index 84b89fb7..1effdfa3 100644 --- a/src/fetch/payouts.py +++ b/src/fetch/payouts.py @@ -69,7 +69,7 @@ class RewardAndPenaltyDatum: # pylint: disable=too-many-instance-attributes All pertinent information and functionality related to individual solver payout (or overdraft) """ - def __init__( # pylint: disable=too-many-arguments + def __init__( # pylint: disable=too-many-arguments, too-many-positional-arguments self, solver: Address, solver_name: str, @@ -299,7 +299,7 @@ def extend_payment_df( return pdf -def prepare_transfers( # pylint: disable=too-many-arguments +def prepare_transfers( # pylint: disable=too-many-arguments, too-many-positional-arguments payout_df: DataFrame, period: AccountingPeriod, final_protocol_fee_wei: int, @@ -440,7 +440,7 @@ def construct_payout_dataframe( config.reward_config.reward_token_address.address ) - merged_df["service_fee"] = merged_df["service_fee"].fillna(Fraction(0, 1)) # type: ignore + merged_df["service_fee"] = merged_df["service_fee"].fillna(Fraction(0, 1)) return merged_df diff --git a/src/fetch/transfer_file.py b/src/fetch/transfer_file.py index b32175d9..0260dc93 100644 --- a/src/fetch/transfer_file.py +++ b/src/fetch/transfer_file.py @@ -14,7 +14,7 @@ from dune_client.client import DuneClient from dune_client.file.interface import FileIO from eth_typing import URI -from gnosis.eth.ethereum_client import EthereumClient +from safe_eth.eth.ethereum_client import EthereumClient from slack.web.client import WebClient from src.config import AccountingConfig, Network diff --git a/src/models/transfer.py b/src/models/transfer.py index 9bcde752..ed6ce676 100644 --- a/src/models/transfer.py +++ b/src/models/transfer.py @@ -9,7 +9,7 @@ from dune_client.types import Address from eth_typing.encoding import HexStr -from gnosis.safe.multi_send import MultiSendOperation, MultiSendTx +from safe_eth.safe.multi_send import MultiSendOperation, MultiSendTx from web3 import Web3 from src.abis.load import erc20 @@ -105,7 +105,7 @@ def as_multisend_tx(self) -> MultiSendTx: assert self.token is not None return MultiSendTx( operation=MultiSendOperation.CALL, - to=str(self.token.address), + to=Web3.to_checksum_address(str(self.token.address)), value=0, data=ERC20_CONTRACT.encodeABI( fn_name="transfer", args=[receiver, self.amount_wei] diff --git a/src/multisend.py b/src/multisend.py index 8b06b7a5..f15cd664 100644 --- a/src/multisend.py +++ b/src/multisend.py @@ -4,11 +4,11 @@ """ from eth_typing.evm import ChecksumAddress -from gnosis.eth.ethereum_client import EthereumClient -from gnosis.eth.ethereum_network import EthereumNetwork -from gnosis.safe.api import TransactionServiceApi -from gnosis.safe.multi_send import MultiSend, MultiSendOperation, MultiSendTx -from gnosis.safe.safe import Safe +from safe_eth.eth.ethereum_client import EthereumClient +from safe_eth.eth.ethereum_network import EthereumNetwork +from safe_eth.safe.api import TransactionServiceApi +from safe_eth.safe.multi_send import MultiSend, MultiSendOperation, MultiSendTx +from safe_eth.safe.safe import Safe from src.config import web3 @@ -84,7 +84,9 @@ def post_multisend( """Posts a MultiSend Transaction from a list of Transfers.""" encoded_multisend = build_encoded_multisend(transactions, client=client) - safe = Safe(address=safe_address, ethereum_client=client) + safe = Safe( # type: ignore # pylint: disable=abstract-class-instantiated + address=safe_address, ethereum_client=client + ) safe_tx = safe.build_multisig_tx( to=MULTISEND_CONTRACT, value=0, diff --git a/src/pg_client.py b/src/pg_client.py index 8fd7f018..2f32f91b 100644 --- a/src/pg_client.py +++ b/src/pg_client.py @@ -70,18 +70,23 @@ def get_solver_rewards( ) results = [] - # Here, we use the convention that we run the prod query for the first connection - # and the barn query to all other connections + # querying the prod database log.info("Setting tcp_keepalives_idle to 900 for prod connection") - self.connections[0].execute(text("SET tcp_keepalives_idle = 900;")) + # set tcp_keepalive_idle to not time out behind firewall + with self.connections[0].connect() as connection: + with connection.begin(): + connection.execute(text("SET tcp_keepalives_idle = 900;")) log.info("Running prod query for first connection (in get_solver_rewards)") results.append( self.exec_query(query=batch_reward_query_prod, engine=self.connections[0]) ) - for engine in self.connections[1:]: + # query for barn database + if len(self.connections) > 1: # this is required due to our test setup log.info("Running barn query on other connections (in get_solver_rewards") results.append( - self.exec_query(query=batch_reward_query_barn, engine=engine) + self.exec_query( + query=batch_reward_query_barn, engine=self.connections[1] + ) ) results_df = pd.concat(results) diff --git a/tests/e2e/test_post_transaction.py b/tests/e2e/test_post_transaction.py index ebd09219..03773404 100644 --- a/tests/e2e/test_post_transaction.py +++ b/tests/e2e/test_post_transaction.py @@ -2,13 +2,13 @@ from dune_client.types import Address from eth_typing import URI -from gnosis.eth import EthereumNetwork, EthereumClient - +import pytest +from safe_eth.eth import EthereumNetwork, EthereumClient from web3 import Web3 + from src.fetch.transfer_file import Transfer from src.models.token import Token from src.multisend import post_multisend -import pytest class TestTransactionPost(unittest.TestCase): diff --git a/tests/queries/test_batch_rewards.py b/tests/queries/test_batch_rewards.py index 88b02272..a34249c3 100644 --- a/tests/queries/test_batch_rewards.py +++ b/tests/queries/test_batch_rewards.py @@ -2,6 +2,7 @@ import pandas.testing from pandas import DataFrame +from sqlalchemy import text from src.config import RewardConfig, Network from src.pg_client import MultiInstanceDBFetcher @@ -17,7 +18,9 @@ def setUp(self) -> None: with open( "./tests/queries/batch_rewards_test_db.sql", "r", encoding="utf-8" ) as file: - self.fetcher.connections[0].execute(file.read()) + with self.fetcher.connections[0].connect() as connection: + with connection.begin(): + connection.execute(text(file.read())) def test_get_batch_rewards(self): start_block, end_block = "0", "100" diff --git a/tests/queries/test_quote_rewards.py b/tests/queries/test_quote_rewards.py index 8bad030b..6ff0b936 100644 --- a/tests/queries/test_quote_rewards.py +++ b/tests/queries/test_quote_rewards.py @@ -2,6 +2,7 @@ import pandas.testing from pandas import DataFrame +from sqlalchemy import text from src.pg_client import MultiInstanceDBFetcher @@ -13,7 +14,9 @@ def setUp(self) -> None: with open( "./tests/queries/quote_rewards_test_db.sql", "r", encoding="utf-8" ) as file: - self.fetcher.connections[0].execute(file.read()) + with self.fetcher.connections[0].connect() as connection: + with connection.begin(): + connection.execute(text(file.read())) def test_get_quote_rewards(self): start_block, end_block = "0", "100" diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py index ab5e969f..53d0c053 100644 --- a/tests/unit/test_models.py +++ b/tests/unit/test_models.py @@ -1,9 +1,8 @@ import unittest -import pandas as pd from dune_client.types import Address from eth_typing import HexStr -from gnosis.safe.multi_send import MultiSendTx, MultiSendOperation +from safe_eth.safe.multi_send import MultiSendTx, MultiSendOperation from web3 import Web3 from src.abis.load import erc20 @@ -48,7 +47,9 @@ def test_basic_as_multisend_tx(self): erc20_transfer.as_multisend_tx(), MultiSendTx( operation=MultiSendOperation.CALL, - to=self.payment_config.cow_token_address.address, + to=Web3.to_checksum_address( + self.payment_config.cow_token_address.address + ), value=0, data=erc20().encodeABI(fn_name="transfer", args=[receiver, 15]), ), diff --git a/tests/unit/test_multisend.py b/tests/unit/test_multisend.py index a06948e1..7e583520 100644 --- a/tests/unit/test_multisend.py +++ b/tests/unit/test_multisend.py @@ -2,8 +2,7 @@ from dune_client.types import Address from eth_typing import URI -from gnosis.eth import EthereumClient -from web3 import Web3 +from safe_eth.eth import EthereumClient from src.abis.load import weth9 from src.config import Network, PaymentConfig @@ -70,9 +69,11 @@ def test_multisend_encoding(self): cow_token = Token(self.payment_config.cow_token_address) self.assertEqual( build_encoded_multisend([], client=self.client), - "0x8d80ff0a" # MethodID - "0000000000000000000000000000000000000000000000000000000000000020" - "0000000000000000000000000000000000000000000000000000000000000000", + bytes.fromhex( + "8d80ff0a" # MethodID + "0000000000000000000000000000000000000000000000000000000000000020" + "0000000000000000000000000000000000000000000000000000000000000000", + ), ) native_transfer = Transfer( @@ -80,12 +81,14 @@ def test_multisend_encoding(self): ).as_multisend_tx() self.assertEqual( build_encoded_multisend([native_transfer], client=self.client), - "0x8d80ff0a" # MethodID - "0000000000000000000000000000000000000000000000000000000000000020" - "0000000000000000000000000000000000000000000000000000000000000055" - "00de786877a10dbb7eba25a4da65aecf47654f08ab0000000000000000000000" - "0000000000000000000000000000000000000000100000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000", + bytes.fromhex( + "8d80ff0a" # MethodID + "0000000000000000000000000000000000000000000000000000000000000020" + "0000000000000000000000000000000000000000000000000000000000000055" + "00de786877a10dbb7eba25a4da65aecf47654f08ab0000000000000000000000" + "0000000000000000000000000000000000000000100000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000", + ), ) erc20_transfer = Transfer( token=cow_token, @@ -94,30 +97,34 @@ def test_multisend_encoding(self): ).as_multisend_tx() self.assertEqual( build_encoded_multisend([erc20_transfer], client=self.client), - "0x8d80ff0a" # MethodID - "0000000000000000000000000000000000000000000000000000000000000020" - "0000000000000000000000000000000000000000000000000000000000000099" - "00def1ca1fb7fbcdc777520aa7f396b4e015f497ab0000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000044a9059cbb00000000000000" - "0000000000de786877a10dbb7eba25a4da65aecf47654f08ab00000000000000" - "0000000000000000000000000000000000000000000000000f00000000000000", + bytes.fromhex( + "8d80ff0a" # MethodID + "0000000000000000000000000000000000000000000000000000000000000020" + "0000000000000000000000000000000000000000000000000000000000000099" + "00def1ca1fb7fbcdc777520aa7f396b4e015f497ab0000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000044a9059cbb00000000000000" + "0000000000de786877a10dbb7eba25a4da65aecf47654f08ab00000000000000" + "0000000000000000000000000000000000000000000000000f00000000000000", + ), ) self.assertEqual( build_encoded_multisend( [erc20_transfer, native_transfer], client=self.client ), - "0x8d80ff0a" # MethodID - "0000000000000000000000000000000000000000000000000000000000000020" - "00000000000000000000000000000000000000000000000000000000000000ee" - "00def1ca1fb7fbcdc777520aa7f396b4e015f497ab0000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000044a9059cbb00000000000000" - "0000000000de786877a10dbb7eba25a4da65aecf47654f08ab00000000000000" - "0000000000000000000000000000000000000000000000000f00de786877a10d" - "bb7eba25a4da65aecf47654f08ab000000000000000000000000000000000000" - "0000000000000000000000000010000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000", + bytes.fromhex( + "8d80ff0a" # MethodID + "0000000000000000000000000000000000000000000000000000000000000020" + "00000000000000000000000000000000000000000000000000000000000000ee" + "00def1ca1fb7fbcdc777520aa7f396b4e015f497ab0000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000044a9059cbb00000000000000" + "0000000000de786877a10dbb7eba25a4da65aecf47654f08ab00000000000000" + "0000000000000000000000000000000000000000000000000f00de786877a10d" + "bb7eba25a4da65aecf47654f08ab000000000000000000000000000000000000" + "0000000000000000000000000010000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000", + ), ) print( build_encoded_multisend( @@ -128,17 +135,19 @@ def test_multisend_encoding(self): build_encoded_multisend( [native_transfer, erc20_transfer], client=self.client ), - "0x8d80ff0a" # MethodID - "0000000000000000000000000000000000000000000000000000000000000020" - "00000000000000000000000000000000000000000000000000000000000000ee" - "00de786877a10dbb7eba25a4da65aecf47654f08ab0000000000000000000000" - "0000000000000000000000000000000000000000100000000000000000000000" - "00000000000000000000000000000000000000000000def1ca1fb7fbcdc77752" - "0aa7f396b4e015f497ab00000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000" - "00000000000000000044a9059cbb000000000000000000000000de786877a10d" - "bb7eba25a4da65aecf47654f08ab000000000000000000000000000000000000" - "000000000000000000000000000f000000000000000000000000000000000000", + bytes.fromhex( + "8d80ff0a" # MethodID + "0000000000000000000000000000000000000000000000000000000000000020" + "00000000000000000000000000000000000000000000000000000000000000ee" + "00de786877a10dbb7eba25a4da65aecf47654f08ab0000000000000000000000" + "0000000000000000000000000000000000000000100000000000000000000000" + "00000000000000000000000000000000000000000000def1ca1fb7fbcdc77752" + "0aa7f396b4e015f497ab00000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000044a9059cbb000000000000000000000000de786877a10d" + "bb7eba25a4da65aecf47654f08ab000000000000000000000000000000000000" + "000000000000000000000000000f000000000000000000000000000000000000", + ), )