Skip to content

Commit

Permalink
Various fixes for pypechain (#142)
Browse files Browse the repository at this point in the history
Breaking changes:
- Function arguments now match the exact function parameter in the abi.

Major changes:
- Fixing a bug with kwargs and function overloading due to mismatched
kwarg key between the abi and the python arg name.
- Adding top level imports for easier importing of contracts.
- Adding `sign_transact_and_wait`, with option to validate the
transaction receipt (i.e., throw an exception if `status == 0`).
- Adjusting exception handling to maintain original exception's `args`
field.
- Fixing #115
- Bug fix for contract functions with multiple instantiations. See
`pypechain/test/overloading/test_overloading.py` for test that showcases
this issue.
- Fixing bug with deep copies of `PypechainCallException`
slundqui authored Oct 16, 2024
1 parent c2c4550 commit 938aedc
Showing 41 changed files with 4,932 additions and 263 deletions.
711 changes: 691 additions & 20 deletions example/types/Example/ExampleContract.py

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions example/types/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Export all types from generated files.
DO NOT EDIT. This file was generated by pypechain v0.0.44.
See documentation at https://github.com/delvtech/pypechain """

# The module name reflects that of the solidity contract,
# which may not adhere to python naming conventions
# pylint: disable=invalid-name


from .Example import ExampleContract
7 changes: 6 additions & 1 deletion pypechain/core/__init__.py
Original file line number Diff line number Diff line change
@@ -2,7 +2,12 @@

from .base_event import BaseEvent, BaseEventArgs
from .combomethod_typed import combomethod_typed
from .contract_call_exception import PypechainCallException, handle_contract_logic_error
from .contract_call_exception import (
FailedTransaction,
PypechainCallException,
check_txn_receipt,
handle_contract_logic_error,
)
from .contract_function import PypechainContractFunction
from .error import ErrorInfo, ErrorParams, PypechainBaseContractErrors, PypechainBaseError
from .utilities import (
117 changes: 112 additions & 5 deletions pypechain/core/contract_call_exception.py
Original file line number Diff line number Diff line change
@@ -2,11 +2,13 @@

from __future__ import annotations

from typing import Any, Generic, Literal, Type, TypeVar, Union
import copy
from typing import Any, Generic, Literal, Type, TypeVar, Union, cast

from eth_typing import BlockNumber
from hexbytes import HexBytes
from web3.exceptions import ContractCustomError, ContractLogicError, ContractPanicError, OffchainLookup
from web3.types import BlockIdentifier, TxParams
from web3.types import BlockIdentifier, TxParams, TxReceipt

from .contract_function import PypechainContractFunction
from .error import PypechainBaseContractErrors
@@ -19,9 +21,15 @@
ContractCallType = Union[Literal["call"], Literal["transact"], Literal["build"]]


class FailedTransaction(Exception):
"""Exception that is thrown when a transaction succeeds, but the status reports failure."""


class PypechainCallException(Exception):
"""Custom contract call exception wrapper that contains additional information on the function call"""

contract_call_type: ContractCallType | None

def __init__(
self,
*args,
@@ -38,7 +46,12 @@ def __init__(
raw_txn: TxParams | None = None,
block_number: BlockNumber | None = None,
):
super().__init__(*args)
# We explicitly define which init we're calling due to multiple inheritance,
# and handle passing in the correct arguments here
exception_args = args + orig_exception.args
if decoded_error is not None:
exception_args += (decoded_error,)
Exception.__init__(self, *exception_args)
self.orig_exception = orig_exception
self.decoded_error = decoded_error
self.decoded_error_name = decoded_error_name
@@ -60,6 +73,36 @@ def __repr__(self):
f"orig_exception={repr(self.orig_exception)})"
)

def __copy__(self):
return PypechainCallException(
*self.args,
orig_exception=self.orig_exception,
decoded_error=self.decoded_error,
decoded_error_name=self.decoded_error_name,
decoded_error_args=self.decoded_error_args,
contract_call_type=self.contract_call_type, # type: ignore
function_name=self.function_name,
fn_args=self.fn_args,
fn_kwargs=self.fn_kwargs,
block_number=self.block_number,
raw_txn=self.raw_txn,
)

def __deepcopy__(self, memo):
return PypechainCallException(
*copy.deepcopy(self.args, memo),
orig_exception=copy.deepcopy(self.orig_exception, memo),
decoded_error=self.decoded_error,
decoded_error_name=self.decoded_error_name,
decoded_error_args=copy.deepcopy(self.decoded_error_args, memo),
contract_call_type=self.contract_call_type, # type: ignore
function_name=self.function_name,
fn_args=copy.deepcopy(self.fn_args, memo),
fn_kwargs=copy.deepcopy(self.fn_kwargs, memo),
block_number=self.block_number,
raw_txn=copy.deepcopy(self.raw_txn, memo),
)


# Subclasses of these exceptions for all 4 types of exceptions

@@ -89,7 +132,10 @@ def __init__(
raw_txn: TxParams | None = None,
block_number: BlockNumber | None = None,
):
super().__init__(
# We explicitly define which init we're calling due to multiple inheritance.
# The PypechainCallException handles filling in the correct args.
PypechainCallException.__init__(
self,
*args,
orig_exception=orig_exception,
decoded_error=decoded_error,
@@ -107,6 +153,18 @@ def __init__(
self.message = orig_exception.message
self.data = orig_exception.data

def __copy__(self):
out = cast(PypechainGenericError, super().__copy__())
out.message = self.message
out.data = self.data
return out

def __deepcopy__(self, memo):
out = cast(PypechainGenericError, super().__deepcopy__(memo))
out.message = self.message
out.data = copy.deepcopy(self.data)
return out


class PypechainContractCustomError(PypechainGenericError[ContractCustomError], ContractCustomError):
"""Instance of `PypechainGenericError` for `ContractCustomError`."""
@@ -226,4 +284,53 @@ def handle_contract_logic_error(
block_number=block_number,
)
case _:
raise TypeError(f"Unexpected error type: {type(err)}")
raise err


def check_txn_receipt(
contract_function: PypechainContractFunction,
tx_hash: HexBytes,
tx_receipt: TxReceipt,
) -> TxReceipt:
"""Check the txn receipt for errors."""
# Error checking when transaction doesn't throw an error, but instead
# has errors in the tx_receipt
block_number = tx_receipt.get("blockNumber")
# Check status here
status = tx_receipt.get("status", None)

error_message = None
if status is None:
error_message = "Receipt did not return status"

if status == 0:
# We use web3 tracing to attempt to get the error message
error_message = "Receipt has status of 0"
try:
# Tracing doesn't exist in typing for some reason.
# Doing this in error checking with try/catch.
trace = contract_function.w3.tracing.trace_transaction(tx_hash) # type: ignore
if len(trace) > 0:
# Trace gives a list of values, the last one should contain the error
error_message = trace[-1].get("error", None)
# If no trace, add back in status == 0 error
if error_message is None:
error_message = "Receipt has status of 0."
# TODO does this need to be BaseException?
except Exception as e: # pylint: disable=broad-exception-caught
# Don't crash in crash reporting
error_message = f"Receipt has status of 0. Error getting trace: {repr(e)}"

if error_message is not None:
# Raise a pypechain error here
raise PypechainCallException(
orig_exception=FailedTransaction(error_message),
contract_call_type="transact",
function_name=contract_function._function_name, # pylint: disable=protected-access
fn_args=contract_function.args,
fn_kwargs=contract_function.kwargs,
raw_txn=None,
block_number=block_number,
)

return tx_receipt
19 changes: 10 additions & 9 deletions pypechain/main.py
Original file line number Diff line number Diff line change
@@ -11,7 +11,9 @@
from typing import NamedTuple, Sequence

from pypechain.render import render_contracts
from pypechain.render.init import render_init_file
from pypechain.utilities.abi import AbiInfo, load_abi_infos_from_file
from pypechain.utilities.format import format_file


def main(argv: Sequence[str] | None = None) -> None:
@@ -72,16 +74,16 @@ def pypechain(

# Since setup directory looks for `pypechain.version`, we make this file first
# Make a pypechain.version file
with open(f"{output_dir}/pypechain.version", "w", encoding="utf-8") as f:
with open(Path(output_dir) / "pypechain.version", "w", encoding="utf-8") as f:
f.write(f"pypechain == {importlib.metadata.version('pypechain')}")

# Now process all gathered files
render_contracts(abi_infos, output_dir, line_length, apply_formatting, parallel=parallel)
file_outputs = render_contracts(abi_infos, output_dir, line_length, apply_formatting, parallel=parallel)

# Make an empty __init__.py file
# render_init_file(output_dir, file_outputs, line_length)
with open(f"{output_dir}/__init__.py", "w", encoding="utf-8") as f:
pass
# Make the top level __init__.py file
render_init_file(Path(output_dir), file_outputs)
if apply_formatting is True:
format_file(Path(output_dir) / "__init__.py", line_length, remove_unused_imports=False)


def gather_json_files(directory: str) -> list:
@@ -132,6 +134,7 @@ def namespace_to_args(namespace: argparse.Namespace) -> Args:
def parse_arguments(argv: Sequence[str] | None = None) -> Args:
"""Parse input arguments."""
parser = argparse.ArgumentParser(description="Generates class files for a given abi.")

parser.add_argument(
"abi_file_path",
help="Path to the abi JSON file or directory containing multiple JSON files.",
@@ -148,11 +151,9 @@ def parse_arguments(argv: Sequence[str] | None = None) -> Args:
default=120,
help="Optional argument for the output file's maximum line length. Defaults to 120.",
)
# TODO apply-formatting won't work when calling with `--apply-formatting=False`
# https://github.com/delvtech/pypechain/issues/115
parser.add_argument(
"--apply-formatting",
type=bool,
action=argparse.BooleanOptionalAction,
default=True,
help="Optional argument to apply formatting to each file. Defaults to True.",
)
12 changes: 4 additions & 8 deletions pypechain/render/contract.py
Original file line number Diff line number Diff line change
@@ -267,8 +267,6 @@ def render_contract_file(contract_info: ContractInfo) -> str | None:

has_bytecode = bool(contract_info.bytecode)
has_events = bool(len(event_datas))
# if any function has overloading
has_overloading = any(function_data["has_overloading"] for function_data in function_datas.values())

structs_used = get_structs_for_abi(contract_info.abi)
structs_filenames = list({struct.contract_name for struct in structs_used if struct.contract_name is not None})
@@ -313,7 +311,6 @@ def render_contract_file(contract_info: ContractInfo) -> str | None:
)

# if any function has overloading
has_overloading = any(function_data["has_overloading"] for function_data in function_datas.values())
has_multiple_return_values = any(
function_data["has_multiple_return_values"] for function_data in function_datas.values()
)
@@ -325,7 +322,6 @@ def render_contract_file(contract_info: ContractInfo) -> str | None:
structs_used=structs_used,
structs_filenames=structs_filenames,
structs_without_filenames=structs_without_filenames,
has_overloading=has_overloading,
has_multiple_return_values=has_multiple_return_values,
has_bytecode=has_bytecode,
functions_block=functions_block,
@@ -441,8 +437,8 @@ def get_function_datas(abi: ABI) -> GetFunctionDatasReturnValue:
abi_constructor = get_abi_constructor(abi)
constructor_data: SignatureData | None = (
{
"input_names_and_types": get_input_names_and_types(abi_constructor),
"input_names": get_input_names(abi_constructor),
"input_names_and_types": get_input_names_and_types(abi_constructor, remove_leading_underscore=True),
"input_names": get_input_names(abi_constructor, remove_leading_underscore=True),
"input_types": get_input_types(abi_constructor),
"outputs": get_output_names(abi_constructor),
"output_types": get_output_names_and_types(abi_constructor),
@@ -458,8 +454,8 @@ def get_function_datas(abi: ABI) -> GetFunctionDatasReturnValue:
name = abi_function.get("name", "")
name = re.sub(r"\W|^(?=\d)", "_", name)
signature_data: SignatureData = {
"input_names_and_types": get_input_names_and_types(abi_function),
"input_names": get_input_names(abi_function),
"input_names_and_types": get_input_names_and_types(abi_function, remove_leading_underscore=False),
"input_names": get_input_names(abi_function, remove_leading_underscore=False),
"input_types": get_input_types(abi_function),
"outputs": get_output_names(abi_function),
"output_types": get_output_types(abi_function),
10 changes: 9 additions & 1 deletion pypechain/render/render.py
Original file line number Diff line number Diff line change
@@ -114,6 +114,7 @@ def render_contract(
A list of filenames and definitions for the generated Contract and Types files.
"""
file_outputs: list[RenderOutput] = []
top_level_file_outputs: list[RenderOutput] = []
contract_dir = Path(output_dir) / contract_info.contract_name
os.makedirs(contract_dir)
file_path = Path(contract_dir)
@@ -132,6 +133,13 @@ def render_contract(
definitions=[f"{contract_info.contract_name}Contract"],
)
)
# We also build the top level __init__.py file
top_level_file_outputs.append(
RenderOutput(
filename=f"{contract_info.contract_name}",
definitions=[f"{contract_info.contract_name}Contract"],
)
)

rendered_types_code = render_types_file(contract_info)
if rendered_types_code:
@@ -158,4 +166,4 @@ def render_contract(
if apply_formatting is True:
format_file(contract_dir / "__init__.py", line_length, remove_unused_imports=False)

return file_outputs
return top_level_file_outputs
4 changes: 2 additions & 2 deletions pypechain/templates/contract.py/base.py.jinja2
Original file line number Diff line number Diff line change
@@ -45,7 +45,7 @@ from typing_extensions import Self
from web3 import Web3
from web3.contract.contract import Contract, ContractFunction, ContractFunctions, ContractConstructor
from web3.contract.contract import ContractEvent, ContractEvents
from web3.types import BlockIdentifier, StateOverride, TxParams, Nonce, EventData
from web3.types import BlockIdentifier, StateOverride, TxParams, Nonce, EventData, TxReceipt
from web3._utils.filters import LogFilter
import copy

@@ -62,7 +62,6 @@ from ..{{contract_name}} import {{contract_name}}Contract
{% endfor %}

{% if has_events %}
from web3.types import TxReceipt
from web3.logs import WARN
from web3._utils.events import EventLogErrorFlags
from pypechain.core import BaseEventArgs
@@ -91,6 +90,7 @@ from pypechain.core import (
PypechainContractLogicError,
PypechainBaseContractErrors,
handle_contract_logic_error,
check_txn_receipt,
)


72 changes: 70 additions & 2 deletions pypechain/templates/contract.py/functions.py.jinja2
Original file line number Diff line number Diff line change
@@ -79,6 +79,24 @@ class {{contract_function_class_name}}{{i}}(PypechainContractFunction):
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class={{contract_name}}ContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
@@ -148,6 +166,53 @@ class {{contract_function_class_name}}{{i}}(PypechainContractFunction):
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.

Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.

Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


{% endfor %}
class {{contract_function_class_name}}(PypechainContractFunction):
"""ContractFunction for the {{function_data.name}} method."""
@@ -193,8 +258,11 @@ class {{contract_function_class_name}}(PypechainContractFunction):
) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
{% for i in range(function_data.signature_datas|length) %}
{{contract_function_class_name}}{{i}}._type_signature: {{contract_function_class_name}}{{i}}.factory(
"{{contract_function_class_name}}{{i}}",
74 changes: 71 additions & 3 deletions pypechain/test/deploy_linking/types/Contract/ContractContract.py
Original file line number Diff line number Diff line change
@@ -42,11 +42,12 @@
from typing_extensions import Self
from web3 import Web3
from web3.contract.contract import Contract, ContractConstructor, ContractFunctions
from web3.types import BlockIdentifier, StateOverride, TxParams
from web3.types import BlockIdentifier, StateOverride, TxParams, TxReceipt

from pypechain.core import (
PypechainBaseContractErrors,
PypechainContractFunction,
check_txn_receipt,
dataclass_to_tuple,
expand_struct_type_str,
get_arg_type_names,
@@ -108,6 +109,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=ContractContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -178,6 +197,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class ContractAddContractFunction(PypechainContractFunction):
"""ContractFunction for the add method."""
@@ -220,8 +285,11 @@ def __call__(self, *args, **kwargs) -> ContractAddContractFunction: # type: ign
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
ContractAddContractFunction0._type_signature: ContractAddContractFunction0.factory(
"ContractAddContractFunction0", **kwargs
),
74 changes: 71 additions & 3 deletions pypechain/test/deploy_linking/types/MyLibrary/MyLibraryContract.py
Original file line number Diff line number Diff line change
@@ -42,11 +42,12 @@
from typing_extensions import Self
from web3 import Web3
from web3.contract.contract import Contract, ContractConstructor, ContractFunctions
from web3.types import BlockIdentifier, StateOverride, TxParams
from web3.types import BlockIdentifier, StateOverride, TxParams, TxReceipt

from pypechain.core import (
PypechainBaseContractErrors,
PypechainContractFunction,
check_txn_receipt,
dataclass_to_tuple,
expand_struct_type_str,
get_arg_type_names,
@@ -106,6 +107,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=MyLibraryContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -176,6 +195,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class MyLibraryAddContractFunction(PypechainContractFunction):
"""ContractFunction for the add method."""
@@ -218,8 +283,11 @@ def __call__(self, *args, **kwargs) -> MyLibraryAddContractFunction: # type: ig
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
MyLibraryAddContractFunction0._type_signature: MyLibraryAddContractFunction0.factory(
"MyLibraryAddContractFunction0", **kwargs
),
12 changes: 12 additions & 0 deletions pypechain/test/deploy_linking/types/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""Export all types from generated files.
DO NOT EDIT. This file was generated by pypechain v0.0.44.
See documentation at https://github.com/delvtech/pypechain """

# The module name reflects that of the solidity contract,
# which may not adhere to python naming conventions
# pylint: disable=invalid-name


from .Contract import ContractContract
from .MyLibrary import MyLibraryContract
Original file line number Diff line number Diff line change
@@ -42,11 +42,12 @@
from typing_extensions import Self
from web3 import Web3
from web3.contract.contract import Contract, ContractConstructor, ContractFunctions
from web3.types import BlockIdentifier, StateOverride, TxParams
from web3.types import BlockIdentifier, StateOverride, TxParams, TxReceipt

from pypechain.core import (
PypechainBaseContractErrors,
PypechainContractFunction,
check_txn_receipt,
dataclass_to_tuple,
expand_struct_type_str,
get_arg_type_names,
@@ -106,6 +107,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=ConstructorNoArgsContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -176,6 +195,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class ConstructorNoArgsNameContractFunction(PypechainContractFunction):
"""ContractFunction for the name method."""
@@ -218,8 +283,11 @@ def __call__(self, *args, **kwargs) -> ConstructorNoArgsNameContractFunction: #
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
ConstructorNoArgsNameContractFunction0._type_signature: ConstructorNoArgsNameContractFunction0.factory(
"ConstructorNoArgsNameContractFunction0", **kwargs
),
@@ -271,6 +339,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=ConstructorNoArgsContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -341,6 +427,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class ConstructorNoArgsSetNameContractFunction(PypechainContractFunction):
"""ContractFunction for the setName method."""
@@ -357,7 +489,7 @@ class ConstructorNoArgsSetNameContractFunction(PypechainContractFunction):
_functions: dict[str, PypechainContractFunction]

@overload
def __call__(self, name: str) -> ConstructorNoArgsSetNameContractFunction0: # type: ignore
def __call__(self, _name: str) -> ConstructorNoArgsSetNameContractFunction0: # type: ignore
...

def __call__(self, *args, **kwargs) -> ConstructorNoArgsSetNameContractFunction: # type: ignore
@@ -383,8 +515,11 @@ def __call__(self, *args, **kwargs) -> ConstructorNoArgsSetNameContractFunction:
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
ConstructorNoArgsSetNameContractFunction0._type_signature: ConstructorNoArgsSetNameContractFunction0.factory(
"ConstructorNoArgsSetNameContractFunction0", **kwargs
),
Original file line number Diff line number Diff line change
@@ -42,11 +42,12 @@
from typing_extensions import Self
from web3 import Web3
from web3.contract.contract import Contract, ContractConstructor, ContractFunctions
from web3.types import BlockIdentifier, StateOverride, TxParams
from web3.types import BlockIdentifier, StateOverride, TxParams, TxReceipt

from pypechain.core import (
PypechainBaseContractErrors,
PypechainContractFunction,
check_txn_receipt,
dataclass_to_tuple,
expand_struct_type_str,
get_arg_type_names,
@@ -106,6 +107,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=ConstructorWithArgsContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -176,6 +195,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class ConstructorWithArgsNameContractFunction(PypechainContractFunction):
"""ContractFunction for the name method."""
@@ -218,8 +283,11 @@ def __call__(self, *args, **kwargs) -> ConstructorWithArgsNameContractFunction:
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
ConstructorWithArgsNameContractFunction0._type_signature: ConstructorWithArgsNameContractFunction0.factory(
"ConstructorWithArgsNameContractFunction0", **kwargs
),
@@ -271,6 +339,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=ConstructorWithArgsContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -341,6 +427,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class ConstructorWithArgsSetNameContractFunction(PypechainContractFunction):
"""ContractFunction for the setName method."""
@@ -357,7 +489,7 @@ class ConstructorWithArgsSetNameContractFunction(PypechainContractFunction):
_functions: dict[str, PypechainContractFunction]

@overload
def __call__(self, name: str) -> ConstructorWithArgsSetNameContractFunction0: # type: ignore
def __call__(self, _name: str) -> ConstructorWithArgsSetNameContractFunction0: # type: ignore
...

def __call__(self, *args, **kwargs) -> ConstructorWithArgsSetNameContractFunction: # type: ignore
@@ -383,8 +515,11 @@ def __call__(self, *args, **kwargs) -> ConstructorWithArgsSetNameContractFunctio
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
ConstructorWithArgsSetNameContractFunction0._type_signature: ConstructorWithArgsSetNameContractFunction0.factory(
"ConstructorWithArgsSetNameContractFunction0", **kwargs
),
Original file line number Diff line number Diff line change
@@ -42,11 +42,12 @@
from typing_extensions import Self
from web3 import Web3
from web3.contract.contract import Contract, ContractConstructor, ContractFunctions
from web3.types import BlockIdentifier, StateOverride, TxParams
from web3.types import BlockIdentifier, StateOverride, TxParams, TxReceipt

from pypechain.core import (
PypechainBaseContractErrors,
PypechainContractFunction,
check_txn_receipt,
dataclass_to_tuple,
expand_struct_type_str,
get_arg_type_names,
@@ -111,6 +112,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=ConstructorWithStructArgsContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -181,6 +200,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class ConstructorWithStructArgsNameContractFunction(PypechainContractFunction):
"""ContractFunction for the name method."""
@@ -223,8 +288,11 @@ def __call__(self, *args, **kwargs) -> ConstructorWithStructArgsNameContractFunc
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
ConstructorWithStructArgsNameContractFunction0._type_signature: ConstructorWithStructArgsNameContractFunction0.factory(
"ConstructorWithStructArgsNameContractFunction0", **kwargs
),
@@ -276,6 +344,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=ConstructorWithStructArgsContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -346,6 +432,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class ConstructorWithStructArgsSetNameContractFunction(PypechainContractFunction):
"""ContractFunction for the setName method."""
@@ -362,7 +494,7 @@ class ConstructorWithStructArgsSetNameContractFunction(PypechainContractFunction
_functions: dict[str, PypechainContractFunction]

@overload
def __call__(self, name: str) -> ConstructorWithStructArgsSetNameContractFunction0: # type: ignore
def __call__(self, _name: str) -> ConstructorWithStructArgsSetNameContractFunction0: # type: ignore
...

def __call__(self, *args, **kwargs) -> ConstructorWithStructArgsSetNameContractFunction: # type: ignore
@@ -388,8 +520,11 @@ def __call__(self, *args, **kwargs) -> ConstructorWithStructArgsSetNameContractF
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
ConstructorWithStructArgsSetNameContractFunction0._type_signature: ConstructorWithStructArgsSetNameContractFunction0.factory(
"ConstructorWithStructArgsSetNameContractFunction0", **kwargs
),
@@ -446,6 +581,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=ConstructorWithStructArgsContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -516,6 +669,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class ConstructorWithStructArgsThingContractFunction(PypechainContractFunction):
"""ContractFunction for the thing method."""
@@ -558,8 +757,11 @@ def __call__(self, *args, **kwargs) -> ConstructorWithStructArgsThingContractFun
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
ConstructorWithStructArgsThingContractFunction0._type_signature: ConstructorWithStructArgsThingContractFunction0.factory(
"ConstructorWithStructArgsThingContractFunction0", **kwargs
),
147 changes: 141 additions & 6 deletions pypechain/test/deployment/types/NoConstructor/NoConstructorContract.py
Original file line number Diff line number Diff line change
@@ -42,11 +42,12 @@
from typing_extensions import Self
from web3 import Web3
from web3.contract.contract import Contract, ContractConstructor, ContractFunctions
from web3.types import BlockIdentifier, StateOverride, TxParams
from web3.types import BlockIdentifier, StateOverride, TxParams, TxReceipt

from pypechain.core import (
PypechainBaseContractErrors,
PypechainContractFunction,
check_txn_receipt,
dataclass_to_tuple,
expand_struct_type_str,
get_arg_type_names,
@@ -106,6 +107,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=NoConstructorContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -176,6 +195,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class NoConstructorNameContractFunction(PypechainContractFunction):
"""ContractFunction for the name method."""
@@ -218,8 +283,11 @@ def __call__(self, *args, **kwargs) -> NoConstructorNameContractFunction: # typ
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
NoConstructorNameContractFunction0._type_signature: NoConstructorNameContractFunction0.factory(
"NoConstructorNameContractFunction0", **kwargs
),
@@ -271,6 +339,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=NoConstructorContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -341,6 +427,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class NoConstructorSetNameContractFunction(PypechainContractFunction):
"""ContractFunction for the setName method."""
@@ -357,7 +489,7 @@ class NoConstructorSetNameContractFunction(PypechainContractFunction):
_functions: dict[str, PypechainContractFunction]

@overload
def __call__(self, name: str) -> NoConstructorSetNameContractFunction0: # type: ignore
def __call__(self, _name: str) -> NoConstructorSetNameContractFunction0: # type: ignore
...

def __call__(self, *args, **kwargs) -> NoConstructorSetNameContractFunction: # type: ignore
@@ -383,8 +515,11 @@ def __call__(self, *args, **kwargs) -> NoConstructorSetNameContractFunction: #
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
NoConstructorSetNameContractFunction0._type_signature: NoConstructorSetNameContractFunction0.factory(
"NoConstructorSetNameContractFunction0", **kwargs
),
14 changes: 14 additions & 0 deletions pypechain/test/deployment/types/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Export all types from generated files.
DO NOT EDIT. This file was generated by pypechain v0.0.44.
See documentation at https://github.com/delvtech/pypechain """

# The module name reflects that of the solidity contract,
# which may not adhere to python naming conventions
# pylint: disable=invalid-name


from .ConstructorNoArgs import ConstructorNoArgsContract
from .ConstructorWithArgs import ConstructorWithArgsContract
from .ConstructorWithStructArgs import ConstructorWithStructArgsContract
from .NoConstructor import NoConstructorContract
216 changes: 209 additions & 7 deletions pypechain/test/errors/types/Errors/ErrorsContract.py
Original file line number Diff line number Diff line change
@@ -42,12 +42,13 @@
from typing_extensions import Self
from web3 import Web3
from web3.contract.contract import Contract, ContractConstructor, ContractFunctions
from web3.types import BlockIdentifier, StateOverride, TxParams
from web3.types import BlockIdentifier, StateOverride, TxParams, TxReceipt

from pypechain.core import (
PypechainBaseContractErrors,
PypechainBaseError,
PypechainContractFunction,
check_txn_receipt,
dataclass_to_tuple,
expand_struct_type_str,
get_arg_type_names,
@@ -105,6 +106,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=ErrorsContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -175,6 +194,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class ErrorsRevertWithErrorOneContractFunction(PypechainContractFunction):
"""ContractFunction for the revertWithErrorOne method."""
@@ -217,8 +282,11 @@ def __call__(self, *args, **kwargs) -> ErrorsRevertWithErrorOneContractFunction:
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
ErrorsRevertWithErrorOneContractFunction0._type_signature: ErrorsRevertWithErrorOneContractFunction0.factory(
"ErrorsRevertWithErrorOneContractFunction0", **kwargs
),
@@ -270,6 +338,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=ErrorsContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -340,6 +426,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class ErrorsRevertWithErrorThreeContractFunction(PypechainContractFunction):
"""ContractFunction for the revertWithErrorThree method."""
@@ -382,8 +514,11 @@ def __call__(self, *args, **kwargs) -> ErrorsRevertWithErrorThreeContractFunctio
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
ErrorsRevertWithErrorThreeContractFunction0._type_signature: ErrorsRevertWithErrorThreeContractFunction0.factory(
"ErrorsRevertWithErrorThreeContractFunction0", **kwargs
),
@@ -435,6 +570,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=ErrorsContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -505,6 +658,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class ErrorsRevertWithErrorTwoContractFunction(PypechainContractFunction):
"""ContractFunction for the revertWithErrorTwo method."""
@@ -547,8 +746,11 @@ def __call__(self, *args, **kwargs) -> ErrorsRevertWithErrorTwoContractFunction:
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
ErrorsRevertWithErrorTwoContractFunction0._type_signature: ErrorsRevertWithErrorTwoContractFunction0.factory(
"ErrorsRevertWithErrorTwoContractFunction0", **kwargs
),
11 changes: 11 additions & 0 deletions pypechain/test/errors/types/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Export all types from generated files.
DO NOT EDIT. This file was generated by pypechain v0.0.44.
See documentation at https://github.com/delvtech/pypechain """

# The module name reflects that of the solidity contract,
# which may not adhere to python naming conventions
# pylint: disable=invalid-name


from .Errors import ErrorsContract
214 changes: 208 additions & 6 deletions pypechain/test/events/types/Events/EventsContract.py
Original file line number Diff line number Diff line change
@@ -51,6 +51,7 @@
BaseEventArgs,
PypechainBaseContractErrors,
PypechainContractFunction,
check_txn_receipt,
combomethod_typed,
dataclass_to_tuple,
expand_struct_type_str,
@@ -113,6 +114,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=EventsContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -183,6 +202,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class EventsEmitNoEventsContractFunction(PypechainContractFunction):
"""ContractFunction for the emitNoEvents method."""
@@ -225,8 +290,11 @@ def __call__(self, *args, **kwargs) -> EventsEmitNoEventsContractFunction: # ty
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
EventsEmitNoEventsContractFunction0._type_signature: EventsEmitNoEventsContractFunction0.factory(
"EventsEmitNoEventsContractFunction0", **kwargs
),
@@ -278,6 +346,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=EventsContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -348,6 +434,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class EventsEmitOneEventContractFunction(PypechainContractFunction):
"""ContractFunction for the emitOneEvent method."""
@@ -390,8 +522,11 @@ def __call__(self, *args, **kwargs) -> EventsEmitOneEventContractFunction: # ty
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
EventsEmitOneEventContractFunction0._type_signature: EventsEmitOneEventContractFunction0.factory(
"EventsEmitOneEventContractFunction0", **kwargs
),
@@ -443,6 +578,24 @@ def transact(self, transaction: TxParams | None = None) -> HexBytes:
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def estimate_gas(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier | None = None,
state_override: StateOverride | None = None,
) -> int:
try:
return super().estimate_gas(transaction, block_identifier, state_override)
except Exception as err: # pylint disable=broad-except
raise handle_contract_logic_error(
contract_function=self,
errors_class=EventsContractErrors,
err=err,
contract_call_type="build",
transaction=transaction,
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def build_transaction(self, transaction: TxParams | None = None) -> TxParams:
try:
return super().build_transaction(transaction)
@@ -513,6 +666,52 @@ def sign_and_transact(self, account: LocalAccount, transaction: TxParams | None
block_identifier="pending", # race condition here, best effort to get block of txn.
) from err

def sign_transact_and_wait(
self,
account: LocalAccount,
transaction: TxParams | None = None,
timeout: float | None = None,
poll_latency: float | None = None,
validate_transaction: bool = False,
) -> TxReceipt:
"""Convenience method for signing and sending a transaction using the provided account.
Arguments
---------
account : LocalAccount
The account to use for signing and sending the transaction.
transaction : TxParams | None, optional
The transaction parameters to use for sending the transaction.
timeout: float, optional
The number of seconds to wait for the transaction to be mined. Defaults to 120.
poll_latency: float, optional
The number of seconds to wait between polling for the transaction receipt. Defaults to 0.1.
validate_transaction: bool, optional
Whether to validate the transaction. If True, will throw an exception if the resulting
tx_receipt returned a failure status.
Returns
-------
HexBytes
The transaction hash.
"""

# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments

if timeout is None:
timeout = 120
if poll_latency is None:
poll_latency = 0.1

tx_hash = self.sign_and_transact(account, transaction)
tx_receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
# Check the receipt, throwing an error if status == 0
if validate_transaction:
return check_txn_receipt(self, tx_hash, tx_receipt)
else:
return tx_receipt


class EventsEmitTwoEventsContractFunction(PypechainContractFunction):
"""ContractFunction for the emitTwoEvents method."""
@@ -555,8 +754,11 @@ def __call__(self, *args, **kwargs) -> EventsEmitTwoEventsContractFunction: # t
def factory(cls, class_name: str, **kwargs: Any) -> Self:
out = super().factory(class_name, **kwargs)

# We initialize our overridden functions here
cls._functions = {
# We initialize our overridden functions here.
# Note that we use the initialized object to ensure each function
# is attached to the instanciated object
# (attached to a specific web3 and contract address)
out._functions = {
EventsEmitTwoEventsContractFunction0._type_signature: EventsEmitTwoEventsContractFunction0.factory(
"EventsEmitTwoEventsContractFunction0", **kwargs
),
11 changes: 11 additions & 0 deletions pypechain/test/events/types/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Export all types from generated files.
DO NOT EDIT. This file was generated by pypechain v0.0.44.
See documentation at https://github.com/delvtech/pypechain """

# The module name reflects that of the solidity contract,
# which may not adhere to python naming conventions
# pylint: disable=invalid-name


from .Events import EventsContract

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"id": "061ddf2787ee6210a6e7bde105021663",
"id": "6286db3c16374e26279108507fea7ac4",
"source_id_to_path": {
"0": "pypechain/test/overloading/contracts/OverloadedMethods.sol"
},
40 changes: 24 additions & 16 deletions pypechain/test/overloading/contracts/OverloadedMethods.sol
Original file line number Diff line number Diff line change
@@ -4,8 +4,8 @@ pragma solidity ^0.8.0;
contract OverloadedMethods {

struct SimpleStruct{
string strVal;
uint intVal;
string _strVal;
uint _intVal;
}

struct NestedStruct{
@@ -14,39 +14,47 @@ contract OverloadedMethods {
SimpleStruct simpleStruct;
}

// Function doesn't accept any parameters, returns a uint
function doSomething() public pure returns (uint) {
return 2;
// Function doesn't accept any parameters, returns the address of the contract
function doSomething() public view returns (address) {
return address(this);
}

// Function accepts an integer, returns a uint
function doSomething(uint x) public pure returns (uint) {
return x * 2;
function doSomething(uint _x) public pure returns (uint) {
return _x * 2;
}

// Overloaded version accepts a string, returns a string
function doSomething(string memory s) public pure returns (string memory) {
return s;
function doSomething(string memory _s) public pure returns (string memory) {
return _s;
}

// Another overloaded version accepts two integers, returns a named uint
function doSomething(uint x, uint y) public pure returns (uint added) {
return x / y;
function doSomething(uint _x, uint _y) public pure returns (uint added) {
return _x / _y;
}

// Another overloaded version accepts an integer and a string, returns both unchanged
function doSomething(
uint x,
string memory s
uint _x,
string memory _s
) public pure returns (uint int_input, string memory) {
return (x, s);
return (_x, _s);
}

// Another overloaded version uses same varible names but types are different
function doSomething(
string memory _x,
uint _s
) public pure returns (string memory, uint int_input) {
return (_x, _s);
}

// Another overloaded version accepts a struct, returns unchanged
function doSomething(
SimpleStruct memory simpleStruct
SimpleStruct memory _simpleStruct
) public pure returns (SimpleStruct memory) {
return SimpleStruct({strVal: simpleStruct.strVal, intVal: simpleStruct.intVal});
return SimpleStruct({_strVal: _simpleStruct._strVal, _intVal: _simpleStruct._intVal});
}

// Overloaded vec of structs as input
39 changes: 37 additions & 2 deletions pypechain/test/overloading/test_overloading.py
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ def test_overloading(self, w3):
y = 1

result = deployed_contract.functions.doSomething().call()
assert result == 2
assert result == deployed_contract.address

result = deployed_contract.functions.doSomething(s).call()
assert result == "test string"
@@ -46,18 +46,40 @@ def test_overloading(self, w3):

# Test kwargs, we pass arguments reversed, but with kwargs
# so we still expect the same result as above
result = deployed_contract.functions.doSomething(y=y, x=x).call()
result = deployed_contract.functions.doSomething(_y=y, _x=x).call()
# Expected result is integer division
assert result == 2 // 1

result = deployed_contract.functions.doSomething(x, s).call()
assert isinstance(result, deployed_contract.functions.doSomething(x, s).ReturnValues)
assert result == deployed_contract.functions.doSomething(x, s).ReturnValues(x, s)

# Test kwargs, we pass arguments reversed, but with kwargs
# so we still expect the same result as above
result = deployed_contract.functions.doSomething(_s=s, _x=x).call()
assert isinstance(result, deployed_contract.functions.doSomething(x, s).ReturnValues)
assert result == deployed_contract.functions.doSomething(x, s).ReturnValues(x, s)

# Test remapped names but different types
result = deployed_contract.functions.doSomething(s, x).call()
assert isinstance(result, deployed_contract.functions.doSomething(s, x).ReturnValues)
assert result == deployed_contract.functions.doSomething(s, x).ReturnValues(s, x)

# Test kwargs, we pass arguments reversed, but with kwargs
# so we still expect the same result as above
result = deployed_contract.functions.doSomething(_s=x, _x=s).call()
assert isinstance(result, deployed_contract.functions.doSomething(s, x).ReturnValues)
assert result == deployed_contract.functions.doSomething(s, x).ReturnValues(s, x)

result = deployed_contract.functions.doSomething(OverloadedMethodsTypes.SimpleStruct(s, x)).call()
assert isinstance(result, OverloadedMethodsTypes.SimpleStruct)
assert result == OverloadedMethodsTypes.SimpleStruct(s, x)

# Test kwargs with structs
result = deployed_contract.functions.doSomething(_simpleStruct=OverloadedMethodsTypes.SimpleStruct(s, x)).call()
assert isinstance(result, OverloadedMethodsTypes.SimpleStruct)
assert result == OverloadedMethodsTypes.SimpleStruct(s, x)

result = deployed_contract.functions.doSomething(
[
OverloadedMethodsTypes.SimpleStruct(s, x),
@@ -89,3 +111,16 @@ def test_overloading(self, w3):
with pytest.raises(MismatchedABI) as err:
result = deployed_contract.functions.doSomething(x, y, s).call() # type: ignore
assert "Could not identify the intended function with name `doSomething`" in str(err.value)

def test_factory(self, w3):
"""Tests creating multiple contracts with the same object"""
# Deploy two contracts
deployed_contract_1 = OverloadedMethodsContract.deploy(w3=w3, account=w3.eth.accounts[0])
deployed_contract_2 = OverloadedMethodsContract.deploy(w3=w3, account=w3.eth.accounts[0])

# Function overload with no arguments returns the address
# Ensure the referenced contract is actually the contract being called
result = deployed_contract_1.functions.doSomething().call()
assert result == deployed_contract_1.address
result = deployed_contract_2.functions.doSomething().call()
assert result == deployed_contract_2.address
Loading

0 comments on commit 938aedc

Please sign in to comment.