def test_format_dict_error(): with pytest.raises(ValueError) as exc_info: apply_formatters_to_dict( {'myfield': int}, {'myfield': 'a'}, ) assert 'myfield' in str(exc_info.value)
def assert_valid_fields(transaction_dict): # check if any keys are missing missing_keys = REQUIRED_TRANSACITON_KEYS.difference( transaction_dict.keys()) if missing_keys: raise TypeError("Transaction must include these fields: %r" % missing_keys) # check if any extra keys were specified superfluous_keys = set( transaction_dict.keys()).difference(ALLOWED_TRANSACTION_KEYS) if superfluous_keys: raise TypeError( "Transaction must not include unrecognized fields: %r" % superfluous_keys) # check for valid types in each field valid_fields = apply_formatters_to_dict(TRANSACTION_VALID_VALUES, transaction_dict) if not all(valid_fields.values()): invalid = { key: transaction_dict[key] for key, valid in valid_fields.items() if not valid } raise TypeError("Transaction had invalid fields: %r" % invalid)
def normalizer(d: Dict[Any, Any]) -> Dict[str, Any]: keys = set(d.keys()) missing_keys = required_set_form - keys superfluous_keys = keys - all_keys if missing_keys: raise KeyError(f"Missing required keys: {', '.join(missing_keys)}") if superfluous_keys: raise KeyError(f"Superfluous keys: {', '.join(superfluous_keys)}") return apply_formatters_to_dict(formatters, d)
def transaction_param_validator(web3): transactions_params_validators = { 'chainId': apply_formatter_if( # Bypass `validate_chain_id` if chainId can't be determined lambda _: is_not_null(web3.net.chainId), validate_chain_id(web3)), } return apply_formatter_at_index( apply_formatters_to_dict(transactions_params_validators), 0)
def _transaction_param_validator(web3_chain_id: int) -> Callable[..., Any]: transactions_params_validators = { "chainId": apply_formatter_if( # Bypass `validate_chain_id` if chainId can't be determined lambda _: is_not_null(web3_chain_id), _validate_chain_id(web3_chain_id), ), } return apply_formatter_at_index( apply_formatters_to_dict(transactions_params_validators), 0)
def transaction_param_validator(web3: "Web3") -> Callable[..., Any]: transactions_params_validators = { # type ignored b/c apply_formatter_if requires more args, but is_not_null is curried "chainId": apply_formatter_if( # type: ignore # Bypass `validate_chain_id` if chainId can't be determined lambda _: is_not_null(web3.eth.chainId), validate_chain_id(web3), ), } return apply_formatter_at_index( apply_formatters_to_dict(transactions_params_validators), 0)
def serializable_unsigned_transaction_from_dict(transaction_dict): assert_valid_fields(transaction_dict) filled_transaction = pipe( transaction_dict, dict, partial(merge, TRANSACTION_DEFAULTS), chain_id_to_v, apply_formatters_to_dict(TRANSACTION_FORMATTERS), ) if 'v' in filled_transaction: serializer = Transaction else: serializer = UnsignedTransaction return serializer.from_dict(filled_transaction)
def validation_middleware(make_request, web3): transaction_validator = apply_formatters_to_dict({ 'chainId': validate_chain_id(web3), }) transaction_sanitizer = compose(transaction_normalizer, transaction_validator) def middleware(method, params): if method in ('eth_sendTransaction', 'eth_estimateGas', 'eth_call'): post_validated_params = apply_formatter_at_index(transaction_sanitizer, 0, params) return make_request(method, post_validated_params) else: return make_request(method, params) return middleware
def serializable_unsigned_transaction_from_dict(web3, transaction_dict): ''' if web3 is None, fill out transaction as much as possible without calling client ''' filled_transaction = pipe( transaction_dict, dict, partial(merge, TRANSACTION_DEFAULTS), chain_id_to_v, apply_formatters_to_dict(TRANSACTION_FORMATTERS), ) if 'v' in filled_transaction: serializer = Transaction else: serializer = UnsignedTransaction return serializer.from_dict(filled_transaction)
def assert_valid_fields(cls, dictionary: Dict[str, Any]): transaction_valid_values = merge(LEGACY_TRANSACTION_VALID_VALUES, { 'type': is_int_or_prefixed_hexstr, 'accessList': is_rpc_structured_access_list, }) if 'v' in dictionary and dictionary['v'] == 0: # This is insane logic that is required because the way we evaluate # correct types is in the `if not all()` branch below, and 0 obviously # maps to the int(0), which maps to False... This was not an issue in non-typed # transaction because v=0, couldn't exist with the chain offset. dictionary['v'] = '0x0' valid_fields = apply_formatters_to_dict( transaction_valid_values, dictionary, ) # type: Dict[str, Any] if not all(valid_fields.values()): invalid = {key: dictionary[key] for key, valid in valid_fields.items() if not valid} raise TypeError("Transaction had invalid fields: %r" % invalid)
def serializable_unsigned_transaction_from_dict(transaction_dict): transaction_dict = set_transaction_type_if_needed(transaction_dict) if 'type' in transaction_dict: # We delegate to TypedTransaction, which will carry out validation & formatting. return TypedTransaction.from_dict(transaction_dict) assert_valid_fields(transaction_dict) filled_transaction = pipe( transaction_dict, dict, partial(merge, TRANSACTION_DEFAULTS), chain_id_to_v, apply_formatters_to_dict(LEGACY_TRANSACTION_FORMATTERS), ) if 'v' in filled_transaction: serializer = Transaction else: serializer = UnsignedTransaction return serializer.from_dict(filled_transaction)
def from_dict(cls, dictionary: Dict[str, Any]): """ Builds a DynamicFeeTransaction from a dictionary. Verifies that the dictionary is well formed. """ # Validate fields. cls.assert_valid_fields(dictionary) sanitized_dictionary = pipe( dictionary, dict, partial(merge, cls.transaction_field_defaults), apply_formatters_to_dict(TYPED_TRANSACTION_FORMATTERS), ) # We have verified the type, we can safely remove it from the dictionary, # given that it is not to be included within the RLP payload. transaction_type = sanitized_dictionary.pop('type') if transaction_type != cls.transaction_type: raise ValueError( "expected transaction type %s, got %s" % (cls.transaction_type, transaction_type), ) return cls( dictionary=sanitized_dictionary, )
apply_formatters_to_dict, apply_key_map, ) from hexbytes import ( HexBytes, ) from web3._utils.toolz import ( compose, ) from web3.middleware.formatting import ( construct_formatting_middleware, ) remap_geth_poa_fields = apply_key_map({ 'extraData': 'proofOfAuthorityData', }) pythonic_geth_poa = apply_formatters_to_dict({ 'proofOfAuthorityData': HexBytes, }) geth_poa_cleanup = compose(pythonic_geth_poa, remap_geth_poa_fields) geth_poa_middleware = construct_formatting_middleware( result_formatters={ 'eth_getBlockByHash': geth_poa_cleanup, 'eth_getBlockByNumber': geth_poa_cleanup, }, )
lambda _: is_not_null(web3.eth.chainId), validate_chain_id(web3), ), } return apply_formatter_at_index( apply_formatters_to_dict(transactions_params_validators), 0) BLOCK_VALIDATORS = { 'extraData': check_extradata_length, } # types ignored b/c same reason as line 79 block_validator = apply_formatter_if( # type: ignore is_not_null, apply_formatters_to_dict(BLOCK_VALIDATORS) # type: ignore ) @curry def chain_id_validator(web3: "Web3") -> Callable[..., Any]: return compose(apply_formatter_at_index(transaction_normalizer, 0), transaction_param_validator(web3)) def build_validators_with_web3(w3: "Web3") -> FormattersDict: return dict( request_formatters={ 'eth_sendTransaction': chain_id_validator(w3), 'eth_estimateGas': chain_id_validator(w3), 'eth_call': chain_id_validator(w3),
LEGACY_TRANSACTION_FORMATTERS, LEGACY_TRANSACTION_VALID_VALUES, is_int_or_prefixed_hexstr, is_rpc_structured_access_list, ) TYPED_TRANSACTION_FORMATTERS = merge( LEGACY_TRANSACTION_FORMATTERS, { 'chainId': hexstr_if_str(to_int), 'type': hexstr_if_str(to_int), 'accessList': apply_formatter_to_array( apply_formatters_to_dict( { "address": apply_one_of_formatters(( (is_string, hexstr_if_str(to_bytes)), (is_bytes, identity), )), "storageKeys": apply_formatter_to_array(hexstr_if_str(to_int)) } ), ), 'maxPriorityFeePerGas': hexstr_if_str(to_int), 'maxFeePerGas': hexstr_if_str(to_int), }, ) # Define typed transaction common sedes. # [[{20 bytes}, [{32 bytes}...]]...], where ... means “zero or more of the thing to the left”. access_list_sede_type = CountableList( List([ Binary.fixed_length(20, allow_empty=False),
), } return apply_formatter_at_index( apply_formatters_to_dict(transactions_params_validators), 0 ) BLOCK_VALIDATORS = { 'extraData': check_extradata_length, } block_validator = apply_formatter_if( is_not_null, apply_formatters_to_dict(BLOCK_VALIDATORS) ) @curry def chain_id_validator(web3): return compose( apply_formatter_at_index(transaction_normalizer, 0), transaction_param_validator(web3) ) def build_validators_with_web3(w3): return dict( request_formatters={ 'eth_sendTransaction': chain_id_validator(w3),
} transaction_request_remapper = apply_key_map(TRANSACTION_REQUEST_KEY_MAPPING) TRANSACTION_REQUEST_FORMATTERS = { 'gas': to_integer_if_hex, 'gasPrice': to_integer_if_hex, 'value': to_integer_if_hex, 'nonce': to_integer_if_hex, 'maxFeePerGas': to_integer_if_hex, 'maxPriorityFeePerGas': to_integer_if_hex, 'accessList': apply_formatter_to_array( apply_key_map({'storageKeys': 'storage_keys'}) ), } transaction_request_formatter = apply_formatters_to_dict(TRANSACTION_REQUEST_FORMATTERS) transaction_request_transformer = compose( transaction_request_remapper, transaction_request_formatter, ) FILTER_REQUEST_KEY_MAPPING = { 'fromBlock': 'from_block', 'toBlock': 'to_block', } filter_request_remapper = apply_key_map(FILTER_REQUEST_KEY_MAPPING) FILTER_REQUEST_FORMATTERS = {
def test_apply_formatters_to_dict(formatter, value, expected): assert eth_utils.apply_formatters_to_dict(formatter, value) == expected mapper = apply_formatters_to_dict(formatter) assert mapper(value) == expected
if key not in transaction: defaults[key] = default_val for key, val in transaction.items(): if key in VALID_GENASSETTX_PARAMS: alreadygot[key] = transaction[key] transaction_merged = merge(defaults, alreadygot) transaction_merged['chainId'] = defaultChainId transaction_new = unsigned_assetcreate_formatter(transaction_merged) assert_check_gen_asset_params(transaction_new) return transaction_new unsigned_assetcreate_formatter = apply_formatters_to_dict( ASSETCREATE_FORMATTERS) def assert_check_gen_asset_params(assetcreate_params): for param in assetcreate_params: if param not in VALID_GENASSETTX_PARAMS: raise ValueError( '{} is not a valid asset create parameter'.format(param)) for param in REQUIRED_GENASSETTX_PARAMS: if param not in assetcreate_params: raise ValueError( '{} is required as an asset create parameter'.format(param)) ################################################################################################
def sign_transaction(transaction_dict, private_key) -> SignedTransaction: """ Sign a (non-staking) transaction dictionary with the specified private key Parameters ---------- transaction_dict: :obj:`dict` with the following keys nonce: :obj:`int` Transaction nonce gasPrice: :obj:`int` Transaction gas price in Atto gas: :obj:`int` Gas limit in Atto to: :obj:`str` Destination address value: :obj:`int` Amount to be transferred in Atto data: :obj:`str` Transaction data, used for smart contracts from: :obj:`str` From address, optional (if passed, must match the public key address generated from private_key) chainId: :obj:`int` One of util.chainIds.keys(), optional If you want to replay your transaction across networks, do not pass it shardID: :obj:`int` Originating shard ID, optional (needed for cx shard transaction) toShardID: :obj:`int` Destination shard ID, optional (needed for cx shard transaction) r: :obj:`int` First 32 bytes of the signature, optional s: :obj:`int` Next 32 bytes of the signature, optional v: :obj:`int` Recovery value, optional private_key: :obj:`str` The private key Returns ------- A SignedTransaction object, which is a named tuple rawTransaction: :obj:`str` Hex bytes of the raw transaction hash: :obj:`str` Hex bytes of the transaction hash r: :obj:`int` First 32 bytes of the signature s: :obj:`int` Next 32 bytes of the signature v: :obj:`int` Recovery value Raises ------ TypeError, if the from address specified is not the same one as derived from the the private key AssertionError, if the fields for the transaction are missing, or if the chainId supplied is not a string, or if the chainId is not a key in util.py API Reference ------------- https://readthedocs.org/projects/eth-account/downloads/pdf/stable/ """ account, sanitized_transaction = sanitize_transaction( transaction_dict, private_key) if 'to' in sanitized_transaction and sanitized_transaction[ 'to'] is not None: sanitized_transaction['to'] = convert_one_to_hex( sanitized_transaction['to']) filled_transaction = pipe( # https://github.com/ethereum/eth-account/blob/00e7b10005c5fa7090086fcef37a76296c524e17/eth_account/_utils/transactions.py#L39 sanitized_transaction, dict, partial(merge, TRANSACTION_DEFAULTS), chain_id_to_v, apply_formatters_to_dict(HARMONY_FORMATTERS)) unsigned_transaction = serialize_transaction(filled_transaction) transaction_hash = unsigned_transaction.hash() if isinstance(unsigned_transaction, (UnsignedEthereumTxData, UnsignedHarmonyTxData)): chain_id = None # https://github.com/ethereum/eth-account/blob/00e7b10005c5fa7090086fcef37a76296c524e17/eth_account/_utils/signing.py#L26 else: chain_id = unsigned_transaction.v (v, r, s) = sign_transaction_hash(account._key_obj, transaction_hash, chain_id) encoded_transaction = encode_transaction(unsigned_transaction, vrs=(v, r, s)) signed_transaction_hash = keccak(encoded_transaction) return SignedTransaction( rawTransaction=HexBytes(encoded_transaction), hash=HexBytes(signed_transaction_hash), r=r, s=s, v=v, )
'gasPrice': 'gas_price', } transaction_params_remapper = apply_key_map(TRANSACTION_PARAMS_MAPPING) TRANSACTION_PARAMS_FORMATTERS = { 'gas': to_integer_if_hex, 'gasPrice': to_integer_if_hex, 'value': to_integer_if_hex, 'nonce': to_integer_if_hex, } transaction_params_formatter = compose( # remove nonce for now due to issue https://github.com/ethereum/eth-tester/issues/80 remove_key_if('nonce', lambda _: True), apply_formatters_to_dict(TRANSACTION_PARAMS_FORMATTERS), ) FILTER_PARAMS_MAPPINGS = { 'fromBlock': 'from_block', 'toBlock': 'to_block', } filter_params_remapper = apply_key_map(FILTER_PARAMS_MAPPINGS) FILTER_PARAMS_FORMATTERS = { 'fromBlock': to_integer_if_hex, 'toBlock': to_integer_if_hex, } filter_params_formatter = apply_formatters_to_dict(FILTER_PARAMS_FORMATTERS)
from eth_utils.curried import ( apply_formatter_to_array, apply_formatters_to_dict, apply_formatters_to_sequence, encode_hex, to_checksum_address, to_hex, ) from eth_utils.toolz import curried environment_formatter = apply_formatters_to_dict({ "currentCoinbase": to_checksum_address, "previousHash": encode_hex, "currentNumber": to_hex, "currentDifficulty": to_hex, "currentGasLimit": to_hex, "currentTimestamp": to_hex, }) storage_item_formatter: Callable[[List[Any]], List[Any]] storage_item_formatter = apply_formatters_to_sequence([to_hex, to_hex]) storage_formatter = curried.itemmap(storage_item_formatter) account_state_formatter = apply_formatters_to_dict({ "balance": to_hex, "nonce": to_hex, "code": encode_hex,
def _sign_transaction_generic(account, sanitized_transaction, parent_serializer): """ Sign a generic staking transaction, given the serializer base class and account Paramters --------- account: :obj:`eth_account.Account`, the account to use for signing sanitized_transaction: :obj:`dict`, The sanitized transaction (chainId checks and no from key) parent_serializer: :obj: The serializer class from staking_structures Returns ------- SignedTransaction object, which can be posted to the chain by using blockchain.send_raw_transaction Raises ------ Assertion / KeyError, if certain keys are missing from the dict rlp.exceptions.ObjectSerializationError, if data types are not as expected """ # obtain the serializers if sanitized_transaction.get('chainId', 0) == 0: unsigned_serializer, signed_serializer = parent_serializer.Unsigned(), parent_serializer.Signed() # unsigned, signed else: unsigned_serializer, signed_serializer = parent_serializer.SignedChainId(), parent_serializer.SignedChainId() # since chain_id_to_v adds v/r/s, unsigned is not used here # fill the transaction filled_transaction = pipe( # https://github.com/ethereum/eth-account/blob/00e7b10005c5fa7090086fcef37a76296c524e17/eth_account/_utils/transactions.py#L39 sanitized_transaction, dict, partial(merge, {'chainId': None}), chain_id_to_v, # will move chain id to v and add v/r/s apply_formatters_to_dict(FORMATTERS) ) # get the unsigned transaction for f, _ in unsigned_serializer._meta.fields: assert f in filled_transaction, f'Could not find {f} in transaction' unsigned_transaction = unsigned_serializer.from_dict(\ {f: filled_transaction[f] for f, _ in unsigned_serializer._meta.fields}) # drop extras silently # sign the unsigned transaction if 'v' in unsigned_transaction.as_dict(): chain_id = unsigned_transaction.v else: chain_id = None transaction_hash = unsigned_transaction.hash() (v, r, s) = sign_transaction_hash( account._key_obj, transaction_hash, chain_id) chain_naive_transaction = dissoc( unsigned_transaction.as_dict(), 'v', 'r', 's') # remove extra v/r/s added by chain_id_to_v # serialize it signed_transaction = signed_serializer( v=v + (8 if chain_id is None else 0), # copied from https://github.com/harmony-one/sdk/blob/99a827782fabcd5f91f025af0d8de228956d42b4/packages/harmony-staking/src/stakingTransaction.ts#L207 r=r, s=s, # in the below statement, remove everything not expected by signed_serializer **{f: chain_naive_transaction[f] for f, _ in signed_serializer._meta.fields if f not in 'vrs'}) # encode it encoded_transaction = rlp.encode(signed_transaction) # hash it signed_transaction_hash = keccak(encoded_transaction) # return is return SignedTransaction( rawTransaction=HexBytes(encoded_transaction), hash=HexBytes(signed_transaction_hash), r=r, s=s, v=v, )
if key not in transaction: defaults[key] = default_val for key, val in transaction.items(): if key in VALID_MAKESWAP_PARAMS: alreadygot[key] = transaction[key] transaction_merged = merge(defaults, alreadygot) transaction_merged['chainId'] = defaultChainId transaction_new = unsigned_makeswap_formatter(transaction_merged) assert_check_makeswap_params(transaction_new) return transaction_new unsigned_makeswap_formatter = apply_formatters_to_dict(MAKESWAP_FORMATTERS) def assert_check_makeswap_params(makeswap_params): for param in makeswap_params: if param not in VALID_MAKESWAP_PARAMS: raise ValueError( '{} is not a valid make swap parameter'.format(param)) for param in REQUIRED_MAKESWAP_PARAMS: if param not in makeswap_params: raise ValueError( '{} is required as an make swap parameter'.format(param)) ##############################################################################################
'maxPriorityFeePerGas': to_integer_if_hex, 'value': to_integer_if_hex, 'from': to_checksum_address, 'publicKey': apply_formatter_if(is_not_null, to_hexbytes(64)), 'r': apply_formatter_if(is_not_null, to_hexbytes(32, variable_length=True)), 'raw': HexBytes, 's': apply_formatter_if(is_not_null, to_hexbytes(32, variable_length=True)), 'to': apply_formatter_if(is_address, to_checksum_address), 'hash': to_hexbytes(32), 'v': apply_formatter_if(is_not_null, to_integer_if_hex), 'standardV': apply_formatter_if(is_not_null, to_integer_if_hex), } transaction_result_formatter = apply_formatters_to_dict( TRANSACTION_RESULT_FORMATTERS) def apply_list_to_array_formatter(formatter: Any) -> Callable[..., Any]: return to_list(apply_formatter_to_array(formatter)) LOG_ENTRY_FORMATTERS = { 'blockHash': apply_formatter_if(is_not_null, to_hexbytes(32)), 'blockNumber': apply_formatter_if(is_not_null, to_integer_if_hex), 'transactionIndex': apply_formatter_if(is_not_null, to_integer_if_hex), 'transactionHash': apply_formatter_if(is_not_null, to_hexbytes(32)), 'logIndex': to_integer_if_hex, 'address': to_checksum_address, 'topics': apply_list_to_array_formatter(to_hexbytes(32)), 'data': to_ascii_if_bytes,
def test_format_dict_error(): with pytest.raises(ValueError) as exc_info: apply_formatters_to_dict({"myfield": int}, {"myfield": "a"}) with pytest.raises(ValueError) as exc_info: eth_utils.apply_formatters_to_dict({"myfield": int}, {"myfield": "a"}) assert "myfield" in str(exc_info.value)
'chainId': apply_formatter_if( # Bypass `validate_chain_id` if chainId can't be determined lambda _: is_not_null(web3.net.chainId), validate_chain_id(web3)), } return apply_formatter_at_index( apply_formatters_to_dict(transactions_params_validators), 0) BLOCK_VALIDATORS = { 'extraData': check_extradata_length, } block_validator = apply_formatter_if( is_not_null, apply_formatters_to_dict(BLOCK_VALIDATORS)) @curry def chain_id_validator(web3): return compose(apply_formatter_at_index(transaction_normalizer, 0), transaction_param_validator(web3)) def build_validators_with_web3(w3): return dict( request_formatters={ 'eth_sendTransaction': chain_id_validator(w3), 'eth_estimateGas': chain_id_validator(w3), 'eth_call': chain_id_validator(w3), },
'nonce': to_integer_if_hex, 'gas': to_integer_if_hex, 'gasPrice': to_integer_if_hex, 'value': to_integer_if_hex, 'from': to_checksum_address, 'publicKey': apply_formatter_if(is_not_null, to_hexbytes(64)), 'r': to_hexbytes(32, variable_length=True), 'raw': HexBytes, 's': to_hexbytes(32, variable_length=True), 'to': apply_formatter_if(is_address, to_checksum_address), 'hash': to_hexbytes(32), 'v': apply_formatter_if(is_not_null, to_integer_if_hex), 'standardV': apply_formatter_if(is_not_null, to_integer_if_hex), } transaction_formatter = apply_formatters_to_dict(TRANSACTION_FORMATTERS) SIGNED_TX_FORMATTER = { 'raw': HexBytes, 'tx': transaction_formatter, } signed_tx_formatter = apply_formatters_to_dict(SIGNED_TX_FORMATTER) WHISPER_LOG_FORMATTERS = { 'sig': to_hexbytes(130), 'topic': to_hexbytes(8), 'payload': HexBytes, 'padding': apply_formatter_if(is_not_null, HexBytes), 'hash': to_hexbytes(64), 'recipientPublicKey': apply_formatter_if(is_not_null, to_hexbytes(130)),
for key, default_val in GENNOTATION_DEFAULTS.items(): if key not in transaction: defaults[key] = default_val for key, val in transaction.items(): if key in VALID_GENNOTATIONTX_PARAMS: alreadygot[key] = transaction[key] transaction_merged = merge(defaults, alreadygot) transaction_merged['chainId'] = defaultChainId transaction_new = unsigned_gennotation_formatter(transaction_merged) assert_check_gen_notation_params(transaction_new) return transaction_new unsigned_gennotation_formatter = apply_formatters_to_dict( GENNOTATION_FORMATTERS) def assert_check_gen_notation_params(gennotation_params): for param in gennotation_params: if param not in VALID_GENNOTATIONTX_PARAMS: raise ValueError( '{} is not a valid gen notation parameter'.format(param)) for param in REQUIRED_GENNOTATIONTX_PARAMS: if param not in gennotation_params: raise ValueError( '{} is required as a gen notation parameter'.format(param))
from eth_utils.curried import ( apply_formatters_to_dict, apply_key_map, ) from hexbytes import ( HexBytes, ) from vns_web3.middleware.formatting import ( construct_formatting_middleware, ) from vns_web3.utils.toolz import ( compose, ) remap_geth_poa_fields = apply_key_map({ 'extraData': 'proofOfAuthorityData', }) pythonic_geth_poa = apply_formatters_to_dict({ 'proofOfAuthorityData': HexBytes, }) geth_poa_cleanup = compose(pythonic_geth_poa, remap_geth_poa_fields) geth_poa_middleware = construct_formatting_middleware(result_formatters={ 'eth_getBlockByHash': geth_poa_cleanup, 'eth_getBlockByNumber': geth_poa_cleanup, }, )
from eth_utils import ( is_string, ) from eth_utils.curried import ( apply_formatter_at_index, apply_formatter_if, apply_formatters_to_dict, ) from .formatting import ( construct_formatting_middleware, ) FILTER_PARAM_NORMALIZERS = apply_formatters_to_dict({ 'address': apply_formatter_if(is_string, lambda x: [x])}) METHOD_NORMALIZERS = { 'eth_getLogs': apply_formatter_at_index(FILTER_PARAM_NORMALIZERS, 0), 'eth_newFilter': apply_formatter_at_index(FILTER_PARAM_NORMALIZERS, 0) } request_parameter_normalizer = construct_formatting_middleware( request_formatters=METHOD_NORMALIZERS, )