Common utility functions for python code that interacts with Ethereum
—
Advanced data transformation utilities including formatters, applicators, and functional programming tools for complex data processing workflows.
Apply formatting functions to data structures with precise control.
def apply_formatter_if(condition, formatter, value):
"""
Conditionally apply formatter based on condition function.
Args:
condition: Function that returns bool when passed value
formatter: Function to apply if condition is True
value: Value to potentially format
Returns:
Formatted value if condition is True, otherwise original value
"""
def apply_formatter_at_index(formatter, at_index, value):
"""
Apply formatter to element at specific index in sequence.
Args:
formatter: Function to apply to the element
at_index (int): Index of element to format
value: Sequence containing element to format
Returns:
Generator yielding formatted sequence
"""
def apply_formatter_to_array(formatter, value):
"""
Apply formatter to all elements in array.
Args:
formatter: Function to apply to each element
value: Iterable to format
Returns:
Generator yielding formatted elements
"""Transform dictionary structures with key mapping and value formatting.
def apply_formatters_to_dict(formatters, value, unaliased=False):
"""
Apply formatters to dictionary values.
Args:
formatters: Dict mapping keys to formatter functions
value: Dictionary to format
unaliased (bool): Whether to process keys without aliasing
Returns:
Generator yielding formatted dictionary items
"""
def apply_key_map(key_mappings, value):
"""
Apply key transformations to dictionary.
Args:
key_mappings: Dict mapping old keys to new keys
value: Dictionary to transform
Returns:
Generator yielding transformed dictionary items
"""Format sequences with multiple formatters.
def apply_formatters_to_sequence(formatters, sequence):
"""
Apply corresponding formatters to sequence elements.
Args:
formatters: Sequence of formatter functions
sequence: Sequence to format
Returns:
Generator yielding formatted sequence elements
"""
def apply_one_of_formatters(formatter_condition_pairs, value):
"""
Apply first matching formatter from condition-formatter pairs.
Args:
formatter_condition_pairs: Sequence of (formatter, condition) tuples
value: Value to format
Returns:
Formatted value using first matching formatter
"""from eth_utils import apply_formatter_if, is_string, to_checksum_address
def format_address_if_string(value):
"""Format value as checksum address if it's a string."""
return apply_formatter_if(
condition=is_string,
formatter=to_checksum_address,
value=value
)
# Examples
addr1 = "0xd3cda913deb6f67967b99d67acdfa1712c293601" # String
addr2 = b'\xd3\xcd\xa9...' # Bytes
result1 = format_address_if_string(addr1) # Checksummed address
result2 = format_address_if_string(addr2) # Unchanged bytes
print(result1) # 0xd3CdA913deB6f67967B99D67aCDFa1712C293601
print(result2) # b'\xd3\xcd\xa9...'from eth_utils import apply_formatter_to_array, to_int
def parse_hex_array(hex_strings):
"""Convert array of hex strings to integers."""
return list(apply_formatter_to_array(
formatter=lambda x: to_int(hexstr=x),
value=hex_strings
))
# Example
hex_values = ["0x1", "0xa", "0xff", "0x100"]
int_values = parse_hex_array(hex_values)
print(int_values) # [1, 10, 255, 256]from eth_utils import apply_formatter_at_index, to_checksum_address
def format_transaction_recipient(transaction_array):
"""Format the recipient address (index 2) in transaction array."""
return list(apply_formatter_at_index(
formatter=to_checksum_address,
at_index=2,
value=transaction_array
))
# Example transaction: [from, value, to, data]
tx = [
"0xsender...",
1000000000000000000, # 1 ETH in wei
"0xd3cda913deb6f67967b99d67acdfa1712c293601", # to address
"0x"
]
formatted_tx = format_transaction_recipient(tx)
print(formatted_tx[2]) # Checksummed addressfrom eth_utils import apply_formatters_to_dict, to_int, to_checksum_address
def format_transaction_dict(tx_dict):
"""Format transaction dictionary fields."""
formatters = {
'value': lambda x: to_int(hexstr=x),
'gasPrice': lambda x: to_int(hexstr=x),
'gasLimit': lambda x: to_int(hexstr=x),
'nonce': lambda x: to_int(hexstr=x),
'to': to_checksum_address,
'from': to_checksum_address
}
return dict(apply_formatters_to_dict(formatters, tx_dict))
# Example raw transaction
raw_tx = {
'value': '0xde0b6b3a7640000', # 1 ETH in hex
'gasPrice': '0x4a817c800', # 20 gwei in hex
'gasLimit': '0x5208', # 21000 in hex
'nonce': '0x1',
'to': '0xd3cda913deb6f67967b99d67acdfa1712c293601',
'from': '0x742d35cc6634c0532925a3b8c17b1e8b4e1d1123',
'data': '0x'
}
formatted_tx = format_transaction_dict(raw_tx)
print(formatted_tx['value']) # 1000000000000000000
print(formatted_tx['gasPrice']) # 20000000000
print(formatted_tx['to']) # Checksummed addressfrom eth_utils import apply_key_map
def normalize_rpc_response(response):
"""Normalize RPC response field names."""
key_mappings = {
'blockHash': 'block_hash',
'blockNumber': 'block_number',
'transactionHash': 'transaction_hash',
'transactionIndex': 'transaction_index',
'gasUsed': 'gas_used',
'gasPrice': 'gas_price'
}
return dict(apply_key_map(key_mappings, response))
# Example RPC response
rpc_response = {
'blockHash': '0x123...',
'blockNumber': '0x1b4',
'transactionHash': '0x456...',
'gasUsed': '0x5208',
'status': '0x1'
}
normalized = normalize_rpc_response(rpc_response)
print(normalized)
# {
# 'block_hash': '0x123...',
# 'block_number': '0x1b4',
# 'transaction_hash': '0x456...',
# 'gas_used': '0x5208',
# 'status': '0x1'
# }from eth_utils import apply_formatters_to_sequence, to_int, to_checksum_address, encode_hex
def format_transaction_tuple(tx_tuple):
"""Format transaction tuple with specific formatters for each field."""
# Transaction format: (nonce, gasPrice, gasLimit, to, value, data)
formatters = [
lambda x: to_int(hexstr=x), # nonce
lambda x: to_int(hexstr=x), # gasPrice
lambda x: to_int(hexstr=x), # gasLimit
to_checksum_address, # to
lambda x: to_int(hexstr=x), # value
lambda x: x if x == '0x' else encode_hex(bytes.fromhex(x[2:])) # data
]
return tuple(apply_formatters_to_sequence(formatters, tx_tuple))
# Example
raw_tx_tuple = (
'0x1', # nonce
'0x4a817c800', # gasPrice
'0x5208', # gasLimit
'0xd3cda913deb6f67967b99d67acdfa1712c293601', # to
'0xde0b6b3a7640000', # value
'0x' # data
)
formatted = format_transaction_tuple(raw_tx_tuple)
print(formatted)from eth_utils import apply_one_of_formatters, is_string, is_integer, to_int, encode_hex
def smart_hex_formatter(value):
"""Apply appropriate hex formatting based on value type."""
formatter_condition_pairs = [
(lambda x: encode_hex(x), lambda x: isinstance(x, int)),
(lambda x: to_int(hexstr=x), lambda x: is_string(x) and x.startswith('0x')),
(lambda x: x, lambda x: True) # Default: return as-is
]
return apply_one_of_formatters(formatter_condition_pairs, value)
# Examples
print(smart_hex_formatter(255)) # 0xff (int to hex)
print(smart_hex_formatter("0xff")) # 255 (hex to int)
print(smart_hex_formatter("text")) # "text" (unchanged)from eth_utils import (
apply_formatters_to_dict, apply_formatter_to_array,
to_int, to_checksum_address, is_string
)
def process_block_data(block_data):
"""Process raw block data from RPC."""
# Format block-level fields
block_formatters = {
'number': lambda x: to_int(hexstr=x),
'timestamp': lambda x: to_int(hexstr=x),
'gasLimit': lambda x: to_int(hexstr=x),
'gasUsed': lambda x: to_int(hexstr=x),
'miner': to_checksum_address
}
# Format the block
formatted_block = dict(apply_formatters_to_dict(block_formatters, block_data))
# Format transactions array if present
if 'transactions' in formatted_block:
tx_formatters = {
'value': lambda x: to_int(hexstr=x),
'gasPrice': lambda x: to_int(hexstr=x),
'gasLimit': lambda x: to_int(hexstr=x),
'nonce': lambda x: to_int(hexstr=x),
'to': lambda x: to_checksum_address(x) if x else None,
'from': to_checksum_address
}
# Apply formatters to each transaction
formatted_transactions = []
for tx in formatted_block['transactions']:
if isinstance(tx, dict): # Full transaction object
formatted_tx = dict(apply_formatters_to_dict(tx_formatters, tx))
formatted_transactions.append(formatted_tx)
else: # Transaction hash only
formatted_transactions.append(tx)
formatted_block['transactions'] = formatted_transactions
return formatted_block
# Example usage with raw block data
raw_block = {
'number': '0x1b4',
'timestamp': '0x61234567',
'gasLimit': '0x1c9c380',
'gasUsed': '0x5208',
'miner': '0x742d35cc6634c0532925a3b8c17b1e8b4e1d1123',
'transactions': [
{
'value': '0xde0b6b3a7640000',
'gasPrice': '0x4a817c800',
'gasLimit': '0x5208',
'nonce': '0x1',
'to': '0xd3cda913deb6f67967b99d67acdfa1712c293601',
'from': '0x742d35cc6634c0532925a3b8c17b1e8b4e1d1123'
}
]
}
processed_block = process_block_data(raw_block)
print(f"Block number: {processed_block['number']}")
print(f"Gas used: {processed_block['gasUsed']}")
print(f"Transaction value: {processed_block['transactions'][0]['value']}")from eth_utils import apply_formatter_if, is_string
class AddressFormatter:
"""Custom formatter for Ethereum addresses."""
def __init__(self, checksum=True):
self.checksum = checksum
def __call__(self, value):
if self.checksum:
return apply_formatter_if(is_string, to_checksum_address, value)
else:
return apply_formatter_if(is_string, str.lower, value)
# Usage
checksum_formatter = AddressFormatter(checksum=True)
lowercase_formatter = AddressFormatter(checksum=False)
addr = "0xD3CDA913DEB6F67967B99D67ACDFA1712C293601"
print(checksum_formatter(addr)) # Proper checksum
print(lowercase_formatter(addr)) # Lowercase