def extract_transfer_from_log(self, receipt_log: Union[KlaytnRawReceiptLog, KlaytnReceiptLog]) -> Union[KlaytnRawTokenTransfer, KlaytnTokenTransfer, None]: if self.enrich and not isinstance(receipt_log, KlaytnReceiptLog): logger.warning("Cannot extract enrich token transfer from raw receipt log. It will return raw token transfer.") topics = receipt_log.topics if topics is None or len(topics) < 1: logger.warning("Topics are empty in log {} of transaction {}".format(receipt_log.log_index, receipt_log.transaction_hash)) return None if topics[0] == TRANSFER_EVENT_TOPIC: # Handle unindexed event fields topics_with_data = topics + split_to_words(receipt_log.data) # if the number of topics and fields in data part != 4, then it's a weird event if len(topics_with_data) != 4: logger.warning("The number of topics and data parts is not equal to 4 in log {} of transaction {}" .format(receipt_log.log_index, receipt_log.transaction_hash)) return None if not self.enrich or not isinstance(receipt_log, KlaytnReceiptLog): token_transfer = KlaytnRawTokenTransfer() token_transfer.token_address = to_normalized_address(receipt_log.address) token_transfer.from_address = word_to_address(topics_with_data[1]) token_transfer.to_address = word_to_address(topics_with_data[2]) token_transfer.value = hex_to_dec(topics_with_data[3]) token_transfer.log_index = receipt_log.log_index token_transfer.transaction_hash = receipt_log.transaction_hash token_transfer.transaction_index = receipt_log.transaction_index token_transfer.block_number = receipt_log.block_number token_transfer.block_hash = receipt_log.block_hash return token_transfer else: token_transfer = KlaytnTokenTransfer() token_transfer.token_address = to_normalized_address(receipt_log.address) token_transfer.from_address = word_to_address(topics_with_data[1]) token_transfer.to_address = word_to_address(topics_with_data[2]) token_transfer.value = hex_to_dec(topics_with_data[3]) token_transfer.log_index = receipt_log.log_index token_transfer.transaction_hash = receipt_log.transaction_hash token_transfer.transaction_index = receipt_log.transaction_index token_transfer.block_number = receipt_log.block_number token_transfer.block_hash = receipt_log.block_hash # enrich token_transfer.block_timestamp = receipt_log.block_timestamp token_transfer.block_unix_timestamp = receipt_log.block_unix_timestamp token_transfer.transaction_receipt_status = receipt_log.transaction_receipt_status return token_transfer return None
def json_dict_to_trace(self, json_dict): trace = EthTrace() trace.block_number = json_dict.get('blockNumber') trace.transaction_hash = json_dict.get('transactionHash') trace.transaction_index = json_dict.get('transactionPosition') trace.subtraces = json_dict.get('subtraces') trace.trace_address = json_dict.get('traceAddress', []) error = json_dict.get('error') if error: trace.error = error action = json_dict.get('action') if action is None: action = {} result = json_dict.get('result') if result is None: result = {} trace_type = json_dict.get('type') trace.trace_type = trace_type # common fields in call/create if trace_type in ('call', 'create'): trace.from_address = to_normalized_address(action.get('from')) trace.value = hex_to_dec(action.get('value')) trace.gas = hex_to_dec(action.get('gas')) trace.gas_used = hex_to_dec(result.get('gasUsed')) # process different trace types if trace_type == 'call': trace.call_type = action.get('callType') trace.to_address = to_normalized_address(action.get('to')) trace.input = action.get('input') trace.output = result.get('output') elif trace_type == 'create': trace.to_address = result.get('address') trace.input = action.get('init') trace.output = result.get('code') elif trace_type == 'suicide': trace.from_address = to_normalized_address(action.get('address')) trace.to_address = to_normalized_address( action.get('refundAddress')) trace.value = hex_to_dec(action.get('balance')) elif trace_type == 'reward': trace.to_address = to_normalized_address(action.get('author')) trace.value = hex_to_dec(action.get('value')) trace.reward_type = action.get('rewardType') return trace
def json_dict_to_transaction( self, json_dict, **kwargs) -> Union[KlaytnTransaction, KlaytnRawTransaction]: _transaction = KlaytnRawTransaction() _transaction.hash = json_dict.get('transactionHash') _transaction.nonce = hex_to_dec(json_dict.get('nonce')) _transaction.block_hash = json_dict.get('blockHash') _transaction.block_number = hex_to_dec(json_dict.get('blockNumber')) _transaction.transaction_index = hex_to_dec( json_dict.get('transactionIndex')) _transaction.from_address = to_normalized_address( json_dict.get('from')) _transaction.to_address = to_normalized_address(json_dict.get('to')) _transaction.value = hex_to_dec(json_dict.get('value')) _transaction.gas = hex_to_dec(json_dict.get('gas')) _transaction.gas_price = hex_to_dec(json_dict.get('gasPrice')) _transaction.input = json_dict.get('input') # Klaytn additional properties _transaction.fee_payer = json_dict.get('feePayer') _transaction.fee_payer_signatures = json_dict.get('feePayerSignatures') # FIXME: deal with null input _transaction.fee_ratio = hex_to_dec(json_dict.get('feeRatio')) _transaction.sender_tx_hash = json_dict.get('senderTxHash') _transaction.signatures = json_dict.get('signatures') _transaction.tx_type = json_dict.get('type') _transaction.tx_type_int = json_dict.get('typeInt') if self.enrich and 'logs' in json_dict: _transaction.logs = [ self.receipt_log_mapper.json_dict_to_receipt_log( log, block_timestamp=kwargs.get('block_timestamp'), block_timestamp_fos=kwargs.get('block_timestamp_fos'), transaction_receipt_status=hex_to_dec( json_dict.get('status')), enrich=self.enrich) for log in json_dict['logs'] ] else: del _transaction.logs return _transaction if not self.enrich else KlaytnTransaction.enrich( _transaction, block_timestamp=kwargs.get('block_timestamp'), block_timestamp_fos=kwargs.get('block_timestamp_fos'), receipt_gas_used=hex_to_dec(json_dict.get('gasUsed')), receipt_status=hex_to_dec(json_dict.get('status')), receipt_contract_address=to_normalized_address( json_dict.get('contractAddress')))
def json_dict_to_receipt_log(self, json_dict): receipt_log = EthReceiptLog() receipt_log.log_index = hex_to_dec(json_dict.get('logIndex')) receipt_log.transaction_hash = json_dict.get('transactionHash') receipt_log.transaction_index = hex_to_dec(json_dict.get('transactionIndex')) receipt_log.block_hash = json_dict.get('blockHash') receipt_log.block_number = hex_to_dec(json_dict.get('blockNumber')) receipt_log.address = json_dict.get('address') receipt_log.data = json_dict.get('data') receipt_log.topics = json_dict.get('topics') return receipt_log
def extract_transfer_from_log(self, receipt_log): topics = receipt_log.topics if topics is None or len(topics) < 1: logger.warning("Topics are empty in log {} of transaction {}".format(receipt_log.log_index, receipt_log.transaction_hash)) return None if topics[0] == TRANSFER_EVENT_TOPIC: # Handle unindexed event fields topics_with_data = topics + split_to_words(receipt_log.data) # if the number of topics and fields in data part != 4, then it's a weird event if len(topics_with_data) != 4: logger.warning("The number of topics and data parts is not equal to 4 in log {} of transaction {}" .format(receipt_log.log_index, receipt_log.transaction_hash)) return None token_transfer = EthTokenTransfer() token_transfer.token_address = to_normalized_address(receipt_log.address) token_transfer.from_address = word_to_address(topics_with_data[1]) token_transfer.to_address = word_to_address(topics_with_data[2]) token_transfer.value = hex_to_dec(topics_with_data[3]) token_transfer.transaction_hash = receipt_log.transaction_hash token_transfer.log_index = receipt_log.log_index token_transfer.block_number = receipt_log.block_number return token_transfer return None
def _iterate_transaction_trace(self, block_number, tx_index, tx_trace, trace_address=[]): trace = EthTrace() trace.block_number = block_number trace.transaction_index = tx_index trace.from_address = to_normalized_address(tx_trace.get('from')) trace.to_address = to_normalized_address(tx_trace.get('to')) trace.input = tx_trace.get('input') trace.output = tx_trace.get('output') trace.value = hex_to_dec(tx_trace.get('value')) trace.gas = hex_to_dec(tx_trace.get('gas')) trace.gas_used = hex_to_dec(tx_trace.get('gasUsed')) trace.error = tx_trace.get('error') # lowercase for compatibility with parity traces trace.trace_type = tx_trace.get('type').lower() if trace.trace_type == 'selfdestruct': # rename to suicide for compatibility with parity traces trace.trace_type = 'suicide' elif trace.trace_type in ('call', 'callcode', 'delegatecall', 'staticcall'): trace.call_type = trace.trace_type trace.trace_type = 'call' result = [trace] calls = tx_trace.get('calls', []) trace.subtraces = len(calls) trace.trace_address = trace_address for call_index, call_trace in enumerate(calls): result.extend( self._iterate_transaction_trace(block_number, tx_index, call_trace, trace_address + [call_index])) return result
def json_dict_to_transaction(self, json_dict, **kwargs): transaction = EthTransaction() transaction.hash = json_dict.get('transactionHash') transaction.nonce = hex_to_dec(json_dict.get('nonce')) transaction.block_hash = json_dict.get('blockHash') transaction.block_number = hex_to_dec(json_dict.get('blockNumber')) transaction.block_timestamp = kwargs.get('block_timestamp') transaction.transaction_index = hex_to_dec( json_dict.get('transactionIndex')) transaction.from_address = to_normalized_address(json_dict.get('from')) transaction.to_address = to_normalized_address(json_dict.get('to')) transaction.value = hex_to_dec(json_dict.get('value')) transaction.gas = hex_to_dec(json_dict.get('gas')) transaction.gas_price = hex_to_dec(json_dict.get('gasPrice')) transaction.input = json_dict.get('input') # Klaytn additional properties transaction.fee_payer = json_dict.get('feePayer') transaction.fee_payer_signatures = json_dict.get('feePayerSignatures') # FIXME: deal with null input transaction.fee_ratio = hex_to_dec(json_dict.get('feeRatio')) transaction.sender_tx_hash = json_dict.get('senderTxHash') transaction.signatures = json_dict.get('signatures') transaction.tx_type = json_dict.get('type') transaction.tx_type_int = json_dict.get('typeInt') return transaction
def json_dict_to_receipt_log(self, json_dict, **kwargs) -> Union[KlaytnRawReceiptLog, KlaytnReceiptLog]: _receipt_log = KlaytnRawReceiptLog() _receipt_log.log_index = hex_to_dec(json_dict.get('logIndex')) _receipt_log.transaction_hash = json_dict.get('transactionHash') _receipt_log.transaction_index = hex_to_dec(json_dict.get('transactionIndex')) _receipt_log.block_hash = json_dict.get('blockHash') _receipt_log.block_number = hex_to_dec(json_dict.get('blockNumber')) _receipt_log.address = json_dict.get('address') _receipt_log.data = json_dict.get('data') _receipt_log.topics = json_dict.get('topics') return _receipt_log if not self.enrich else KlaytnReceiptLog.enrich(_receipt_log, block_timestamp=kwargs.get('block_timestamp'), block_timestamp_fos=kwargs.get('transaction_receipt_status'), transaction_receipt_status=kwargs.get('transaction_receipt_status'))
def json_dict_to_receipt(self, json_dict) -> KlaytnRawReceipt: receipt = KlaytnRawReceipt() receipt.transaction_hash = json_dict.get('hash') receipt.transaction_index = hex_to_dec(json_dict.get('index')) receipt.block_hash = json_dict.get('blockHash') receipt.block_number = hex_to_dec(json_dict.get('blockNumber')) receipt.gas_used = hex_to_dec(json_dict.get('gasUsed')) receipt.contract_address = to_normalized_address( json_dict.get('contractAddress')) receipt.status = hex_to_dec(json_dict.get('status')) if 'logs' in json_dict: receipt.logs = [ self.receipt_log_mapper.json_dict_to_receipt_log(log) for log in json_dict['logs'] ] return receipt
def json_dict_to_block(self, json_dict) -> Union[KlaytnRawBlock, KlaytnBlock]: _block = KlaytnRawBlock() _block.number = hex_to_dec(json_dict.get('number')) _block.hash = json_dict.get('hash') _block.parent_hash = json_dict.get('parentHash') _block.logs_bloom = json_dict.get('logsBloom') _block.transactions_root = json_dict.get('transactionsRoot') _block.state_root = json_dict.get('stateRoot') _block.receipts_root = json_dict.get('receiptsRoot') _block.size = hex_to_dec(json_dict.get('size')) _block.extra_data = json_dict.get('extraData') _block.gas_limit = hex_to_dec(json_dict.get('gasLimit')) _block.gas_used = hex_to_dec(json_dict.get('gasUsed')) _block.timestamp = hex_to_dec(json_dict.get('timestamp')) _block.timestamp_fos = hex_to_dec(json_dict.get('timestampFoS')) # Klaytn additional properties _block.block_score = hex_to_dec(json_dict.get('blockscore')) _block.total_block_score = hex_to_dec(json_dict.get('totalBlockScore')) _block.governance_data = json_dict.get('governanceData') _block.vote_data = json_dict.get('voteData') _block.committee = json_dict.get('committee') _block.proposer = json_dict.get('proposer') _block.reward_address = json_dict.get('reward') if 'transactions' in json_dict: _block.transactions = [ self.transaction_mapper.json_dict_to_transaction( tx, block_timestamp=_block.timestamp, block_timestamp_fos=_block.timestamp_fos, enrich=self.enrich) for tx in json_dict['transactions'] if isinstance(tx, dict) ] _block.transaction_count = len(json_dict['transactions']) if not self.enrich: _block.receipts = [ self.receipt_mapper.json_dict_to_receipt(tx) for tx in json_dict['transactions'] ] else: del _block.receipts return _block if not self.enrich else KlaytnBlock.enrich(_block)
def json_dict_to_block(self, json_dict): block = EthBlock() block.number = hex_to_dec(json_dict.get('number')) block.hash = json_dict.get('hash') block.parent_hash = json_dict.get('parentHash') # block.nonce = json_dict.get('nonce') # block.sha3_uncles = json_dict.get('sha3Uncles') block.logs_bloom = json_dict.get('logsBloom') block.transactions_root = json_dict.get('transactionsRoot') block.state_root = json_dict.get('stateRoot') block.receipts_root = json_dict.get('receiptsRoot') # block.miner = to_normalized_address(json_dict.get('miner')) # block.difficulty = hex_to_dec(json_dict.get('difficulty')) # block.total_difficulty = hex_to_dec(json_dict.get('totalDifficulty')) block.size = hex_to_dec(json_dict.get('size')) block.extra_data = json_dict.get('extraData') block.gas_limit = hex_to_dec(json_dict.get('gasLimit')) block.gas_used = hex_to_dec(json_dict.get('gasUsed')) block.timestamp = hex_to_dec(json_dict.get('timestamp')) # Klaytn additional properties block.block_score = hex_to_dec(json_dict.get('blockscore')) block.total_block_score = hex_to_dec(json_dict.get('totalBlockScore')) block.timestamp_fos = hex_to_dec(json_dict.get('timestampFoS')) block.governance_data = json_dict.get('governanceData') block.vote_data = json_dict.get('voteData') block.committee = json_dict.get('committee') block.proposer = json_dict.get('proposer') block.reward_address = json_dict.get('reward') if 'transactions' in json_dict: block.transactions = [ self.transaction_mapper.json_dict_to_transaction( tx, block_timestamp=block.timestamp) for tx in json_dict['transactions'] if isinstance(tx, dict) ] block.transaction_count = len(json_dict['transactions']) return block
def block_json_dict_to_events(self, block_json_dict, event_hash=None): events = [] block = EthBlock() block.number = hex_to_dec(block_json_dict.get('number')) block.hash = block_json_dict.get('hash') block.timestamp = hex_to_dec(block_json_dict.get('timestamp')) block.timestamp_fos = hex_to_dec(block_json_dict.get('timestampFoS')) if 'transactions' in block_json_dict: for tx_json_dict in block_json_dict['transactions']: if isinstance(tx_json_dict, dict): transaction = EthTransaction() transaction.hash = tx_json_dict.get('transactionHash') transaction.index = hex_to_dec(tx_json_dict.get('transactionIndex')) transaction.status = hex_to_dec(tx_json_dict.get('status')) if 'logs' in tx_json_dict: for log_json_dict in tx_json_dict['logs']: if isinstance(log_json_dict, dict): event = KlaytnEvent() event.block_number = block.number event.block_hash = block.hash event.block_timestamp = block.timestamp event.block_timestamp_fos = block.timestamp_fos event.transaction_hash = transaction.hash event.transaction_index = transaction.index event.transaction_status = transaction.status event.log_index = hex_to_dec(log_json_dict.get('logIndex')) event.log_address = log_json_dict.get('address') event.log_data = log_json_dict.get('data') event.log_topics = self._safe_convert_to_topics(log_json_dict.get('topics')) if self._match_first_hash(event.log_topics, event_hash) is True: events.append(event) return events