Source code for eth_defi.deploy

"""Deploy any precompiled contract.

`See Github for available contracts <https://github.com/tradingstrategy-ai/web3-ethereum-defi/tree/master/eth_defi/abi>`_.
"""
from pathlib import Path
from shutil import which
from typing import Dict, TypeAlias, Union

from eth_typing import HexAddress
from web3 import Web3
from web3.contract import Contract

from eth_defi.abi import get_contract

#: Manage internal registry of deployed contracts
#:
#: Lower case address -> Contract mapping.
ContractRegistry: TypeAlias = Dict[str, Contract]


[docs]class ContractDeploymentFailed(Exception): """Did not get successful tx receipt from a deployment."""
[docs] def __init__(self, tx_hash, msg): super().__init__(msg) self.tx_hash = tx_hash
[docs]def deploy_contract( web3: Web3, contract: Union[str, Contract], deployer: str, *constructor_args, register_for_tracing=True, ) -> Contract: """Deploys a new contract from ABI file. A generic helper function to deploy any contract. Example: .. code-block:: python token = deploy_contract(web3, deployer, "ERC20Mock.json", name, symbol, supply) print(f"Deployed ERC-20 token at {token.address}") If you need to verify the deployed contract use :py:func:`eth_defi.foundry.forge.deploy_contract_with_forge`. :param web3: Web3 instance :param contract: Contract file path as string or contract proxy class :param deployer: Deployer account :param constructor_args: Other arguments to pass to the contract's constructor :param register_for_tracing: Make the symbolic contract information available on web3 instance. See :py:func:`get_contract_registry` :raise ContractDeploymentFailed: In the case we could not deploy the contract. :return: Contract proxy instance """ if isinstance(contract, str): Contract = get_contract(web3, contract) # Used in trace.py contract_name = contract.replace(".json", "") else: Contract = contract contract_name = None tx_hash = Contract.constructor(*constructor_args).transact({"from": deployer}) tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash) if tx_receipt["status"] != 1: raise ContractDeploymentFailed(tx_hash, f"Contract {contract_name} deployment failed with args {constructor_args}, tx hash is {tx_hash.hex()}") instance = Contract(address=tx_receipt["contractAddress"]) if register_for_tracing: instance.name = contract_name register_contract(web3, tx_receipt["contractAddress"], instance) return instance
[docs]def get_or_create_contract_registry(web3: Web3) -> ContractRegistry: """Get a contract registry associated with a Web3 connection. - Only relevant for test sessions - Assumes one web3 instance per test - Useful to make traces symbolic in :py:mod:`eth_defi.trace` :param web3: Web3 test session :return: Mapping of address -> deployed contract instance """ if not hasattr(web3, "contract_registry"): web3.contract_registry = {} return web3.contract_registry
[docs]def register_contract(web3, address: HexAddress, instance: Contract): """Register a contract for tracing. See :py:func:`deploy_contract`. """ assert type(address) == str, f"address is {type(address)}, expected str" registry = get_or_create_contract_registry(web3) registry[address.lower()] = instance
[docs]def get_registered_contract(web3, address: str) -> Contract: """Get a contract that was deployed with the registry. - Resolve a symbolic contract information based on the contract address and our contract registry - See :py:func:`eth_defi.deploy.deploy_contract` how to deploy a registered contract Example: .. code-block:: python from eth_defi.deploy import get_registered_contract contract = get_registered_contract(web3, "0x1613beb3b2c4f22ee086b2b38c1476a3ce7f78e8") assert contract.name == "VaultSpecificGenericAdapter" :param address: Contract address as a hex string :return: The known Contract instance at the registry or `None` if the contract was not registered/deployed through registry mechanism. """ assert type(address) == str registry = get_or_create_contract_registry(web3) return registry.get(address.lower())