def test_dynamic_length_argument_extraction(web3, emitter, wait_for_transaction, emitter_log_topics, emitter_event_ids): string_0 = "this-is-the-first-string-which-exceeds-32-bytes-in-length" string_1 = "this-is-the-second-string-which-exceeds-32-bytes-in-length" txn_hash = emitter.functions.logDynamicArgs(string_0, string_1).transact() txn_receipt = wait_for_transaction(web3, txn_hash) assert len(txn_receipt['logs']) == 1 log_entry = txn_receipt['logs'][0] event_abi = emitter._find_matching_event_abi('LogDynamicArgs') event_topic = emitter_log_topics.LogDynamicArgs assert event_topic in log_entry['topics'] string_0_topic = web3.keccak(text=string_0) assert string_0_topic in log_entry['topics'] event_data = get_event_data(event_abi, log_entry) expected_args = { "arg0": string_0_topic, "arg1": string_1, } assert event_data['args'] == expected_args assert event_data['blockHash'] == txn_receipt['blockHash'] assert event_data['blockNumber'] == txn_receipt['blockNumber'] assert event_data['transactionIndex'] == txn_receipt['transactionIndex'] assert is_same_address(event_data['address'], emitter.address) assert event_data['event'] == 'LogDynamicArgs'
def test_event_data_extraction(web3, emitter, wait_for_transaction, emitter_log_topics, emitter_event_ids, contract_fn, event_name, call_args, expected_args): function = getattr(emitter.functions, contract_fn) event_id = getattr(emitter_event_ids, event_name) txn_hash = function(event_id, *call_args).transact() txn_receipt = wait_for_transaction(web3, txn_hash) assert len(txn_receipt['logs']) == 1 log_entry = txn_receipt['logs'][0] event_abi = emitter._find_matching_event_abi(event_name) event_topic = getattr(emitter_log_topics, event_name) is_anonymous = event_abi['anonymous'] if is_anonymous: assert event_topic not in log_entry['topics'] else: assert event_topic in log_entry['topics'] event_data = get_event_data(event_abi, log_entry) assert event_data['args'] == expected_args assert event_data['blockHash'] == txn_receipt['blockHash'] assert event_data['blockNumber'] == txn_receipt['blockNumber'] assert event_data['transactionIndex'] == txn_receipt['transactionIndex'] assert is_same_address(event_data['address'], emitter.address) assert event_data['event'] == event_name
def _parse_logs(self, txn_receipt): for log in txn_receipt['logs']: try: decoded_log = get_event_data(self.abi, log) except MismatchedABI: continue yield decoded_log
def createFilter( self, *, # PEP 3102 argument_filters=None, fromBlock=None, toBlock="latest", address=None, topics=None): """ Create filter object that tracks logs emitted by this contract event. :param filter_params: other parameters to limit the events """ if fromBlock is None: raise TypeError( "Missing mandatory keyword argument to createFilter: fromBlock" ) if argument_filters is None: argument_filters = dict() _filters = dict(**argument_filters) event_abi = self._get_event_abi() check_for_forbidden_api_filter_arguments(event_abi, _filters) _, event_filter_params = construct_event_filter_params( self._get_event_abi(), contract_address=self.address, argument_filters=_filters, fromBlock=fromBlock, toBlock=toBlock, address=address, topics=topics, ) filter_builder = EventFilterBuilder(event_abi) filter_builder.address = event_filter_params.get('address') filter_builder.fromBlock = event_filter_params.get('fromBlock') filter_builder.toBlock = event_filter_params.get('toBlock') match_any_vals = { arg: value for arg, value in _filters.items() if not is_array_type(filter_builder.args[arg].arg_type) and is_list_like(value) } for arg, value in match_any_vals.items(): filter_builder.args[arg].match_any(*value) match_single_vals = { arg: value for arg, value in _filters.items() if not is_array_type(filter_builder.args[arg].arg_type) and not is_list_like(value) } for arg, value in match_single_vals.items(): filter_builder.args[arg].match_single(value) log_filter = filter_builder.deploy(self.web3) log_filter.log_entry_formatter = get_event_data(self._get_event_abi()) log_filter.builder = filter_builder return log_filter
def getLogs(self, argument_filters=None, fromBlock=1, toBlock="latest"): """Get events for this contract instance using eth_getLogs API. This is a stateless method, as opposed to createFilter. It can be safely called against nodes which do not provide eth_newFilter API, like Infura nodes. If no block range is provided and there are many events, like ``Transfer`` events for a popular token, the Ethereum node might be overloaded and timeout on the underlying JSON-RPC call. Example - how to get all ERC-20 token transactions for the latest 10 blocks: .. code-block:: python from = max(mycontract.web3.eth.blockNumber - 10, 1) to = mycontract.web3.eth.blockNumber events = mycontract.events.Transfer.getLogs(fromBlock=from, toBlock=to) for e in events: print(e["args"]["from"], e["args"]["to"], e["args"]["value"]) The returned processed log values will look like: .. code-block:: python ( AttributeDict({ 'args': AttributeDict({}), 'event': 'LogNoArguments', 'logIndex': 0, 'transactionIndex': 0, 'transactionHash': HexBytes('...'), 'address': '0xF2E246BB76DF876Cef8b38ae84130F4F55De395b', 'blockHash': HexBytes('...'), 'blockNumber': 3 }), AttributeDict(...), ... ) See also: :func:`web3.middleware.filter.local_filter_middleware`. :param argument_filters: :param fromBlock: block number, defaults to 1 :param toBlock: block number or "latest". Defaults to "latest" :yield: Tuple of :class:`AttributeDict` instances """ if not self.address: raise TypeError("This method can be only called on " "an instated contract with an address") abi = self._get_event_abi() if argument_filters is None: argument_filters = dict() _filters = dict(**argument_filters) # Construct JSON-RPC raw filter presentation based on human readable Python descriptions # Namely, convert event names to their keccak signatures data_filter_set, event_filter_params = construct_event_filter_params( abi, contract_address=self.address, argument_filters=_filters, fromBlock=fromBlock, toBlock=toBlock, address=self.address, ) # Call JSON-RPC API logs = self.web3.eth.getLogs(event_filter_params) # Convert raw binary data to Python proxy objects as described by ABI return tuple(get_event_data(abi, entry) for entry in logs)
def build_filter(self): builder = EventFilterBuilder(self._get_event_abi(), formatter=get_event_data( self._get_event_abi())) builder.address = self.address return builder