def match_fn(codec: ABICodec, match_values_and_abi: Collection[Tuple[str, Any]], data: Any) -> bool: """Match function used for filtering non-indexed event arguments. Values provided through the match_values_and_abi parameter are compared to the abi decoded log data. """ abi_types, all_match_values = zip(*match_values_and_abi) decoded_values = codec.decode_abi(abi_types, HexBytes(data)) for data_value, match_values, abi_type in zip(decoded_values, all_match_values, abi_types): if match_values is None: continue normalized_data = normalize_data_values(abi_type, data_value) for value in match_values: if not codec.is_encodable(abi_type, value): raise ValueError(f"Value {value} is of the wrong abi type. " f"Expected {abi_type} typed value.") if value == normalized_data: break else: return False return True
def __init__(self, receipt): self.raw_receipt = receipt self.transaction_hash = receipt['transactionHash'] self.gas_used = receipt['gasUsed'] self.transfers = [] self.result = None receipt_logs = receipt['logs'] if (receipt_logs is not None) and (len(receipt_logs) > 0): self.successful = True for receipt_log in receipt_logs: if len(receipt_log['topics']) > 0: # $ seth keccak $(seth --from-ascii "Transfer(address,address,uint256)") # 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef if receipt_log['topics'][0] == HexBytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'): from pymaker.token import ERC20Token transfer_abi = [abi for abi in ERC20Token.abi if abi.get('name') == 'Transfer'][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, transfer_abi, receipt_log) self.transfers.append(Transfer(token_address=Address(event_data['address']), from_address=Address(event_data['args']['from']), to_address=Address(event_data['args']['to']), value=Wad(event_data['args']['value']))) # $ seth keccak $(seth --from-ascii "Mint(address,uint256)") # 0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885 if receipt_log['topics'][0] == HexBytes('0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885'): from pymaker.token import DSToken transfer_abi = [abi for abi in DSToken.abi if abi.get('name') == 'Mint'][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, transfer_abi, receipt_log) self.transfers.append(Transfer(token_address=Address(event_data['address']), from_address=Address('0x0000000000000000000000000000000000000000'), to_address=Address(event_data['args']['guy']), value=Wad(event_data['args']['wad']))) # $ seth keccak $(seth --from-ascii "Burn(address,uint256)") # 0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5 if receipt_log['topics'][0] == HexBytes('0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5'): from pymaker.token import DSToken transfer_abi = [abi for abi in DSToken.abi if abi.get('name') == 'Burn'][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, transfer_abi, receipt_log) self.transfers.append(Transfer(token_address=Address(event_data['address']), from_address=Address(event_data['args']['guy']), to_address=Address('0x0000000000000000000000000000000000000000'), value=Wad(event_data['args']['wad']))) else: self.successful = False
def __init__(self, provider=None, middlewares=None, modules=None, ens=empty): self.manager = self.RequestManager(self, provider, middlewares) if modules is None: modules = get_default_modules() attach_modules(self, modules) self.codec = ABICodec(build_default_registry()) self.ens = ens
def __init__( self, provider: Optional[BaseProvider] = None, middlewares: Optional[Sequence[Any]] = None, modules: Optional[Dict[str, Sequence[Any]]] = None, ens: ENS = cast(ENS, empty) ) -> None: self.manager = self.RequestManager(self, provider, middlewares) if modules is None: modules = get_default_modules() attach_modules(self, modules) self.codec = ABICodec(build_default_registry()) self.ens = ens
def parse_event(self, event): signature = Web3.toHex(event['topics'][0]) codec = ABICodec(default_registry) if signature == "0xc84ce3a1172f0dec3173f04caaa6005151a4bfe40d4c9f3ea28dba5f719b2a7a": event_data = get_event_data(codec, self.kick_abi, event) return Flipper.KickLog(event_data) else: event_data = get_event_data(codec, self.log_note_abi, event) return LogNote(event_data)
def parse_event(self, event): signature = Web3.toHex(event['topics'][0]) codec = ABICodec(default_registry) if signature == "0x7e8881001566f9f89aedb9c5dc3d856a2b81e5235a8196413ed484be91cc0df6": event_data = get_event_data(codec, self.kick_abi, event) return Flopper.KickLog(event_data) else: event_data = get_event_data(codec, self.log_note_abi, event) return LogNote(event_data)
def __init__( self, provider: Optional[BaseProvider] = None, middlewares: Optional[Sequence[Any]] = None, modules: Optional[Dict[str, Sequence[Any]]] = None, ens: ENS = cast(ENS, empty) ) -> None: self.manager = self.RequestManager(self, provider, middlewares) # this codec gets used in the module initialization, # so it needs to come before attach_modules self.codec = ABICodec(build_default_registry()) if modules is None: modules = get_default_modules() attach_modules(self, modules) self.ens = ens
def parse_event(self, event): signature = Web3.toHex(event['topics'][0]) codec = ABICodec(default_registry) if signature == "0xe6dde59cbc017becba89714a037778d234a84ce7f0a137487142a007e580d609": event_data = get_event_data(codec, self.kick_abi, event) return Flapper.KickLog(event_data) else: event_data = get_event_data(codec, self.log_note_abi, event) return LogNote(event_data)
def from_event(cls, event: dict): assert(isinstance(event, dict)) topics = event.get('topics') if topics and topics[0] == HexBytes('0x3383e3357c77fd2e3a4b30deea81179bc70a795d053d14d5b7f2f01d0fd4596f'): log_take_abi = [abi for abi in SimpleMarket.abi if abi.get('name') == 'LogTake'][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, log_take_abi, event) return LogTake(event_data)
def from_receipt(cls, receipt: Receipt): assert(isinstance(receipt, Receipt)) if receipt.logs is not None: for log in receipt.logs: if len(log['topics']) > 0 and log['topics'][0] == HexBytes('0x773ff502687307abfa024ac9f62f9752a0d210dac2ffd9a29e38e12e2ea82c82'): log_make_abi = [abi for abi in SimpleMarket.abi if abi.get('name') == 'LogMake'][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, log_make_abi, log) yield LogMake(event_data)
def from_event(cls, event: AttributeDict, contract_abi: list): assert isinstance(event, AttributeDict) assert isinstance(contract_abi, list) log_note_abi = [abi for abi in contract_abi if abi.get('name') == 'LogNote'][0] try: codec = ABICodec(default_registry) event_data = get_event_data(codec, log_note_abi, event) return LogNote(event_data) except ValueError: # event is not a LogNote return None
def from_event(cls, event: dict): assert isinstance(event, dict) topics = event.get('topics') if topics and topics[0] == HexBytes('0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8'): log_bite_abi = [abi for abi in Cat.abi if abi.get('name') == 'Bite'][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, log_bite_abi, event) return Cat.LogBite(event_data) else: logging.warning(f'[from_event] Invalid topic in {event}')
async def poll_zeroex_logs_loop(self): while True: try: new_blocks: List[ AttributeDict] = await self._new_blocks_queue.get() for block in new_blocks: block_bloom_filter = BloomFilter( int.from_bytes(block["logsBloom"], byteorder='big')) if FILL_EVENT_TOPIC in block_bloom_filter: # Potentially a Fill for an order hash we are interested in order_hashes: List[str] = [] for order_hash in self._watch_order_hashes: if bytes.fromhex(order_hash) in block_bloom_filter: order_hashes.append("0x" + order_hash) if len(order_hashes) > 0: fill_entries = await self._get_logs({ 'topics': [ "0x6869791f0a34781b29882982cc39e882768cf2c96995c2a110c577c53bc932d5", None, None, order_hashes ], 'blockhash': block["hash"].hex() }) for fill_entry in fill_entries: event_data: AttributeDict = get_event_data( ABICodec(registry), self._event_abi, fill_entry) event_data_tx_hash: HexBytes = event_data[ "transactionHash"] # Skip any duplicates if event_data_tx_hash not in self._event_cache: await self._handle_event_data(event_data) # Mark all of these as processed now, since each tx may contain multiple Fill logs for fill_entry in fill_entries: event_data_tx_hash: HexBytes = fill_entry[ "transactionHash"] if event_data_tx_hash not in self._event_cache: self._event_cache.add(event_data_tx_hash) except asyncio.CancelledError: raise except asyncio.TimeoutError: continue except Exception: self.logger().network( "Unknown error trying to fetch new events for ZeroEx fills.", exc_info=True, app_warning_msg= "Unknown error trying to fetch new events for ZeroEx fills. " "Check wallet network connection")
def parse_event(self, event): signature = Web3.toHex(event['topics'][0]) codec = ABICodec(default_registry) if signature == "0x9102bd0b66dcb83f469f1122a583dc797657b114141460c59230fc1b41f48229": event_data = get_event_data(codec, self.start_auction_abi, event) return DebtAuctionHouse.StartAuctionLog(event_data) elif signature == "0x8c63feacc784a7f735e454365ba433f17d17293b02c57d98dad113977dbf0f13": event_data = get_event_data(codec, self.decrease_sold_amount_abi, event) return DebtAuctionHouse.DecreaseSoldAmountLog(event_data) elif signature == "0xef063949eb6ef5abef19139d9c75a558424ffa759302cfe445f8d2d327376fe4": event_data = get_event_data(codec, self.settle_auction_abi, event) return DebtAuctionHouse.SettleAuctionLog(event_data)
def from_event(cls, event: dict): assert (isinstance(event, dict)) topics = event.get('topics') if topics and topics[0] == HexBytes( '0x0bcc4c97732e47d9946f229edb95f5b6323f601300e4690de719993f3c371129' ): log_fill_abi = [ abi for abi in ZrxExchangeV2.abi if abi.get('name') == 'Fill' ][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, log_fill_abi, event) return LogFill(event_data)
def parse_event(self, event): signature = Web3.toHex(event['topics'][0]) codec = ABICodec(default_registry) if signature == "0x7c5bfdc0a5e8192f6cd4972f382cec69116862fb62e6abff8003874c58e064b8": event_data = get_event_data(codec, self.kick_abi, event) return Clipper.KickLog(event_data) elif signature == "0x05e309fd6ce72f2ab888a20056bb4210df08daed86f21f95053deb19964d86b1": event_data = get_event_data(codec, self.take_abi, event) self._get_sender_for_eventlog(event_data) return Clipper.TakeLog(event_data, self._get_sender_for_eventlog(event_data)) elif signature == "0x275de7ecdd375b5e8049319f8b350686131c219dd4dc450a08e9cf83b03c865f": event_data = get_event_data(codec, self.redo_abi, event) return Clipper.RedoLog(event_data) else: logger.debug(f"Found event signature {signature}")
def parse_event(self, event): signature = Web3.toHex(event['topics'][0]) codec = ABICodec(default_registry) if signature == "0xdf7b5cd0ee6547c7389d2ac00ee0c1cd3439542399d6c8c520cc69c7409c0990": event_data = get_event_data(codec, self.start_auction_abi, event) return FixedDiscountCollateralAuctionHouse.StartAuctionLog( event_data) elif signature == "0xa4a1133e32fac37643a1fe1db4631daadb462c8662ae16004e67f0b8bb608383": event_data = get_event_data(codec, self.buy_collateral_abi, event) return FixedDiscountCollateralAuctionHouse.BuyCollateralLog( event_data) elif signature == "0xef063949eb6ef5abef19139d9c75a558424ffa759302cfe445f8d2d327376fe4": event_data = get_event_data(codec, self.settle_auction_abi, event) return FixedDiscountCollateralAuctionHouse.SettleAuctionLog( event_data)
def parse_event(self, event): signature = Web3.toHex(event['topics'][0]) codec = ABICodec(default_registry) if signature == "0xa4863af70e77aecfe2769e0569806782ba7c6f86fc9a307290a3816fb8a563e5": event_data = get_event_data(codec, self.start_auction_abi, event) return PreSettlementSurplusAuctionHouse.StartAuctionLog(event_data) elif signature == "0xd87c815d5a67c2e130ad04b714d87a6fb69d5a6df0dbb0f1639cd9fe292201f9": event_data = get_event_data(codec, self.increase_bid_size_abi, event) return PreSettlementSurplusAuctionHouse.IncreaseBidSizeLog( event_data) elif signature == "0x03af424b0e12d91ea31fe7f2c199fc02c9ede38f9aa1bdc019a8087b41445f7a": event_data = get_event_data(codec, self.settle_auction_abi, event) return PreSettlementSurplusAuctionHouse.SettleAuctionLog( event_data)
def from_event(cls, event: dict): assert (isinstance(event, dict)) topics = event.get('topics') if topics and topics[0] == HexBytes( '0x259b30ca39885c6d801a0b5dbc988640f3c25e2f37531fe138c5c5af8955d41b' ): log_created_abi = [ abi for abi in DSProxyFactory.abi if abi.get('name') == 'Created' ][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, log_created_abi, event) return LogCreated(event_data) else: raise Exception(f'[from_event] Invalid topic in {event}')
def parse_event(self, event): signature = Web3.toHex(event['topics'][0]) codec = ABICodec(default_registry) if signature == "0xdf7b5cd0ee6547c7389d2ac00ee0c1cd3439542399d6c8c520cc69c7409c0990": event_data = get_event_data(codec, self.start_auction_abi, event) return EnglishCollateralAuctionHouse.StartAuctionLog(event_data) elif signature == "0xd87c815d5a67c2e130ad04b714d87a6fb69d5a6df0dbb0f1639cd9fe292201f9": event_data = get_event_data(codec, self.increase_bid_size_abi, event) return EnglishCollateralAuctionHouse.IncreaseBidSizeLog(event_data) elif signature == "0x8c63feacc784a7f735e454365ba433f17d17293b02c57d98dad113977dbf0f13": event_data = get_event_data(codec, self.decrease_sold_amount_abi, event) return EnglishCollateralAuctionHouse.DecreaseSoldAmountLog( event_data) elif signature == "0x03af424b0e12d91ea31fe7f2c199fc02c9ede38f9aa1bdc019a8087b41445f7a": event_data = get_event_data(codec, self.settle_auction_abi, event) return EnglishCollateralAuctionHouse.SettleAuctionLog(event_data)
def construct_event_data_set( event_abi: ABIEvent, abi_codec: ABICodec, arguments: Optional[Union[Sequence[Any], Dict[str, Any]]] = None ) -> List[List[Optional[HexStr]]]: if arguments is None: arguments = {} if isinstance(arguments, (list, tuple)): if len(arguments) != len(event_abi['inputs']): raise ValueError( "When passing an argument list, the number of arguments must " "match the event constructor." ) arguments = { arg['name']: [arg_value] for arg, arg_value in zip(event_abi['inputs'], arguments) } normalized_args = { key: value if is_list_like(value) else [value] # type ignored b/c at this point arguments is always a dict for key, value in arguments.items() # type: ignore } non_indexed_args = exclude_indexed_event_inputs(event_abi) zipped_abi_and_args = [ (arg, normalized_args.get(arg['name'], [None])) for arg in non_indexed_args ] encoded_args = [ [ None if option is None else encode_hex(abi_codec.encode_single(arg['type'], option)) for option in arg_options] for arg, arg_options in zipped_abi_and_args ] data = [ list(permutation) if any(value is not None for value in permutation) else [] for permutation in itertools.product(*encoded_args) ] return data
def construct_event_topic_set( event_abi: ABIEvent, abi_codec: ABICodec, arguments: Optional[Union[Sequence[Any], Dict[str, Any]]] = None ) -> List[HexStr]: if arguments is None: arguments = {} if isinstance(arguments, (list, tuple)): if len(arguments) != len(event_abi['inputs']): raise ValueError( "When passing an argument list, the number of arguments must " "match the event constructor." ) arguments = { arg['name']: [arg_value] for arg, arg_value in zip(event_abi['inputs'], arguments) } normalized_args = { key: value if is_list_like(value) else [value] # type ignored b/c arguments is always a dict at this point for key, value in arguments.items() # type: ignore } # typed dict cannot be used w/ a normal Dict # https://github.com/python/mypy/issues/4976 event_topic = encode_hex(event_abi_to_log_topic(event_abi)) # type: ignore indexed_args = get_indexed_event_inputs(event_abi) zipped_abi_and_args = [ (arg, normalized_args.get(arg['name'], [None])) for arg in indexed_args ] encoded_args = [ [ None if option is None else encode_hex(abi_codec.encode_single(arg['type'], option)) for option in arg_options] for arg, arg_options in zipped_abi_and_args ] topics = list(normalize_topic_list([event_topic] + encoded_args)) # type: ignore return topics
def from_receipt(cls, contract_abi: List, receipt: Receipt): assert (isinstance(contract_abi, List)) assert (isinstance(receipt, Receipt)) mint_logs = [] if receipt.logs is not None: for log in receipt.logs: if len(log['topics']) > 0 and log['topics'][0] == HexBytes( '0x7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde' ): log_mint_abi = [ abi for abi in contract_abi if abi.get('name') == 'Mint' ][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, log_mint_abi, log) mint_logs.append(LogMint(event_data)) return mint_logs
def from_receipt(cls, contract_abi: List, receipt: Receipt): assert (isinstance(contract_abi, List)) assert (isinstance(receipt, Receipt)) initialize_logs = [] if receipt.logs is not None: for log in receipt.logs: if len(log['topics']) > 0 and log['topics'][0] == HexBytes( '0x98636036cb66a9c19a37435efc1e90142190214e8abeb821bdba3f2990dd4c95' ): log_initialize_abi = [ abi for abi in contract_abi if abi.get('name') == 'Initialize' ][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, log_initialize_abi, log) initialize_logs.append(LogInitialize(event_data)) return initialize_logs
def from_receipt(cls, contract_abi: List, receipt: Receipt): assert (isinstance(contract_abi, List)) assert (isinstance(receipt, Receipt)) swap_logs = [] if receipt.logs is not None: for log in receipt.logs: if len(log['topics']) > 0 and log['topics'][0] == HexBytes( '0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67' ): log_swap_abi = [ abi for abi in contract_abi if abi.get('name') == 'Swap' ][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, log_swap_abi, log) swap_logs.append(LogSwap(event_data)) return swap_logs
def from_receipt(cls, contract_abi: List, receipt: Receipt): assert (isinstance(contract_abi, List)) assert (isinstance(receipt, Receipt)) liquidity_logs = [] if receipt.logs is not None: for log in receipt.logs: if len(log['topics']) > 0 and log['topics'][0] == HexBytes( '0x40d0efd1a53d60ecbf40971b9daf7dc90178c3aadc7aab1765632738fa8b8f01' ): log_collect_abi = [ abi for abi in contract_abi if abi.get('name') == 'Collect' ][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, log_collect_abi, log) liquidity_logs.append(LogCollect(event_data)) return liquidity_logs
def from_receipt(cls, contract_abi: List, receipt: Receipt): assert (isinstance(contract_abi, List)) assert (isinstance(receipt, Receipt)) liquidity_logs = [] if receipt.logs is not None: for log in receipt.logs: if len(log['topics']) > 0 and log['topics'][0] == HexBytes( '0x26f6a048ee9138f2c0ce266f322cb99228e8d619ae2bff30c67f8dcf9d2377b4' ): log_decrease_liquidity_abi = [ abi for abi in contract_abi if abi.get('name') == 'DecreaseLiquidity' ][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, log_decrease_liquidity_abi, log) liquidity_logs.append(LogDecreaseLiquidity(event_data)) return liquidity_logs
def from_receipt(cls, contract_abi: List, receipt: Receipt): assert (isinstance(contract_abi, List)) assert (isinstance(receipt, Receipt)) liquidity_logs = [] if receipt.logs is not None: for log in receipt.logs: if len(log['topics']) > 0 and log['topics'][0] == HexBytes( '0x3067048beee31b25b2f1681f88dac838c8bba36af25bfb2b7cf7473a5847e35f' ): log_increase_liquidity_abi = [ abi for abi in contract_abi if abi.get('name') == 'IncreaseLiquidity' ][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, log_increase_liquidity_abi, log) liquidity_logs.append(LogIncreaseLiquidity(event_data)) return liquidity_logs
from eth_abi.codec import ( ABICodec, ) from eth_abi.registry import ( registry, ) default_codec = ABICodec(registry) encode = default_codec.encode decode = default_codec.decode is_encodable = default_codec.is_encodable is_encodable_type = default_codec.is_encodable_type
def get_event_data(abi_codec: ABICodec, event_abi: ABIEvent, log_entry: LogReceipt) -> EventData: """ Given an event ABI and a log entry for that event, return the decoded event data """ if event_abi['anonymous']: log_topics = log_entry['topics'] elif not log_entry['topics']: raise MismatchedABI("Expected non-anonymous event to have 1 or more topics") # type ignored b/c event_abi_to_log_topic(event_abi: Dict[str, Any]) elif event_abi_to_log_topic(event_abi) != log_entry['topics'][0]: # type: ignore raise MismatchedABI("The event signature did not match the provided ABI") else: log_topics = log_entry['topics'][1:] log_topics_abi = get_indexed_event_inputs(event_abi) log_topic_normalized_inputs = normalize_event_input_types(log_topics_abi) log_topic_types = get_event_abi_types_for_decoding(log_topic_normalized_inputs) log_topic_names = get_abi_input_names(ABIEvent({'inputs': log_topics_abi})) if len(log_topics) != len(log_topic_types): raise LogTopicError("Expected {0} log topics. Got {1}".format( len(log_topic_types), len(log_topics), )) log_data = hexstr_if_str(to_bytes, log_entry['data']) log_data_abi = exclude_indexed_event_inputs(event_abi) log_data_normalized_inputs = normalize_event_input_types(log_data_abi) log_data_types = get_event_abi_types_for_decoding(log_data_normalized_inputs) log_data_names = get_abi_input_names(ABIEvent({'inputs': log_data_abi})) # sanity check that there are not name intersections between the topic # names and the data argument names. duplicate_names = set(log_topic_names).intersection(log_data_names) if duplicate_names: raise InvalidEventABI( "The following argument names are duplicated " f"between event inputs: '{', '.join(duplicate_names)}'" ) decoded_log_data = abi_codec.decode_abi(log_data_types, log_data) normalized_log_data = map_abi_data( BASE_RETURN_NORMALIZERS, log_data_types, decoded_log_data ) decoded_topic_data = [ abi_codec.decode_single(topic_type, topic_data) for topic_type, topic_data in zip(log_topic_types, log_topics) ] normalized_topic_data = map_abi_data( BASE_RETURN_NORMALIZERS, log_topic_types, decoded_topic_data ) event_args = dict(itertools.chain( zip(log_topic_names, normalized_topic_data), zip(log_data_names, normalized_log_data), )) event_data = { 'args': event_args, 'event': event_abi['name'], 'logIndex': log_entry['logIndex'], 'transactionIndex': log_entry['transactionIndex'], 'transactionHash': log_entry['transactionHash'], 'address': log_entry['address'], 'blockHash': log_entry['blockHash'], 'blockNumber': log_entry['blockNumber'], } return cast(EventData, AttributeDict.recursive(event_data))