def is_encodable(_type, value): if not isinstance(_type, str): raise ValueError("is_encodable only accepts type strings") base, sub, arrlist = process_type(_type) if arrlist: if not is_list_like(value): return False if arrlist[-1] and len(value) != arrlist[-1][0]: return False sub_type = (base, sub, arrlist[:-1]) return all(is_encodable(collapse_type(*sub_type), sub_value) for sub_value in value) elif base == 'address' and is_ens_name(value): # ENS names can be used anywhere an address is needed # Web3.py will resolve the name to an address before encoding it return True elif base == 'bytes' and isinstance(value, str): # Hex-encoded bytes values can be used anywhere a bytes value is needed if is_hex(value) and len(value) % 2 == 0: # Require hex-encoding of full bytes (even length) bytes_val = to_bytes(hexstr=value) return eth_abi_is_encodable(_type, bytes_val) else: return False elif base == 'string' and isinstance(value, bytes): # bytes that were encoded with utf-8 can be used anywhere a string is needed try: string_val = to_text(value) except UnicodeDecodeError: return False else: return eth_abi_is_encodable(_type, string_val) else: return eth_abi_is_encodable(_type, value)
def __init__( self, private_key: str = None, key_password_path: str = None, channel_manager_address: str = None, web3: Web3 = None ) -> None: is_hex_key = is_hex(private_key) and len(remove_0x_prefix(private_key)) == 64 is_path = os.path.exists(private_key) assert is_hex_key or is_path, 'Private key must either be a hex key or a file path.' # Load private key from file if none is specified on command line. if is_path: private_key = get_private_key(private_key, key_password_path) assert private_key is not None, 'Could not load private key from file.' self.channels = [] # type: List[Channel] # Create web3 context if none is provided, either by using the proxies' context or creating # a new one. if not web3: web3 = Web3(HTTPProvider(WEB3_PROVIDER_DEFAULT)) channel_manager_address = to_checksum_address( channel_manager_address or NETWORK_CFG.CHANNEL_MANAGER_ADDRESS ) self.context = Context(private_key, web3, channel_manager_address) self.sync_channels()
def is_by_hash(at_block): if is_string(at_block) and is_hex(at_block) and len(at_block) == 66: return True elif is_integer(at_block) or at_block in ('latest', 'earliest', 'pending'): return False else: raise ValueError("Unrecognized 'at_block' value: %r" % at_block)
def faucet_private_key(request, faucet_password_path: str) -> str: private_key = request.config.getoption('faucet_private_key') if is_hex(private_key): assert len(remove_0x_prefix(private_key)) == 64 return private_key else: private_key = get_private_key(private_key, faucet_password_path) assert private_key is not None, 'Error loading faucet private key from file.' return private_key
def is_encodable(_type, value): try: base, sub, arrlist = _type except ValueError: base, sub, arrlist = process_type(_type) if arrlist: if not is_list_like(value): return False if arrlist[-1] and len(value) != arrlist[-1][0]: return False sub_type = (base, sub, arrlist[:-1]) return all(is_encodable(sub_type, sub_value) for sub_value in value) elif base == 'bool': return is_boolean(value) elif base == 'uint': if not is_integer(value): return False exp = int(sub) if value < 0 or value >= 2**exp: return False return True elif base == 'int': if not is_integer(value): return False exp = int(sub) if value <= -1 * 2**(exp - 1) or value >= 2**(exp - 1): return False return True elif base == 'string': if not is_string(value): return False return True elif base == 'bytes': if not is_string(value): return False if not sub: return True max_length = int(sub) if isinstance(value, str): decodable = is_hex(value) and len(value) % 2 == 0 return decodable and len(decode_hex(value)) <= max_length elif isinstance(value, bytes): return len(value) <= max_length else: False elif base == 'address': if is_ens_name(value): return True elif is_address(value): return True else: return False else: raise ValueError("Unsupported type")
def is_ens_name(value): if not isinstance(value, str): return False elif is_hex_address(value): return False elif is_0x_prefixed(value) and is_hex(value): return False else: return ENS.is_valid_name(value)
def test_hexstr_if_str_on_invalid_hex(val): try: is_hexstr = (is_hex(val) or val == '') except ValueError: is_hexstr = False if not is_hexstr: with pytest.raises(ValueError): hexstr_if_str(Mock(), val)
def hexstr_if_str(to_type, hexstr_or_primitive): ''' Convert to a type, assuming that strings can be only hexstr (not unicode text) @param to_type is a function that takes the arguments (primitive, hexstr=hexstr, text=text), eg~ to_bytes, to_text, to_hex, to_int, etc @param text_or_primitive in bytes, str, or int. ''' if isinstance(hexstr_or_primitive, str): (primitive, hexstr) = (None, hexstr_or_primitive) if remove_0x_prefix(hexstr) and not is_hex(hexstr): raise ValueError( "when sending a str, it must be a hex string. Got: {0!r}".format( hexstr_or_primitive, ) ) else: (primitive, hexstr) = (hexstr_or_primitive, None) return to_type(primitive, hexstr=hexstr)
def hexstr_if_str(to_type, hexstr_or_primitive): """ Convert to a type, assuming that strings can be only hexstr (not unicode text) @param to_type is a function that takes the arguments (primitive, hexstr=hexstr, text=text), eg~ to_bytes, to_text, to_hex, to_int, etc @param text_or_primitive in bytes, str, or int. """ if isinstance(hexstr_or_primitive, str): (primitive, hexstr) = (None, hexstr_or_primitive) if remove_0x_prefix(hexstr) and not is_hex(hexstr): raise ValueError( "when sending a str, it must be a hex string. Got: {0!r}".format( hexstr_or_primitive, ) ) else: (primitive, hexstr) = (hexstr_or_primitive, None) return to_type(primitive, hexstr=hexstr)
def normalize_int(value: IntConvertible) -> int: """ Robust to integer conversion, handling hex values, string representations, and special cases like `0x`. """ if is_integer(value): return cast(int, value) elif is_bytes(value): return big_endian_to_int(cast(bytes, value)) elif is_hex(value) and is_0x_prefixed(value): value = cast(str, value) if len(value) == 2: return 0 else: return int(value, 16) elif is_string(value): return int(value) else: raise TypeError(f"Unsupported type: Got `{type(value)}`")
def get_private_key(pk_file, pw_file=None): """Open a JSON-encoded private key and return it If a password file is provided, uses it to decrypt the key. If not, the password is asked interactively. Raw hex-encoded private keys are supported, but deprecated.""" is_hex_key = is_hex(pk_file) and len(remove_0x_prefix(pk_file)) == 64 is_path = os.path.exists(pk_file) assert is_hex_key or is_path, 'Private key must either be a hex key or a file path.' # Load private key from file if none is specified on command line. if is_path: private_key = load_pk(pk_file, pw_file) assert private_key is not None, 'Could not load private key from file.' return private_key else: # TODO make sure '0x' return pk_file
def get_private_key(key_path, password_path=None): """Open a JSON-encoded private key and return it If a password file is provided, uses it to decrypt the key. If not, the password is asked interactively. Raw hex-encoded private keys are supported, but deprecated.""" assert key_path, key_path if not os.path.exists(key_path): log.fatal("%s: no such file", key_path) return None if not check_permission_safety(key_path): log.fatal("Private key file %s must be readable only by its owner.", key_path) return None if password_path and not check_permission_safety(password_path): log.fatal("Password file %s must be readable only by its owner.", password_path) return None with open(key_path) as keyfile: private_key = keyfile.readline().strip() if is_hex(private_key) and len(decode_hex(private_key)) == 32: log.warning("Private key in raw format. Consider switching to JSON-encoded") else: keyfile.seek(0) try: json_data = json.load(keyfile) if password_path: with open(password_path) as password_file: password = password_file.readline().strip() else: password = getpass.getpass("Enter the private key password: "******"crypto"]["kdf"] == "pbkdf2": password = password.encode() private_key = encode_hex(decode_keyfile_json(json_data, password)) except ValueError: log.fatal("Invalid private key format or password!") return None return private_key
def to_hexbytes(num_bytes, val): if isinstance(val, str): result = HexBytes(val) elif isinstance(val, bytes): if len(val) == num_bytes: result = HexBytes(val) else: # some providers return values with hex as bytes, like b'0xEFFF' :( hexstr = val.decode('utf-8') if not is_hex(hexstr): raise ValueError("Cannot convert %r into a %d byte argument" % (hexstr, num_bytes)) result = HexBytes(hexstr) else: raise TypeError("Cannot convert %r to HexBytes" % val) if len(result) != num_bytes: raise ValueError("The value %r is %d bytes, but should be %d" % (result, len(result), num_bytes)) return result
def time_based_gas_price_strategy(web3, transaction_params): avg_block_time = _get_avg_block_time(web3, sample_size=sample_size) wait_blocks = int(math.ceil(max_wait_seconds / avg_block_time)) raw_miner_data = _get_raw_miner_data(web3, sample_size=sample_size) miner_data = _aggregate_miner_data(raw_miner_data) probabilities = _compute_probabilities( miner_data, wait_blocks=wait_blocks, sample_size=sample_size, ) latest = web3.eth.getBlock('latest') latest_block_gas_price = latest.minimumGasPrice if is_hex(latest_block_gas_price): latest_block_gas_price = int(latest_block_gas_price, 16) else: latest_block_gas_price = int(latest_block_gas_price) gas_price = _compute_gas_price(probabilities, probability / 100) max_gas = max(gas_price, latest_block_gas_price) return max_gas
def hexstr_if_str(to_type, hexstr_or_primitive): ''' Convert to a type, assuming that strings can be only hexstr (not unicode text) @param to_type is a function that takes the arguments (primitive, hexstr=hexstr, text=text), eg~ to_bytes, to_text, to_hex, to_int, etc @param text_or_primitive in bytes, str, or int. (or unicode in py2) In Python 2, a bytes, unicode or str object will be interpreted as hexstr In Python 3, only a str object will be interpreted as hexstr ''' if isinstance(hexstr_or_primitive, str) or ( sys.version_info.major < 3 and isinstance(hexstr_or_primitive, unicode) # noqa: F821 ): (primitive, hexstr) = (None, hexstr_or_primitive) if remove_0x_prefix(hexstr) and not is_hex(hexstr): raise ValueError( "when sending this str, it must be a hex string. Got: %r" % hexstr_or_primitive ) else: (primitive, hexstr) = (hexstr_or_primitive, None) return to_type(primitive, hexstr=hexstr)
def get_private_key(key_path, password_path=None): """Open a JSON-encoded private key and return it If a password file is provided, uses it to decrypt the key. If not, the password is asked interactively. Raw hex-encoded private keys are supported, but deprecated.""" assert key_path, key_path if not os.path.exists(key_path): log.fatal("%s: no such file", key_path) return None if not check_permission_safety(key_path): log.fatal("Private key file %s must be readable only by its owner.", key_path) return None if password_path and not check_permission_safety(password_path): log.fatal("Password file %s must be readable only by its owner.", password_path) return None with open(key_path) as keyfile: private_key = keyfile.readline().strip() if is_hex(private_key) and len(decode_hex(private_key)) == 32: log.warning("Private key in raw format. Consider switching to JSON-encoded") else: keyfile.seek(0) try: json_data = json.load(keyfile) if password_path: with open(password_path) as password_file: password = password_file.readline().strip() else: password = getpass.getpass("Enter the private key password: "******"Invalid private key format or password!") return None return private_key
def iou_side_effect(*args, **kwargs): if args[0].endswith("/info"): return mocked_json_response({ "price_info": 5, "network_info": { "chain_id": 42, "token_network_registry_address": to_checksum_address( factories.make_token_network_registry_address()), "user_deposit_address": to_checksum_address(factories.make_address()), "confirmed_block": { "number": 11 }, }, "version": "0.0.3", "operator": "John Doe", "message": "This is your favorite pathfinding service", "payment_address": to_checksum_address(factories.make_address()), "matrix_server": "http://matrix.example.com", }) else: assert "params" in kwargs body = kwargs["params"] assert is_hex_address(body["sender"]) assert is_hex_address(body["receiver"]) assert "timestamp" in body assert is_hex(body["signature"]) assert len(body["signature"] ) == 65 * 2 + 2 # 65 hex encoded bytes with 0x prefix return mocked_json_response(response_data=iou_json_data)
def __init__( self, w3: "Web3", from_block: Optional[Union[BlockNumber, LatestBlockParam]] = None, to_block: Optional[Union[BlockNumber, LatestBlockParam]] = None, address: Optional[Union[Address, ChecksumAddress, List[Union[Address, ChecksumAddress]]]] = None, topics: Optional[List[Optional[Union[_Hash32, List[_Hash32]]]]] = None ) -> None: self.address = address self.topics = topics self.w3 = w3 if from_block is None or from_block == "latest": self._from_block = BlockNumber(w3.eth.block_number + 1) elif is_string(from_block) and is_hex(from_block): self._from_block = BlockNumber( hex_to_integer(from_block)) # type: ignore else: # cast b/c LatestBlockParam is handled above self._from_block = cast(BlockNumber, from_block) self._to_block = to_block self.filter_changes = self._get_filter_changes()
def push(self, input_data: Union[bytes, str, int]) -> "Contract": """ Opcode push1(0x60) to push32(0x7f), the length of data determines which opcode to use """ data: bytes if isinstance(input_data, bytes): data = input_data elif isinstance(input_data, int): data = to_big_endian(input_data) elif is_hex(input_data): data = decode_hex(input_data) else: raise TypeError(f"Unsupported input_data type: {type(input_data)}") len_data = len(data) if len_data == 0 or len_data > 32: raise ValueError(f"Invalid data length: {len_data}") # If the data has length 5, the opcode for push5 is 0x5F + 5 self.code.append(0x5F + len_data) self.code.extend([d for d in data]) return self
def ipfs_get_json(ipfs_conn: ipfsapi.client.Client, file_hash: str, tmpdir: Optional[PS] = None) -> Dict[str, Any]: """ Perform an ipfs.get and return the json object as a Python dict """ if isinstance(file_hash, bytes): file_hash = to_b58_string( from_hex_string('1220' + remove_0x_prefix(file_hash.hex()))) elif is_0x_prefixed(file_hash): file_hash = to_b58_string( from_hex_string('1220' + remove_0x_prefix(file_hash))) elif is_hex(file_hash): file_hash = to_b58_string(from_hex_string('1220' + file_hash)) elif file_hash.startswith('Qm'): pass else: raise ValueError("Invalid file_hash") with tempfile.TemporaryDirectory(dir=tmpdir) as _workdir: workdir = Path(_workdir) orig_dir = Path.cwd() assert orig_dir is not None os.chdir(workdir) ipfs_conn.get(file_hash) downloaded: Path = workdir.joinpath(file_hash) if not downloaded.exists() or not downloaded.is_file(): raise ScatterError("Download filed. File not found.") contents = '' with downloaded.open() as _userfile: userfile_text = _userfile.read() print("Downloaded... {}".format(userfile_text)) contents = json.loads(userfile_text) os.chdir(orig_dir) downloaded.unlink() return contents
def etherscan_url(item, network: str, is_token=False) -> str: if network is None or network is UNKNOWN_DEVELOPMENT_CHAIN_ID: raise ValueError("A network must be provided") elif network == 'mainnet': domain = "https://etherscan.io" else: network = network.lower() testnets_supported_by_etherscan = ('ropsten', 'goerli', 'rinkeby', 'kovan') if network in testnets_supported_by_etherscan: domain = f"https://{network}.etherscan.io" else: raise ValueError(f"'{network}' network not supported by Etherscan") if is_address(item): item_type = 'address' if not is_token else 'token' item = to_checksum_address(item) elif is_hex(item) and len(item) == 2 + 32*2: # If it's a hash... item_type = 'tx' else: raise ValueError(f"Cannot construct etherscan URL for {item}") url = f"{domain}/{item_type}/{item}" return url
def hexstr_if_str(to_type, hexstr_or_primitive): ''' Convert to a type, assuming that strings can be only hexstr (not unicode text) @param to_type is a function that takes the arguments (primitive, hexstr=hexstr, text=text), eg~ to_bytes, to_text, to_hex, to_int, etc @param text_or_primitive in bytes, str, or int. (or unicode in py2) In Python 2, a bytes, unicode or str object will be interpreted as hexstr In Python 3, only a str object will be interpreted as hexstr ''' if isinstance(hexstr_or_primitive, str) or ( sys.version_info.major < 3 and isinstance(hexstr_or_primitive, unicode) # noqa: F821 ): (primitive, hexstr) = (None, hexstr_or_primitive) if remove_0x_prefix(hexstr) and not is_hex(hexstr): raise ValueError( "when sending a str, it must be a hex string. Got: {0!r}".format( hexstr_or_primitive, ) ) else: (primitive, hexstr) = (hexstr_or_primitive, None) return to_type(primitive, hexstr=hexstr)
def is_encodable(_type, value): if not isinstance(_type, str): raise ValueError("is_encodable only accepts type strings") base, sub, arrlist = process_type(_type) if arrlist: if not is_list_like(value): return False if arrlist[-1] and len(value) != arrlist[-1][0]: return False sub_type = (base, sub, arrlist[:-1]) return all( is_encodable(collapse_type(*sub_type), sub_value) for sub_value in value) elif base == 'address' and is_ens_name(value): # ENS names can be used anywhere an address is needed # Web3.py will resolve the name to an address before encoding it return True elif base == 'bytes' and isinstance(value, str): # Hex-encoded bytes values can be used anywhere a bytes value is needed if is_hex(value) and len(value) % 2 == 0: # Require hex-encoding of full bytes (even length) bytes_val = to_bytes(hexstr=value) return eth_abi_is_encodable(_type, bytes_val) else: return False elif base == 'string' and isinstance(value, bytes): # bytes that were encoded with utf-8 can be used anywhere a string is needed try: string_val = to_text(value) except UnicodeDecodeError: return False else: return eth_abi_is_encodable(_type, string_val) else: return eth_abi_is_encodable(_type, value)
def __init__(self, private_key: str = None, key_password_path: str = None, channel_manager_address: str = None, web3: Web3 = None) -> None: """ Args: private_key: key_password_path: channel_manager_address: web3: """ is_hex_key = is_hex(private_key) and len( remove_0x_prefix(private_key)) == 64 is_path = os.path.exists(private_key) assert is_hex_key or is_path, 'Private key must either be a hex key or a file path.' # Load private key from file if none is specified on command line. if is_path: private_key = get_private_key(private_key, key_password_path) assert private_key is not None, 'Could not load private key from file.' self.channels = [] # type: List[Channel] # Create web3 context if none is provided, either by using the proxies' context or creating # a new one. if not web3: web3 = Web3(HTTPProvider(WEB3_PROVIDER_DEFAULT)) channel_manager_address = to_checksum_address( channel_manager_address or NETWORK_CFG.CHANNEL_MANAGER_ADDRESS) self.context = Context(private_key, web3, channel_manager_address) self.sync_channels()
def is_encoded_hash32(value: str) -> bool: return is_hex(value) and len(value) == 2 + 2 * 32
def is_hexstr(value): return is_string(value) and is_hex(value)
def is_convertible(self, value: str) -> bool: return is_hex(value)
def is_hex_node_id(value: Any) -> bool: return (isinstance(value, str) and is_hex(value) and len(remove_0x_prefix(HexStr(value))) == 64)
def validate_signature(ctx, param, value): if is_hex(value) and is_0x_prefixed(value) and len(value) == 132: return decode_hex(value) else: raise click.BadParameter( f"A signature parameter seems to be not well structured: {value}")
def _hex_compare(a: Any, b: Any) -> bool: b = str(b) if not b.startswith("0x") or not eth_utils.is_hex(b): raise TypeError(f"Invalid type for comparison: '{b}' is not a valid hex string") return a.lstrip("0x").lower() == b.lstrip("0x").lower()
def validate_raw_transaction(raw_transaction): if not is_text(raw_transaction) or not is_hex(raw_transaction): raise ValidationError( "Raw Transaction must be a hexidecimal encoded string. Got: " "{0}".format(raw_transaction))
def is_32byte_hex_string(value): return is_text(value) and is_hex(value) and len( remove_0x_prefix(value)) == 64
def is_hex_encoded_block_hash(value): if not is_string(value): return False return len(remove_0x_prefix(value)) == 64 and is_hex(value)
def is_hex_encoded_block_hash(value: Any) -> bool: if not is_string(value): return False return len(remove_0x_prefix(value)) == 64 and is_hex(value)
def validate_private_key(value): if not is_text(value) or not is_hex(value) or not len( remove_0x_prefix(value)) == 64: raise ValidationError( "Private keys must be 32 bytes encoded as hexidecimal")
def is_hexstr(value: Any) -> bool: return is_string(value) and is_hex(value)
def _address_compare(a: Any, b: Any) -> bool: b = str(b) if not b.startswith("0x") or not eth_utils.is_hex(b) or len(b) != 42: raise TypeError(f"Invalid type for comparison: '{b}' is not a valid address") return a.lower() == b.lower()
def test_is_hex(value, expected): actual = is_hex(value) assert actual is expected
def validate_transaction(value, txn_type): if txn_type not in ALLOWED_TRANSACTION_TYPES: raise TypeError( "the `txn_type` parameter must be one of send/call/estimate") if not is_dict(value): raise ValidationError( "Transaction must be a dictionary. Got: {0}".format(type(value))) unknown_keys = tuple( sorted( set(value.keys()).difference(TRANSACTION_TYPE_INFO[txn_type], ))) if unknown_keys: raise ValidationError( "Only the keys '{0}' are allowed. Got extra keys: '{1}'".format( "/".join(tuple(sorted(TRANSACTION_TYPE_INFO[txn_type]))), "/".join(unknown_keys), )) if txn_type == 'send': required_keys = {'from', 'gas'} elif txn_type == 'send_signed': required_keys = {'from', 'gas'} | SIGNED_TRANSACTION_KEYS elif txn_type in {'estimate', 'call'}: required_keys = set(['from']) else: raise Exception("Invariant: code path should be unreachable") missing_required_keys = tuple( sorted(required_keys.difference(value.keys()))) if missing_required_keys: raise ValidationError( "Transaction is missing the required keys: '{0}'".format( "/".join(missing_required_keys), )) if 'from' in value: validate_account(value['from']) if 'to' in value and value['to'] != '': validate_account(value['to']) elif 'to' in value and value['to'] == '': validate_text(value['to']) if 'gas' in value: validate_uint256(value['gas']) if 'gas_price' in value: validate_uint256(value['gas_price']) if 'value' in value: validate_uint256(value['value']) if 'nonce' in value: validate_uint256(value['nonce']) if 'data' in value: bad_data_message = ( "Transaction data must be a hexidecimal encoded string. Got: " "{0}".format(value['data'])) if not is_text(value['data']): raise ValidationError(bad_data_message) elif not remove_0x_prefix(value['data']): pass elif not is_hex(value['data']): raise ValidationError(bad_data_message) try: decode_hex(value['data']) except (binascii.Error, TypeError): # TypeError is for python2 # binascii.Error is for python3 raise ValidationError(bad_data_message) if txn_type == 'send_signed': validate_uint256(value['r']) validate_uint256(value['s']) validate_uint8(value['v'])
def faucet_private_key(request) -> str: private_key = request.config.getoption('faucet_private_key') if is_hex(private_key): assert len(remove_0x_prefix(private_key)) == 64 return private_key
def test_eth_chainId(self, web3): chain_id = web3.eth.chainId assert is_hex(chain_id) assert hex_to_integer(chain_id) is 61