"""Event parsing utilities for Arbitrum SDK.This module provides utilities for parsing and decoding Ethereum event logs,with type-safe interfaces similar to TypeScript's TypedEvent system."""fromtypingimportAny,Dict,List,Optional,TypeVar,castfrometh_typingimportHexStrfromtyping_extensionsimportProtocol,TypedDictfromweb3importWeb3fromweb3.exceptionsimportABIFunctionNotFound,LogTopicErrorfromweb3.typesimportEventData,LogReceiptfromarbitrum_py.utils.helperimportCaseDict,create_contract_instance,load_contract
[docs]classEventArgs(TypedDict,total=False):"""Base type for event arguments."""pass
T=TypeVar("T",bound=EventArgs)
[docs]classTypedEvent(Protocol[T]):"""Protocol for typed events, similar to TypeScript's TypedEvent."""args:T
[docs]classContractEventProcessor(Protocol):"""Protocol for contract event processing interface."""
[docs]defparse_typed_log(contract_name:str,log:Dict[str,Any],event_name:str,)->Optional[Dict[str,Any]]:"""Parse a single log entry against a specific event. This function attempts to decode a log entry using the specified event's ABI. If the log's topic matches the event signature, it returns the decoded arguments. Args: contract_name: Name of the contract containing the event definition log: Log dictionary from transaction receipt event_name: Name of the event to decode (e.g. 'WithdrawalInitiated') Returns: Decoded event arguments if log matches event signature, None otherwise Raises: ValueError: If event not found in contract ABI ABIFunctionNotFound: If contract ABI is invalid """contract=create_contract_instance(contract_name)try:event=getattr(contract.events,event_name)exceptABIFunctionNotFound:raiseValueError(f"Event {event_name} not found in contract {contract_name}")# Get event signatureevent_abi=next((eforeincontract.abiife.get("type")=="event"ande.get("name")==event_name),None)ifnotevent_abi:raiseValueError(f"Event {event_name} not found in contract ABI")event_signature=Web3.keccak(text=f"{event_name}({','.join(inp['type']forinpinevent_abi['inputs'])})").hex()try:# Check if log matches event signaturelog_topic=Web3.to_hex(log["topics"][0])iflog_topicandlog_topic==event_signature:# Convert to LogReceipt format and processlog_receipt=LogReceipt(log)try:decoded_log=event().process_log(log_receipt)returnCaseDict(decoded_log["args"])except(LogTopicError,ValueError):returnNoneexcept(KeyError,IndexError):returnNonereturnNone
[docs]defparse_typed_logs(contract_name:str,logs:List[Dict[str,Any]],event_name:str,)->List[Dict[str,Any]]:"""Parse multiple logs against a specific event. This function processes an array of logs, filtering out any that don't match the specified event's signature and decoding the matching ones. Args: contract_name: Name of the contract containing the event definition logs: List of log dictionaries from transaction receipt event_name: Name of the event to decode (e.g. 'WithdrawalInitiated') Returns: List of decoded event arguments from matching logs Raises: ValueError: If event not found in contract ABI ABIFunctionNotFound: If contract ABI is invalid """return[log_argsforloginlogsif(log_args:=parse_typed_log(contract_name,log,event_name))isnotNone]
[docs]defget_event_signature(contract_name:str,event_name:str)->HexStr:"""Get the keccak256 signature hash for an event. Computes the event signature by concatenating the event name with its parameter types and taking the keccak256 hash. Args: contract_name: Name of the contract containing the event event_name: Name of the event to get signature for Returns: Hex string of the event signature hash Raises: ValueError: If event not found in contract ABI """contract=load_contract(contract_name)event_abi=next((eforeincontract.abiife.get("type")=="event"ande.get("name")==event_name),None)ifnotevent_abi:raiseValueError(f"Event {event_name} not found in {contract_name}")signature=Web3.keccak(text=f"{event_name}({','.join(inp['type']forinpinevent_abi['inputs'])})").hex()returncast(HexStr,signature)