Type-safe Python bindings for Ethereum smart contracts!
Used by
Features
Static Python bindings for ethereum smart contracts.
Parses JSON ABIs to create typesafe web3.py contract instances.
Functions have typesafe function parameters and return values.
Functions have transparent exceptions that contains decoded error messages and more.
Smart Contract internal types are exposed as dataclasses.
Contract event interfaces are exposed as typesafe dataclasses.
Helper functions to deploy a given contract.
Helper functions for get_logs_typed and process_receipt_typed to return typesafe dataclass events.
Helper functions for signing, transacting, and waiting for transaction receipts.
This project is a work-in-progress. All code is provided as is and without guarantee.
Install
pip install --upgrade pypechain
For development install instructions, see toplevel INSTALL.md
Packages 📦
Package Name
Version
Description
pypechain
Codegen python interfaces for web3.py contracts.
autoflake
Removes unused imports and unused variables
black
The uncompromising code formatter.
isort
A Python utility / library to sort Python imports.
jinja2
A very fast and expressive template engine.
web3
web3.py
Usage
Pypechain is primarily to be used via the CLI:
❯❯ pypechain -h
usage: pypechain [-h] [--output-dir OUTPUT_DIR] [--line-length LINE_LENGTH] abi_file_path
Generates class files for a given abi.
positional arguments:
abi_file_path Path to the abi JSON file or directory containing multiple JSON files.
options:
-h, --help show this help message and exit
--output-dir OUTPUT_DIR
Path to the directory where files will be generated. Defaults to pypechain_types.
--line-length LINE_LENGTH
Optional argument for the output file's maximum line length. Defaults to 80.
However, you can also run the main script directly from Python:
Pypechain generates a Python module from compiled Solidity code in ABI format.
This enables access to typesafe contract, struct, and event objects, which greatly improves
the developer experience.
Accessing contract balances
Using web3:
from web3 import Web3
web3 = Web3()
base_token_address = "0xSomeAddress"
user_address = "0xUserAddress"# Contract construction takes an ABI filepath string
base_token_contract = web3.eth.contract(
abi=base_contract_abi, address=web3.to_checksum_address(base_token_address)
)
# Arbitrary function arguments and names forces one to examine the ABI JSON to know the values & types# Additionally, the types are not specified as Python types in the ABI
fn_args = [user_address]
fn_kwargs = {}
# HARD TO DISCOVER ALL FUNCTIONS AND THEIR ARGUMENTS
contract_function = base_token_contract.get_function_by_name("balanceOf")(*fn_args, **fn_kwargs)
# The function call also takes arbitrary args and kwargs
call_args = []
call_kwargs = {}
# UNTYPED RETURN VALUE!!
return_values: dict[str, Any] = contract_function.call(*call_args, **call_kwargs)
Using Pypechain generated objects:
from web3 import Web3
from pypechain_types import ERC20MintableContract
web3 = Web3()
base_token_address = "0xSomeAddress"
user_address = "0xUserAddress"# Contracts include a factory function to initialize with your given web3 provider
base_token_contract: ERC20MintableContract = ERC20MintableContract.deploy(w3=web3, signer=user_address)
# balanceOf is a class function, enabling IDE tab-completion, intuitive inspection, typed inputs and typed outputs
user_base_balance: int = base_token_contract.functions.balanceOf(user_address).call()
Understanding contracts
Solidity files can be difficult to read for native Python programmers that have little exposure to smart contract code.
Running pypechain on the compiled ABI from this contract produces code that is more intuitive for Python programmers.
... # imports@dataclassclassSimpleStruct:
"""SimpleStruct struct."""
intVal: int
strVal: str@dataclassclassInnerStruct:
"""InnerStruct struct."""
boolVal: bool@dataclassclassNestedStruct:
"""NestedStruct struct."""
intVal: int
strVal: str
innerStruct: InnerStruct
classReturnTypesMixStructsAndPrimitivesContractFunction(ContractFunction):
"""ContractFunction for the mixStructsAndPrimitives method."""classReturnValues(NamedTuple):
"""The return named tuple for MixStructsAndPrimitives."""
simpleStruct: SimpleStruct
arg2: NestedStruct
arg3: int
name: str
YesOrNo: booldef__call__(self) -> ReturnTypesMixStructsAndPrimitivesContractFunction:
clone = super().__call__()
self.kwargs = clone.kwargs
self.args = clone.args
return self
defcall(
self,
transaction: TxParams | None = None,
block_identifier: BlockIdentifier = "latest",
state_override: CallOverride | None = None,
ccip_read_enabled: bool | None = None,
) -> ReturnValues:
"""returns ReturnValues."""# Define the expected return types from the smart contract call
return_types = [SimpleStruct, NestedStruct, int, str, bool]
# Call the function
raw_values = super().call(transaction, block_identifier, state_override, ccip_read_enabled)
return self.ReturnValues(*rename_returned_types(return_types, raw_values))
classReturnTypesContractFunctions(ContractFunctions):
"""ContractFunctions for the ReturnTypes contract."""
mixStructsAndPrimitives: ReturnTypesMixStructsAndPrimitivesContractFunction
def__init__(
self,
abi: ABI,
w3: "Web3",
address: ChecksumAddress | None = None,
decode_tuples: bool | None = False,
) -> None:
super().__init__(abi, w3, address, decode_tuples)
self.mixStructsAndPrimitives = ReturnTypesMixStructsAndPrimitivesContractFunction.factory(
"mixStructsAndPrimitives",
w3=w3,
contract_abi=abi,
address=address,
decode_tuples=decode_tuples,
function_identifier="mixStructsAndPrimitives",
)
classReturnTypesContract(Contract):
"""A web3.py Contract class for the ReturnTypes contract."""
abi: ABI = returntypes_abi
bytecode: bytes = HexBytes(returntypes_bytecode)
def__init__(self, address: ChecksumAddress | None = None) -> None:
try:
# Initialize parent Contract classsuper().__init__(address=address)
self.functions = ReturnTypesContractFunctions(returntypes_abi, self.w3, address)
except FallbackNotFound:
print("Fallback function not found. Continuing...")
functions: ReturnTypesContractFunctions
@classmethoddefdeploy(cls, w3: Web3, signer: ChecksumAddress) -> Self:
"""Deploys and instance of the contract.
Parameters
----------
w3 : Web3
A web3 instance.
signer : ChecksumAddress
The address to deploy the contract from.
Returns
-------
Self
A deployed instance of the contract.
"""
deployer = cls.factory(w3=w3)
tx_hash = deployer.constructor().transact({"from": signer})
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
deployed_contract = deployer(address=tx_receipt.contractAddress) # type: ignorereturn deployed_contract
@classmethoddeffactory(cls, w3: Web3, class_name: str | None = None, **kwargs: Any) -> Type[Self]:
contract = super().factory(w3, class_name, **kwargs)
contract.functions = ReturnTypesContractFunctions(returntypes_abi, w3, None)
return contract
Tests
We use pytest in our pypechain tests. Pytest, when ran locally, automatically compiles Solidity
using Foundry, as well as running
pypechain on the output abis.
If you run into issues during pytest, run make clean; make build-test to rebuild all solidity
and pypechain types in tests.
We also use pytest-snapshot for some tests to ensure
rendered files are as expected. If any changes are made to rendering that results in failures in snapshots,
run pytest --snapshot-update, ensure the generated files in snapshots/ are as expected, and commit the new
snapshots in snapshots/ as part of the update.
TODO also add in tests compiled via solc. See conftest.py for more information.
FAQs
Codegen python interfaces for web3.py contracts.
We found that pypechain demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Malicious Go packages are impersonating popular libraries to install hidden loader malware on Linux and macOS, targeting developers with obfuscated payloads.
Bybit's $1.46B hack by North Korea's Lazarus Group pushes 2025 crypto losses to $1.6B in just two months, already surpassing all of 2024's $1.49B total.
OpenSSF has published OSPS Baseline, an initiative designed to establish a minimum set of security-related best practices for open source software projects.