def get_contract_events( proxy_manager: ProxyManager, abi: ABI, contract_address: Address, topics: Optional[List[str]] = ALL_EVENTS, from_block: BlockIdentifier = GENESIS_BLOCK_NUMBER, to_block: BlockIdentifier = BLOCK_ID_LATEST, ) -> List[Dict]: """Query the blockchain for all events of the smart contract at `contract_address` that match the filters `topics`, `from_block`, and `to_block`. """ verify_block_number(from_block, "from_block") verify_block_number(to_block, "to_block") events = proxy_manager.client.get_filter_events( contract_address, topics=topics, from_block=from_block, to_block=to_block ) result = [] for event in events: decoded_event = dict(decode_event(abi, event)) if event.get("blockNumber"): decoded_event["block_number"] = event["blockNumber"] del decoded_event["blockNumber"] result.append(decoded_event) return result
def get_channel_participants_from_open_event( token_network: "TokenNetwork", channel_identifier: ChannelID, contract_manager: ContractManager, from_block: BlockNumber, ) -> Optional[Tuple[Address, Address]]: # For this check it is perfectly fine to use a `latest` block number. # Because the filter is looking just for the OPENED event. to_block = "latest" filter_args = get_filter_args_for_specific_event_from_channel( token_network_address=token_network.address, channel_identifier=channel_identifier, event_name=ChannelEvent.OPENED, contract_manager=contract_manager, from_block=from_block, to_block=to_block, ) events = token_network.proxy.contract.web3.eth.getLogs(filter_args) # There must be only one channel open event per channel identifier if len(events) != 1: return None event = decode_event( contract_manager.get_contract_abi(CONTRACT_TOKEN_NETWORK), events[0]) participant1 = Address(decode_hex(event["args"]["participant1"])) participant2 = Address(decode_hex(event["args"]["participant2"])) return participant1, participant2
def find_deposits( web3: Web3, service_address: Address, service_registry_contract: Contract, start_block: BlockNumber, ) -> List[Dict[str, Any]]: """ Return the address of the oldest deposit contract which is not withdrawn """ # Get RegisteredService events for service_address event_abi = dict( service_registry_contract.events[EVENT_REGISTERED_SERVICE]().abi) topics = [ event_abi_to_log_topic(event_abi), bytes([0] * 12) + service_address, ] filter_params = FilterParams({ "fromBlock": start_block, "toBlock": "latest", "address": service_registry_contract.address, "topics": [HexStr("0x" + t.hex()) for t in topics], }) raw_events = web3.eth.getLogs(filter_params) events = [ decode_event(service_registry_contract.abi, event) for event in raw_events ] # Bring events into a pleasant form return [ dict( block_number=e["blockNumber"], valid_till=datetime.utcfromtimestamp( e["args"]["valid_till"]).isoformat(" "), amount=e["args"]["deposit_amount"], deposit_contract=e["args"]["deposit_contract"], withdrawn=not web3.eth.getCode(e["args"]["deposit_contract"]), ) for e in events ]
def settle_timeout(self) -> BlockTimeout: """ Returns the channels settle_timeout. """ # There is no way to get the settle timeout after the channel has been closed as # we're saving gas. Therefore get the ChannelOpened event and get the timeout there. filter_args = get_filter_args_for_specific_event_from_channel( token_network_address=self.token_network.address, channel_identifier=self.channel_identifier, event_name=ChannelEvent.OPENED, contract_manager=self.contract_manager, ) events = self.client.web3.eth.getLogs(filter_args) assert len(events) > 0, "No matching ChannelOpen event found." # we want the latest event here, there might have been multiple channels event = decode_event( self.contract_manager.get_contract_abi(CONTRACT_TOKEN_NETWORK), events[-1]) return event["args"]["settle_timeout"]
def close_block_number(self) -> Optional[BlockNumber]: """ Returns the channel's closed block number. """ # The closed block number is not in the smart contract storage to save # gas. Therefore get the ChannelClosed event is needed here. filter_args = get_filter_args_for_specific_event_from_channel( token_network_address=self.token_network.address, channel_identifier=self.channel_identifier, event_name=ChannelEvent.CLOSED, contract_manager=self.contract_manager, ) events = self.token_network.proxy.contract.web3.eth.getLogs( filter_args) if not events: return None assert len(events) == 1 event = decode_event( self.contract_manager.get_contract_abi(CONTRACT_TOKEN_NETWORK), events[0]) return event["blockNumber"]
def decode_event(self, log: Dict[str, Any]) -> Dict[str, Any]: return decode_event(self.contract.abi, log)
def decode_raiden_event_to_internal( abi: ABI, chain_id: ChainID, log_event: LogReceipt ) -> DecodedEvent: """Enforce the sandwich encoding. Converts the JSON RPC/web3 data types to the internal representation. Note:: This function must only on confirmed data. """ # Note: All addresses inside the event_data must be decoded. decoded_event = decode_event(abi, log_event) if not decoded_event: raise UnknownRaidenEventType() # copy the attribute dict because that data structure is immutable data = dict(decoded_event) args = dict(decoded_event["args"]) data["args"] = args # translate from web3's to raiden's name convention data["block_number"] = log_event["blockNumber"] data["transaction_hash"] = log_event["transactionHash"] data["block_hash"] = bytes(log_event["blockHash"]) # Remove the old names del data["blockNumber"] del data["transactionHash"] del data["blockHash"] assert data["block_number"], "The event must have the block_number" assert data["transaction_hash"], "The event must have the transaction hash field" assert data["block_hash"], "The event must have the block_hash" event = data["event"] if event == EVENT_TOKEN_NETWORK_CREATED: args["token_network_address"] = to_canonical_address(args["token_network_address"]) args["token_address"] = to_canonical_address(args["token_address"]) elif event == ChannelEvent.OPENED: args["participant1"] = to_canonical_address(args["participant1"]) args["participant2"] = to_canonical_address(args["participant2"]) elif event == ChannelEvent.DEPOSIT: args["participant"] = to_canonical_address(args["participant"]) elif event == ChannelEvent.WITHDRAW: args["participant"] = to_canonical_address(args["participant"]) elif event == ChannelEvent.BALANCE_PROOF_UPDATED: args["closing_participant"] = to_canonical_address(args["closing_participant"]) elif event == ChannelEvent.CLOSED: args["closing_participant"] = to_canonical_address(args["closing_participant"]) elif event == ChannelEvent.UNLOCKED: args["receiver"] = to_canonical_address(args["receiver"]) args["sender"] = to_canonical_address(args["sender"]) return DecodedEvent( chain_id=chain_id, originating_contract=to_canonical_address(log_event["address"]), event_data=data, block_number=log_event["blockNumber"], block_hash=BlockHash(log_event["blockHash"]), transaction_hash=TransactionHash(log_event["transactionHash"]), )
def decode_event(self, log: Dict): return decode_event(self.contract.abi, log)