class AsyncNet(Module): is_async = True _listening: Method[Callable[[], Awaitable[bool]]] = Method( RPC.net_listening, mungers=[default_root_munger], ) _peer_count: Method[Callable[[], Awaitable[int]]] = Method( RPC.net_peerCount, mungers=[default_root_munger], ) _version: Method[Callable[[], Awaitable[str]]] = Method( RPC.net_version, mungers=[default_root_munger], ) @property async def listening(self) -> bool: return await self._listening() @property async def peer_count(self) -> int: return await self._peer_count() @property async def version(self) -> str: return await self._version()
def test_empty_mungers_for_property_with_no_input_parameters(empty): method = Method( is_property=True, mungers=empty, json_rpc_method='eth_method', ) assert method.input_munger(object(), [], {}) == ()
def test_attach_methods_to_module(web3_with_external_modules): w3 = web3_with_external_modules w3.module1.attach_methods({ # set `property1` on `module1` with `eth_chainId` RPC endpoint 'property1': Method('eth_chainId', is_property=True), # set `method1` on `module1` with `eth_getBalance` RPC endpoint 'method1': Method('eth_getBalance'), }) assert w3.eth.chain_id == 131277322940537 assert w3.module1.property1 == 131277322940537 coinbase = w3.eth.coinbase assert w3.eth.get_balance(coinbase, 'latest') == 1000000000000000000000000 assert w3.module1.method1(coinbase, 'latest') == 1000000000000000000000000 w3.module2.submodule1.attach_methods({ # set `method2` on `module2.submodule1` with `eth_blockNumber` RPC endpoint 'method2': Method('eth_blockNumber', is_property=True) }) assert w3.eth.block_number == 0 assert w3.module2.submodule1.method2 == 0 w3.eth.attach_methods({'get_block2': Method('eth_getBlockByNumber')}) assert w3.eth.get_block('latest')['number'] == 0 assert w3.eth.get_block('pending')['number'] == 1 assert w3.eth.get_block2('latest')['number'] == 0 assert w3.eth.get_block2('pending')['number'] == 1
def test_method_selector_fn_invalid_arg(): with pytest.raises(ValueError): method = Method( mungers=[], json_rpc_method=555555, ) method.method_selector_fn()
def test_input_munger_parameter_passthrough_mismatch_arity(): method = Method( mungers=[lambda m, z, y: 'success'], json_rpc_method='eth_method', ) with pytest.raises(TypeError): method.input_munger(object(), ['first', 'second', 'third'], {})
def test_input_munger_parameter_passthrough_matching_arity(): method = Method( mungers=[lambda m, z, y: ['success']], json_rpc_method='eth_method', ) assert method.input_munger(object(), ['first', 'second'], {}) == ['success']
def test_default_input_munger_with_input_parameters_exception(): method = Method( mungers=[], json_rpc_method='eth_method', ) with pytest.raises(TypeError): method.input_munger(object(), [1], {})
class AlexandriaModule(ModuleV2): # type: ignore """ A web3.py module that exposes high level APIs for interacting with the discovery v5 network. """ # # Live Content Retrieval # retrieve_content: Method[Callable[[ContentKey], bytes]] = Method( RPC.retrieveContent, result_formatters=lambda method, module: decode_hex, mungers=(content_key_munger, ), ) # # Local Storage # get_content: Method[Callable[[ContentKey], bytes]] = Method( RPC.getContent, result_formatters=lambda method, module: decode_hex, mungers=(content_key_munger, ), ) add_content: Method[Callable[[ContentKey], bytes]] = Method( RPC.addContent, mungers=(content_key_and_content_munger, ), ) delete_content: Method[Callable[[ContentKey], bytes]] = Method( RPC.deleteContent, mungers=(content_key_munger, ), )
def test_get_formatters_non_falsy_config_retrieval(): method = Method( mungers=[], json_rpc_method='eth_getBalance', ) method_name = method.method_selector_fn() first_formatter = (method.request_formatters(method_name).first, ) all_other_formatters = method.request_formatters(method_name).funcs assert len(first_formatter + all_other_formatters) == 2
def test_default_munger_for_property_with_input_parameters_raises_ValidationError( ): method = Method( is_property=True, json_rpc_method='eth_method', ) with pytest.raises(ValidationError, match='Parameters cannot be passed to a property'): method.input_munger(object(), [1], {})
def test_get_formatters_default_formatter_for_falsy_config(): method = Method(mungers=[], json_rpc_method='eth_method', formatter_lookup_fn='') default_input_formatters, default_output_formatters = method.get_formatters( '') assert pipe(['a', 'b', 'c'], *default_input_formatters) == ['a', 'b', 'c'] assert pipe(['a', 'b', 'c'], *default_output_formatters) == ['a', 'b', 'c']
class BaseVersion(ModuleV2): retrieve_caller_fn = None _get_node_version = Method('web3_clientVersion') _get_protocol_version = Method('eth_protocolVersion') @property def api(self): from web3 import __version__ return __version__
class BaseVersion(ModuleV2): retrieve_caller_fn = None _get_node_version: Method[Callable[[], str]] = Method(RPC.web3_clientVersion) _get_protocol_version: Method[Callable[[], str]] = Method(RPC.eth_protocolVersion) @property def api(self) -> str: from web3 import __version__ return __version__
def test_get_formatters_non_falsy_config_retrieval(): def formatter_lookup_fn(method): if method == 'eth_method': return 'match' return 'nonmatch' method = Method( mungers=[], json_rpc_method='eth_method', formatter_lookup_fn=formatter_lookup_fn, ) assert method.get_formatters('eth_method') == 'match' assert method.get_formatters('eth_nonmatching') == 'nonmatch'
def test_attach_methods_with_mungers(web3_with_external_modules): w3 = web3_with_external_modules # `method1` uses `eth_getBlockByNumber` but makes use of unique mungers w3.module1.attach_methods({ 'method1': Method( 'eth_getBlockByNumber', mungers=[ lambda _method, block_id, full_transactions: (block_id, full_transactions), # take the user-provided `block_id` and subtract 1 lambda _method, block_id, full_transactions: (block_id - 1, full_transactions), ]), }) assert w3.eth.get_block(0, False)['baseFeePerGas'] == 1000000000 assert w3.eth.get_block(1, False)['baseFeePerGas'] == 875000000 # Testing the mungers work: # `method1` also calls 'eth_getBlockByNumber' but subtracts 1 from the user-provided `block_id` # due to the second munger. So, `0` from above is a `1` here and `1` is `2`. assert w3.module1.method1(1, False)['baseFeePerGas'] == 1000000000 assert w3.module1.method1(2, False)['baseFeePerGas'] == 875000000
def test_property_with_mungers_raises_ValidationError(): with pytest.raises(ValidationError, match='Mungers cannot be used with a property'): Method( is_property=True, mungers=[lambda m, z, y: 'success'], json_rpc_method='eth_method', )
class AlexandriaModule(ModuleV2): # type: ignore """ A web3.py module that exposes high level APIs for interacting with the discovery v5 network. """ get_block_header: Method[Callable[[Hash32], BlockHeader]] = Method( RPC.getContent, result_formatters=lambda method, module: decode_block_header, mungers=(get_block_header_munger, ), ) # # Live Content Retrieval # get_content: Method[Callable[[ContentKey], bytes]] = Method( RPC.getContent, result_formatters=lambda method, module: decode_hex, mungers=(content_key_munger, ), ) # # Commons # get_commons_content: Method[Callable[[ContentKey], bytes]] = Method( RPC.getCommonsContent, result_formatters=lambda method, module: decode_hex, mungers=(content_key_munger, ), ) add_commons_content: Method[Callable[[ContentKey], bytes]] = Method( RPC.addCommonsContent, mungers=(content_key_and_content_munger, ), ) delete_commons_content: Method[Callable[[ContentKey], bytes]] = Method( RPC.deleteCommonsContent, mungers=(content_key_munger, ), ) # # Pinned # get_pinned_content: Method[Callable[[ContentKey], bytes]] = Method( RPC.getPinnedContent, result_formatters=lambda method, module: decode_hex, mungers=(content_key_munger, ), ) add_pinned_content: Method[Callable[[ContentKey], bytes]] = Method( RPC.addPinnedContent, mungers=(content_key_and_content_munger, ), ) delete_pinned_content: Method[Callable[[ContentKey], bytes]] = Method( RPC.deletePinnedContent, mungers=(content_key_munger, ), )
class DiscoveryV5Module(ModuleV2): # type: ignore """ A web3.py module that exposes high level APIs for interacting with the discovery v5 network. """ get_node_info: Method[Callable[[], NodeInfo]] = Method( RPC.nodeInfo, result_formatters=lambda method: NodeInfo.from_rpc_response, ) get_routing_table_info: Method[Callable[[], TableInfo]] = Method( RPC.routingTableInfo, result_formatters=lambda method: TableInfo.from_rpc_response, ) ping: Method[Callable[[Union[ NodeID, ENRAPI, HexStr, str]], PongPayload]] = Method( RPC.ping, result_formatters=lambda method: PongPayload.from_rpc_response, mungers=[ping_munger], )
class Net(Module): _listening: Method[Callable[[], bool]] = Method( RPC.net_listening, mungers=[default_root_munger], ) _peer_count: Method[Callable[[], int]] = Method( RPC.net_peerCount, mungers=[default_root_munger], ) _version: Method[Callable[[], str]] = Method( RPC.net_version, mungers=[default_root_munger], ) @property def chainId(self) -> NoReturn: raise DeprecationWarning( "This method has been deprecated in EIP 1474.") @property def listening(self) -> bool: return self._listening() @property def peer_count(self) -> int: return self._peer_count() @property def version(self) -> str: return self._version() # # Deprecated Methods # peerCount = DeprecatedMethod(peer_count, 'peerCount', 'peer_count') # type: ignore
def test_get_formatters_default_formatter_for_falsy_config(): method = Method( mungers=[], json_rpc_method='eth_method', ) default_request_formatters = method.request_formatters(method.method_selector_fn()) default_result_formatters = method.result_formatters(method.method_selector_fn()) assert _apply_request_formatters(['a', 'b', 'c'], default_request_formatters) == ('a', 'b', 'c') assert apply_result_formatters( default_result_formatters, ['a', 'b', 'c']) == ['a', 'b', 'c']
def test_process_params( method_config, args, kwargs, expected_result, ): if isclass(expected_result) and issubclass(expected_result, Exception): with pytest.raises(expected_result): method = Method(**method_config) req_params, output_formatter = method.process_params( object(), *args, **kwargs) else: method = Method(**method_config) req_params, output_formatter = method.process_params( object(), *args, **kwargs) assert req_params == expected_result
def test_process_params(method_config, args, kwargs, expected_request_result, expected_result_formatters_len): if isclass(expected_request_result) and issubclass(expected_request_result, Exception): with pytest.raises(expected_request_result): method = Method(**method_config) request_params, output_formatter = method.process_params( object(), *args, **kwargs) else: method = Method(**method_config) request_params, output_formatter = method.process_params( object(), *args, **kwargs) assert request_params == expected_request_result first_formatter = (output_formatter[0].first, ) all_other_formatters = output_formatter[0].funcs assert len(first_formatter + all_other_formatters) == expected_result_formatters_len
def startWS(): return Method( "admin_startWS", mungers=[admin_start_params_munger], )
class BaseEth(Module): _default_account: Union[ChecksumAddress, Empty] = empty gasPriceStrategy = None _gas_price: Method[Callable[[], Wei]] = Method( RPC.eth_gasPrice, mungers=None, ) @property def default_account(self) -> Union[ChecksumAddress, Empty]: return self._default_account def send_transaction_munger(self, transaction: TxParams) -> Tuple[TxParams]: if 'from' not in transaction and is_checksum_address( self.default_account): transaction = assoc(transaction, 'from', self.default_account) return (transaction, ) _send_transaction: Method[Callable[[TxParams], HexBytes]] = Method( RPC.eth_sendTransaction, mungers=[send_transaction_munger]) _get_transaction: Method[Callable[[_Hash32], TxData]] = Method( RPC.eth_getTransactionByHash, mungers=[default_root_munger]) def _generate_gas_price( self, transaction_params: Optional[TxParams] = None) -> Optional[Wei]: if self.gasPriceStrategy: return self.gasPriceStrategy(self.web3, transaction_params) return None def set_gas_price_strategy(self, gas_price_strategy: GasPriceStrategy) -> None: self.gasPriceStrategy = gas_price_strategy def estimate_gas_munger( self, transaction: TxParams, block_identifier: Optional[BlockIdentifier] = None ) -> Sequence[Union[TxParams, BlockIdentifier]]: if 'from' not in transaction and is_checksum_address( self.default_account): transaction = assoc(transaction, 'from', self.default_account) if block_identifier is None: params: Sequence[Union[TxParams, BlockIdentifier]] = [transaction] else: params = [transaction, block_identifier] return params _estimate_gas: Method[Callable[..., Wei]] = Method( RPC.eth_estimateGas, mungers=[estimate_gas_munger]) def get_block_munger( self, block_identifier: BlockIdentifier, full_transactions: bool = False) -> Tuple[BlockIdentifier, bool]: return (block_identifier, full_transactions) """ `eth_getBlockByHash` `eth_getBlockByNumber` """ _get_block: Method[Callable[..., BlockData]] = Method( method_choice_depends_on_args=select_method_for_block_identifier( if_predefined=RPC.eth_getBlockByNumber, if_hash=RPC.eth_getBlockByHash, if_number=RPC.eth_getBlockByNumber, ), mungers=[get_block_munger], ) get_block_number: Method[Callable[[], BlockNumber]] = Method( RPC.eth_blockNumber, mungers=None, ) get_coinbase: Method[Callable[[], ChecksumAddress]] = Method( RPC.eth_coinbase, mungers=None, )
class Eth(BaseEth, Module): account = Account() _default_block: BlockIdentifier = "latest" defaultContractFactory: Type[ Union[Contract, ConciseContract, ContractCaller]] = Contract # noqa: E704,E501 iban = Iban def namereg(self) -> NoReturn: raise NotImplementedError() def icapNamereg(self) -> NoReturn: raise NotImplementedError() _protocol_version: Method[Callable[[], str]] = Method( RPC.eth_protocolVersion, mungers=None, ) @property def protocol_version(self) -> str: warnings.warn( "This method has been deprecated in some clients.", category=DeprecationWarning, ) return self._protocol_version() @property def protocolVersion(self) -> str: warnings.warn( 'protocolVersion is deprecated in favor of protocol_version', category=DeprecationWarning, ) return self.protocol_version is_syncing: Method[Callable[[], Union[SyncStatus, bool]]] = Method( RPC.eth_syncing, mungers=None, ) @property def syncing(self) -> Union[SyncStatus, bool]: return self.is_syncing() @property def coinbase(self) -> ChecksumAddress: return self.get_coinbase() is_mining: Method[Callable[[], bool]] = Method( RPC.eth_mining, mungers=None, ) @property def mining(self) -> bool: return self.is_mining() get_hashrate: Method[Callable[[], int]] = Method( RPC.eth_hashrate, mungers=None, ) @property def hashrate(self) -> int: return self.get_hashrate() @property def gas_price(self) -> Wei: return self._gas_price() @property def gasPrice(self) -> Wei: warnings.warn( 'gasPrice is deprecated in favor of gas_price', category=DeprecationWarning, ) return self.gas_price get_accounts: Method[Callable[[], Tuple[ChecksumAddress]]] = Method( RPC.eth_accounts, mungers=None, ) @property def accounts(self) -> Tuple[ChecksumAddress]: return self.get_accounts() @property def block_number(self) -> BlockNumber: return self.get_block_number() @property def blockNumber(self) -> BlockNumber: warnings.warn( 'blockNumber is deprecated in favor of block_number', category=DeprecationWarning, ) return self.block_number _chain_id: Method[Callable[[], int]] = Method( RPC.eth_chainId, mungers=None, ) @property def chain_id(self) -> int: return self._chain_id() @property def chainId(self) -> int: warnings.warn( 'chainId is deprecated in favor of chain_id', category=DeprecationWarning, ) return self.chain_id """ property default_account """ @property def default_account(self) -> Union[ChecksumAddress, Empty]: return self._default_account @default_account.setter def default_account(self, account: Union[ChecksumAddress, Empty]) -> None: self._default_account = account @property def defaultAccount(self) -> Union[ChecksumAddress, Empty]: warnings.warn( 'defaultAccount is deprecated in favor of default_account', category=DeprecationWarning, ) return self._default_account @defaultAccount.setter def defaultAccount(self, account: Union[ChecksumAddress, Empty]) -> None: warnings.warn( 'defaultAccount is deprecated in favor of default_account', category=DeprecationWarning, ) self._default_account = account """ property default_block """ @property def default_block(self) -> BlockIdentifier: return self._default_block @default_block.setter def default_block(self, value: BlockIdentifier) -> None: self._default_block = value @property def defaultBlock(self) -> BlockIdentifier: warnings.warn( 'defaultBlock is deprecated in favor of default_block', category=DeprecationWarning, ) return self._default_block @defaultBlock.setter def defaultBlock(self, value: BlockIdentifier) -> None: warnings.warn( 'defaultBlock is deprecated in favor of default_block', category=DeprecationWarning, ) self._default_block = value def block_id_munger( self, account: Union[Address, ChecksumAddress, ENS], block_identifier: Optional[BlockIdentifier] = None ) -> Tuple[Union[Address, ChecksumAddress, ENS], BlockIdentifier]: if block_identifier is None: block_identifier = self.default_block return (account, block_identifier) get_balance: Method[Callable[..., Wei]] = Method( RPC.eth_getBalance, mungers=[block_id_munger], ) def get_storage_at_munger( self, account: Union[Address, ChecksumAddress, ENS], position: int, block_identifier: Optional[BlockIdentifier] = None ) -> Tuple[Union[Address, ChecksumAddress, ENS], int, BlockIdentifier]: if block_identifier is None: block_identifier = self.default_block return (account, position, block_identifier) get_storage_at: Method[Callable[..., HexBytes]] = Method( RPC.eth_getStorageAt, mungers=[get_storage_at_munger], ) def get_proof_munger( self, account: Union[Address, ChecksumAddress, ENS], positions: Sequence[int], block_identifier: Optional[BlockIdentifier] = None ) -> Tuple[Union[Address, ChecksumAddress, ENS], Sequence[int], Optional[BlockIdentifier]]: if block_identifier is None: block_identifier = self.default_block return (account, positions, block_identifier) get_proof: Method[Callable[[ Tuple[Union[Address, ChecksumAddress, ENS], Sequence[int], Optional[BlockIdentifier]] ], MerkleProof]] = Method( RPC.eth_getProof, mungers=[get_proof_munger], ) get_code: Method[Callable[..., HexBytes]] = Method(RPC.eth_getCode, mungers=[block_id_munger]) def get_block(self, block_identifier: BlockIdentifier, full_transactions: bool = False) -> BlockData: return self._get_block(block_identifier, full_transactions) """ `eth_getBlockTransactionCountByHash` `eth_getBlockTransactionCountByNumber` """ get_block_transaction_count: Method[Callable[ [BlockIdentifier], int]] = Method( method_choice_depends_on_args=select_method_for_block_identifier( if_predefined=RPC.eth_getBlockTransactionCountByNumber, if_hash=RPC.eth_getBlockTransactionCountByHash, if_number=RPC.eth_getBlockTransactionCountByNumber, ), mungers=[default_root_munger]) """ `eth_getUncleCountByBlockHash` `eth_getUncleCountByBlockNumber` """ get_uncle_count: Method[Callable[[BlockIdentifier], int]] = Method( method_choice_depends_on_args=select_method_for_block_identifier( if_predefined=RPC.eth_getUncleCountByBlockNumber, if_hash=RPC.eth_getUncleCountByBlockHash, if_number=RPC.eth_getUncleCountByBlockNumber, ), mungers=[default_root_munger]) """ `eth_getUncleByBlockHashAndIndex` `eth_getUncleByBlockNumberAndIndex` """ get_uncle_by_block: Method[Callable[ [BlockIdentifier, int], Uncle]] = Method( method_choice_depends_on_args=select_method_for_block_identifier( if_predefined=RPC.eth_getUncleByBlockNumberAndIndex, if_hash=RPC.eth_getUncleByBlockHashAndIndex, if_number=RPC.eth_getUncleByBlockNumberAndIndex, ), mungers=[default_root_munger]) def get_transaction(self, transaction_hash: _Hash32) -> TxData: return self._get_transaction(transaction_hash) def getTransactionFromBlock(self, block_identifier: BlockIdentifier, transaction_index: int) -> NoReturn: """ Alias for the method getTransactionByBlock Deprecated to maintain naming consistency with the json-rpc API """ raise DeprecationWarning( "This method has been deprecated as of EIP 1474.") get_transaction_by_block: Method[Callable[ [BlockIdentifier, int], TxData]] = Method( method_choice_depends_on_args=select_method_for_block_identifier( if_predefined=RPC.eth_getTransactionByBlockNumberAndIndex, if_hash=RPC.eth_getTransactionByBlockHashAndIndex, if_number=RPC.eth_getTransactionByBlockNumberAndIndex, ), mungers=[default_root_munger]) @deprecated_for("wait_for_transaction_receipt") def waitForTransactionReceipt(self, transaction_hash: _Hash32, timeout: int = 120, poll_latency: float = 0.1) -> TxReceipt: return self.wait_for_transaction_receipt(transaction_hash, timeout, poll_latency) def wait_for_transaction_receipt(self, transaction_hash: _Hash32, timeout: int = 120, poll_latency: float = 0.1) -> TxReceipt: try: return wait_for_transaction_receipt(self.web3, transaction_hash, timeout, poll_latency) except Timeout: raise TimeExhausted( "Transaction {} is not in the chain, after {} seconds".format( to_hex(transaction_hash), timeout, )) get_transaction_receipt: Method[Callable[[_Hash32], TxReceipt]] = Method( RPC.eth_getTransactionReceipt, mungers=[default_root_munger]) get_transaction_count: Method[Callable[..., Nonce]] = Method( RPC.eth_getTransactionCount, mungers=[block_id_munger], ) @deprecated_for("replace_transaction") def replaceTransaction(self, transaction_hash: _Hash32, new_transaction: TxParams) -> HexBytes: return self.replace_transaction(transaction_hash, new_transaction) def replace_transaction(self, transaction_hash: _Hash32, new_transaction: TxParams) -> HexBytes: current_transaction = get_required_transaction(self.web3, transaction_hash) return replace_transaction(self.web3, current_transaction, new_transaction) # todo: Update Any to stricter kwarg checking with TxParams # https://github.com/python/mypy/issues/4441 @deprecated_for("modify_transaction") def modifyTransaction(self, transaction_hash: _Hash32, **transaction_params: Any) -> HexBytes: return self.modify_transaction(transaction_hash, **transaction_params) def modify_transaction(self, transaction_hash: _Hash32, **transaction_params: Any) -> HexBytes: assert_valid_transaction_params(cast(TxParams, transaction_params)) current_transaction = get_required_transaction(self.web3, transaction_hash) current_transaction_params = extract_valid_transaction_params( current_transaction) new_transaction = merge(current_transaction_params, transaction_params) return replace_transaction(self.web3, current_transaction, new_transaction) def send_transaction(self, transaction: TxParams) -> HexBytes: return self._send_transaction(transaction) send_raw_transaction: Method[Callable[[Union[HexStr, bytes]], HexBytes]] = Method( RPC.eth_sendRawTransaction, mungers=[default_root_munger], ) def sign_munger( self, account: Union[Address, ChecksumAddress, ENS], data: Union[int, bytes] = None, hexstr: HexStr = None, text: str = None ) -> Tuple[Union[Address, ChecksumAddress, ENS], HexStr]: message_hex = to_hex(data, hexstr=hexstr, text=text) return (account, message_hex) sign: Method[Callable[..., HexStr]] = Method( RPC.eth_sign, mungers=[sign_munger], ) sign_transaction: Method[Callable[[TxParams], SignedTx]] = Method( RPC.eth_signTransaction, mungers=[default_root_munger], ) sign_typed_data: Method[Callable[..., HexStr]] = Method( RPC.eth_signTypedData, mungers=[default_root_munger], ) def call_munger( self, transaction: TxParams, block_identifier: Optional[BlockIdentifier] = None, state_override: Optional[CallOverrideParams] = None, ) -> Union[Tuple[TxParams, BlockIdentifier], Tuple[ TxParams, BlockIdentifier, CallOverrideParams]]: # noqa-E501 # TODO: move to middleware if 'from' not in transaction and is_checksum_address( self.default_account): transaction = assoc(transaction, 'from', self.default_account) # TODO: move to middleware if block_identifier is None: block_identifier = self.default_block if state_override is None: return (transaction, block_identifier) else: return (transaction, block_identifier, state_override) call: Method[Callable[..., Union[bytes, bytearray]]] = Method(RPC.eth_call, mungers=[call_munger]) def estimate_gas( self, transaction: TxParams, block_identifier: Optional[BlockIdentifier] = None) -> Wei: return self._estimate_gas(transaction, block_identifier) def filter_munger( self, filter_params: Optional[Union[str, FilterParams]] = None, filter_id: Optional[HexStr] = None ) -> Union[List[FilterParams], List[HexStr], List[str]]: if filter_id and filter_params: raise TypeError( "Ambiguous invocation: provide either a `filter_params` or a `filter_id` argument. " "Both were supplied.") if isinstance(filter_params, dict): return [filter_params] elif is_string(filter_params): if filter_params in ['latest', 'pending']: return [filter_params] else: raise ValueError( "The filter API only accepts the values of `pending` or " "`latest` for string based filters") elif filter_id and not filter_params: return [filter_id] else: raise TypeError( "Must provide either filter_params as a string or " "a valid filter object, or a filter_id as a string " "or hex.") filter: Method[Callable[..., Any]] = Method( method_choice_depends_on_args=select_filter_method( if_new_block_filter=RPC.eth_newBlockFilter, if_new_pending_transaction_filter=RPC. eth_newPendingTransactionFilter, if_new_filter=RPC.eth_newFilter, ), mungers=[filter_munger], ) get_filter_changes: Method[Callable[[HexStr], List[LogReceipt]]] = Method( RPC.eth_getFilterChanges, mungers=[default_root_munger]) get_filter_logs: Method[Callable[[HexStr], List[LogReceipt]]] = Method( RPC.eth_getFilterLogs, mungers=[default_root_munger]) get_logs: Method[Callable[[FilterParams], List[LogReceipt]]] = Method( RPC.eth_getLogs, mungers=[default_root_munger]) submit_hashrate: Method[Callable[[int, _Hash32], bool]] = Method( RPC.eth_submitHashrate, mungers=[default_root_munger], ) submit_work: Method[Callable[[int, _Hash32, _Hash32], bool]] = Method( RPC.eth_submitWork, mungers=[default_root_munger], ) uninstall_filter: Method[Callable[[HexStr], bool]] = Method( RPC.eth_uninstallFilter, mungers=[default_root_munger], ) @overload def contract(self, address: None = None, **kwargs: Any) -> Type[Contract]: ... # noqa: E704,E501 @overload # noqa: F811 def contract(self, address: Union[Address, ChecksumAddress, ENS], **kwargs: Any) -> Contract: ... # noqa: E704,E501 def contract( # noqa: F811 self, address: Optional[Union[Address, ChecksumAddress, ENS]] = None, **kwargs: Any) -> Union[Type[Contract], Contract]: ContractFactoryClass = kwargs.pop('ContractFactoryClass', self.defaultContractFactory) ContractFactory = ContractFactoryClass.factory(self.web3, **kwargs) if address: return ContractFactory(address) else: return ContractFactory @deprecated_for("set_contract_factory") def setContractFactory( self, contractFactory: Type[Union[Contract, ConciseContract, ContractCaller]] ) -> None: return self.set_contract_factory(contractFactory) def set_contract_factory( self, contractFactory: Type[Union[Contract, ConciseContract, ContractCaller]] ) -> None: self.defaultContractFactory = contractFactory def getCompilers(self) -> NoReturn: raise DeprecationWarning( "This method has been deprecated as of EIP 1474.") get_work: Method[Callable[[], List[HexBytes]]] = Method( RPC.eth_getWork, mungers=None, ) @deprecated_for("generate_gas_price") def generateGasPrice( self, transaction_params: Optional[TxParams] = None) -> Optional[Wei]: return self._generate_gas_price(transaction_params) def generate_gas_price( self, transaction_params: Optional[TxParams] = None) -> Optional[Wei]: return self._generate_gas_price(transaction_params) @deprecated_for("set_gas_price_strategy") def setGasPriceStrategy(self, gas_price_strategy: GasPriceStrategy) -> None: return self.set_gas_price_strategy(gas_price_strategy) # Deprecated Methods getBalance = DeprecatedMethod(get_balance, 'getBalance', 'get_balance') getStorageAt = DeprecatedMethod(get_storage_at, 'getStorageAt', 'get_storage_at') getBlock = DeprecatedMethod(get_block, 'getBlock', 'get_block') # type: ignore getBlockTransactionCount = DeprecatedMethod(get_block_transaction_count, 'getBlockTransactionCount', 'get_block_transaction_count') getCode = DeprecatedMethod(get_code, 'getCode', 'get_code') getProof = DeprecatedMethod(get_proof, 'getProof', 'get_proof') getTransaction = DeprecatedMethod( get_transaction, # type: ignore 'getTransaction', 'get_transaction') getTransactionByBlock = DeprecatedMethod(get_transaction_by_block, 'getTransactionByBlock', 'get_transaction_by_block') getTransactionCount = DeprecatedMethod(get_transaction_count, 'getTransactionCount', 'get_transaction_count') getUncleByBlock = DeprecatedMethod(get_uncle_by_block, 'getUncleByBlock', 'get_uncle_by_block') getUncleCount = DeprecatedMethod(get_uncle_count, 'getUncleCount', 'get_uncle_count') sendTransaction = DeprecatedMethod( send_transaction, # type: ignore 'sendTransaction', 'send_transaction') signTransaction = DeprecatedMethod(sign_transaction, 'signTransaction', 'sign_transaction') signTypedData = DeprecatedMethod(sign_typed_data, 'signTypedData', 'sign_typed_data') submitHashrate = DeprecatedMethod(submit_hashrate, 'submitHashrate', 'submit_hashrate') submitWork = DeprecatedMethod(submit_work, 'submitWork', 'submit_work') getLogs = DeprecatedMethod(get_logs, 'getLogs', 'get_logs') estimateGas = DeprecatedMethod(estimate_gas, 'estimateGas', 'estimate_gas') # type: ignore sendRawTransaction = DeprecatedMethod(send_raw_transaction, 'sendRawTransaction', 'send_raw_transaction') getTransactionReceipt = DeprecatedMethod(get_transaction_receipt, 'getTransactionReceipt', 'get_transaction_receipt') uninstallFilter = DeprecatedMethod(uninstall_filter, 'uninstallFilter', 'uninstall_filter') getFilterLogs = DeprecatedMethod(get_filter_logs, 'getFilterLogs', 'get_filter_logs') getFilterChanges = DeprecatedMethod(get_filter_changes, 'getFilterChanges', 'get_filter_changes') getWork = DeprecatedMethod(get_work, 'getWork', 'get_work')
class AsyncEth(BaseEth): is_async = True @property async def accounts(self) -> Tuple[ChecksumAddress]: return await self._get_accounts() # type: ignore @property async def block_number(self) -> BlockNumber: # types ignored b/c mypy conflict with BlockingEth properties return await self.get_block_number() # type: ignore @property async def chain_id(self) -> int: return await self._chain_id() # type: ignore @property async def coinbase(self) -> ChecksumAddress: # types ignored b/c mypy conflict with BlockingEth properties return await self.get_coinbase() # type: ignore @property async def gas_price(self) -> Wei: # types ignored b/c mypy conflict with BlockingEth properties return await self._gas_price() # type: ignore @property async def hashrate(self) -> int: return await self._get_hashrate() # type: ignore @property async def max_priority_fee(self) -> Wei: """ Try to use eth_maxPriorityFeePerGas but, since this is not part of the spec and is only supported by some clients, fall back to an eth_feeHistory calculation with min and max caps. """ try: return await self._max_priority_fee() # type: ignore except ValueError: warnings.warn( "There was an issue with the method eth_maxPriorityFeePerGas. Calculating using " "eth_feeHistory.") return await async_fee_history_priority_fee(self) @property async def mining(self) -> bool: return await self._is_mining() # type: ignore @property async def syncing(self) -> Union[SyncStatus, bool]: return await self._is_syncing() # type: ignore async def fee_history( self, block_count: int, newest_block: Union[BlockParams, BlockNumber], reward_percentiles: Optional[List[float]] = None) -> FeeHistory: return await self._fee_history( # type: ignore block_count, newest_block, reward_percentiles) async def send_transaction(self, transaction: TxParams) -> HexBytes: # types ignored b/c mypy conflict with BlockingEth properties return await self._send_transaction(transaction) # type: ignore async def send_raw_transaction( self, transaction: Union[HexStr, bytes]) -> HexBytes: # types ignored b/c mypy conflict with BlockingEth properties return await self._send_raw_transaction(transaction) # type: ignore async def get_transaction(self, transaction_hash: _Hash32) -> TxData: # types ignored b/c mypy conflict with BlockingEth properties return await self._get_transaction(transaction_hash) # type: ignore async def get_raw_transaction(self, transaction_hash: _Hash32) -> TxData: # types ignored b/c mypy conflict with BlockingEth properties return await self._get_raw_transaction(transaction_hash ) # type: ignore async def get_raw_transaction_by_block(self, block_identifier: BlockIdentifier, index: int) -> HexBytes: # types ignored b/c mypy conflict with BlockingEth properties return await self._get_raw_transaction_by_block( block_identifier, index) # type: ignore async def generate_gas_price( self, transaction_params: Optional[TxParams] = None) -> Optional[Wei]: return self._generate_gas_price(transaction_params) async def estimate_gas( self, transaction: TxParams, block_identifier: Optional[BlockIdentifier] = None) -> int: # types ignored b/c mypy conflict with BlockingEth properties return await self._estimate_gas(transaction, block_identifier) # type: ignore async def get_block(self, block_identifier: BlockIdentifier, full_transactions: bool = False) -> BlockData: # types ignored b/c mypy conflict with BlockingEth properties return await self._get_block(block_identifier, full_transactions) # type: ignore _get_balance: Method[Callable[..., Awaitable[Wei]]] = Method( RPC.eth_getBalance, mungers=[BaseEth.block_id_munger], ) async def get_balance( self, account: Union[Address, ChecksumAddress, ENS], block_identifier: Optional[BlockIdentifier] = None) -> Wei: return await self._get_balance(account, block_identifier) _get_code: Method[Callable[..., Awaitable[HexBytes]]] = Method( RPC.eth_getCode, mungers=[BaseEth.block_id_munger]) async def get_code( self, account: Union[Address, ChecksumAddress, ENS], block_identifier: Optional[BlockIdentifier] = None) -> HexBytes: return await self._get_code(account, block_identifier) _get_logs: Method[Callable[[FilterParams], Awaitable[List[LogReceipt]]]] = Method( RPC.eth_getLogs, mungers=[default_root_munger]) async def get_logs( self, filter_params: FilterParams, ) -> List[LogReceipt]: return await self._get_logs(filter_params) _get_transaction_count: Method[Callable[..., Awaitable[Nonce]]] = Method( RPC.eth_getTransactionCount, mungers=[BaseEth.block_id_munger], ) async def get_transaction_count( self, account: Union[Address, ChecksumAddress, ENS], block_identifier: Optional[BlockIdentifier] = None) -> Nonce: return await self._get_transaction_count(account, block_identifier) _call: Method[Callable[..., Awaitable[Union[bytes, bytearray]]]] = Method( RPC.eth_call, mungers=[BaseEth.call_munger]) async def get_transaction_receipt(self, transaction_hash: _Hash32) -> TxReceipt: return await self._get_transaction_receipt(transaction_hash ) # type: ignore async def wait_for_transaction_receipt( self, transaction_hash: _Hash32, timeout: float = 120, poll_latency: float = 0.1) -> TxReceipt: async def _wait_for_tx_receipt_with_timeout( _tx_hash: _Hash32, _poll_latence: float) -> TxReceipt: while True: try: tx_receipt = await self._get_transaction_receipt( _tx_hash) # type: ignore except TransactionNotFound: tx_receipt = None if tx_receipt is not None: break await asyncio.sleep(poll_latency) return tx_receipt try: return await asyncio.wait_for( _wait_for_tx_receipt_with_timeout(transaction_hash, poll_latency), timeout=timeout, ) except asyncio.TimeoutError: raise TimeExhausted( f"Transaction {HexBytes(transaction_hash) !r} is not in the chain " f"after {timeout} seconds") _get_storage_at: Method[Callable[..., Awaitable[HexBytes]]] = Method( RPC.eth_getStorageAt, mungers=[BaseEth.get_storage_at_munger], ) async def get_storage_at( self, account: Union[Address, ChecksumAddress, ENS], position: int, block_identifier: Optional[BlockIdentifier] = None) -> HexBytes: return await self._get_storage_at(account, position, block_identifier) async def call( self, transaction: TxParams, block_identifier: Optional[BlockIdentifier] = None, state_override: Optional[CallOverrideParams] = None, ) -> Union[bytes, bytearray]: return await self._call(transaction, block_identifier, state_override)
class BaseEth(Module): _default_account: Union[ChecksumAddress, Empty] = empty _default_block: BlockIdentifier = "latest" gasPriceStrategy = None _gas_price: Method[Callable[[], Wei]] = Method( RPC.eth_gasPrice, mungers=None, ) @property def default_block(self) -> BlockIdentifier: return self._default_block @default_block.setter def default_block(self, value: BlockIdentifier) -> None: self._default_block = value @property def defaultBlock(self) -> BlockIdentifier: warnings.warn( 'defaultBlock is deprecated in favor of default_block', category=DeprecationWarning, ) return self._default_block @defaultBlock.setter def defaultBlock(self, value: BlockIdentifier) -> None: warnings.warn( 'defaultBlock is deprecated in favor of default_block', category=DeprecationWarning, ) self._default_block = value @property def default_account(self) -> Union[ChecksumAddress, Empty]: return self._default_account @default_account.setter def default_account(self, account: Union[ChecksumAddress, Empty]) -> None: self._default_account = account @property def defaultAccount(self) -> Union[ChecksumAddress, Empty]: warnings.warn( 'defaultAccount is deprecated in favor of default_account', category=DeprecationWarning, ) return self._default_account @defaultAccount.setter def defaultAccount(self, account: Union[ChecksumAddress, Empty]) -> None: warnings.warn( 'defaultAccount is deprecated in favor of default_account', category=DeprecationWarning, ) self._default_account = account def send_transaction_munger(self, transaction: TxParams) -> Tuple[TxParams]: if 'from' not in transaction and is_checksum_address( self.default_account): transaction = assoc(transaction, 'from', self.default_account) return (transaction, ) _send_transaction: Method[Callable[[TxParams], HexBytes]] = Method( RPC.eth_sendTransaction, mungers=[send_transaction_munger]) _send_raw_transaction: Method[Callable[[Union[HexStr, bytes]], HexBytes]] = Method( RPC.eth_sendRawTransaction, mungers=[default_root_munger], ) _get_transaction: Method[Callable[[_Hash32], TxData]] = Method( RPC.eth_getTransactionByHash, mungers=[default_root_munger]) _get_raw_transaction: Method[Callable[[_Hash32], HexBytes]] = Method( RPC.eth_getRawTransactionByHash, mungers=[default_root_munger]) """ `eth_getRawTransactionByBlockHashAndIndex` `eth_getRawTransactionByBlockNumberAndIndex` """ _get_raw_transaction_by_block: Method[Callable[ [BlockIdentifier, int], HexBytes]] = Method( method_choice_depends_on_args=select_method_for_block_identifier( if_predefined=RPC.eth_getRawTransactionByBlockNumberAndIndex, if_hash=RPC.eth_getRawTransactionByBlockHashAndIndex, if_number=RPC.eth_getRawTransactionByBlockNumberAndIndex, ), mungers=[default_root_munger]) def _generate_gas_price( self, transaction_params: Optional[TxParams] = None) -> Optional[Wei]: if self.gasPriceStrategy: return self.gasPriceStrategy(self.web3, transaction_params) return None def set_gas_price_strategy(self, gas_price_strategy: GasPriceStrategy) -> None: self.gasPriceStrategy = gas_price_strategy def estimate_gas_munger( self, transaction: TxParams, block_identifier: Optional[BlockIdentifier] = None ) -> Sequence[Union[TxParams, BlockIdentifier]]: if 'from' not in transaction and is_checksum_address( self.default_account): transaction = assoc(transaction, 'from', self.default_account) if block_identifier is None: params: Sequence[Union[TxParams, BlockIdentifier]] = [transaction] else: params = [transaction, block_identifier] return params _estimate_gas: Method[Callable[..., int]] = Method( RPC.eth_estimateGas, mungers=[estimate_gas_munger]) _fee_history: Method[Callable[..., FeeHistory]] = Method( RPC.eth_feeHistory, mungers=[default_root_munger]) _max_priority_fee: Method[Callable[..., Wei]] = Method( RPC.eth_maxPriorityFeePerGas, mungers=None, ) def get_block_munger( self, block_identifier: BlockIdentifier, full_transactions: bool = False) -> Tuple[BlockIdentifier, bool]: return (block_identifier, full_transactions) """ `eth_getBlockByHash` `eth_getBlockByNumber` """ _get_block: Method[Callable[..., BlockData]] = Method( method_choice_depends_on_args=select_method_for_block_identifier( if_predefined=RPC.eth_getBlockByNumber, if_hash=RPC.eth_getBlockByHash, if_number=RPC.eth_getBlockByNumber, ), mungers=[get_block_munger], ) get_block_number: Method[Callable[[], BlockNumber]] = Method( RPC.eth_blockNumber, mungers=None, ) get_coinbase: Method[Callable[[], ChecksumAddress]] = Method( RPC.eth_coinbase, mungers=None, ) def block_id_munger( self, account: Union[Address, ChecksumAddress, ENS], block_identifier: Optional[BlockIdentifier] = None ) -> Tuple[Union[Address, ChecksumAddress, ENS], BlockIdentifier]: if block_identifier is None: block_identifier = self.default_block return (account, block_identifier) def get_storage_at_munger( self, account: Union[Address, ChecksumAddress, ENS], position: int, block_identifier: Optional[BlockIdentifier] = None ) -> Tuple[Union[Address, ChecksumAddress, ENS], int, BlockIdentifier]: if block_identifier is None: block_identifier = self.default_block return (account, position, block_identifier) def call_munger( self, transaction: TxParams, block_identifier: Optional[BlockIdentifier] = None, state_override: Optional[CallOverrideParams] = None, ) -> Union[Tuple[TxParams, BlockIdentifier], Tuple[ TxParams, BlockIdentifier, CallOverrideParams]]: # noqa-E501 # TODO: move to middleware if 'from' not in transaction and is_checksum_address( self.default_account): transaction = assoc(transaction, 'from', self.default_account) # TODO: move to middleware if block_identifier is None: block_identifier = self.default_block if state_override is None: return (transaction, block_identifier) else: return (transaction, block_identifier, state_override) _get_accounts: Method[Callable[[], Tuple[ChecksumAddress]]] = Method( RPC.eth_accounts, mungers=None, ) _get_hashrate: Method[Callable[[], int]] = Method( RPC.eth_hashrate, mungers=None, ) _chain_id: Method[Callable[[], int]] = Method( RPC.eth_chainId, mungers=None, ) _is_mining: Method[Callable[[], bool]] = Method( RPC.eth_mining, mungers=None, ) _is_syncing: Method[Callable[[], Union[SyncStatus, bool]]] = Method( RPC.eth_syncing, mungers=None, ) _get_transaction_receipt: Method[Callable[[_Hash32], TxReceipt]] = Method( RPC.eth_getTransactionReceipt, mungers=[default_root_munger])
def stopWS(): return Method( "admin_stopWS", mungers=None, )
def stopRPC(): return Method( "admin_stopRPC", mungers=None, )
def setSolc(): return Method( "admin_setSolc", mungers=[default_root_munger], )