def describe_input(self, s): """ Describe the input bytesequence s based on the loaded contract abi definition :param s: bytes input :return: AbiMethod instance """ signatures = self.signatures.items() for sighash, method in signatures: if sighash is None or sighash.startswith(b"__"): continue # skip constructor if s.startswith(sighash): s = s[len(sighash):] types_def = self.signatures.get(sighash)["inputs"] types = [t["type"] for t in types_def] names = [t["name"] for t in types_def] if not len(s): values = len(types) * ["<nA>"] else: values = decode_abi(types, s) # (type, name, data) method.inputs = [{ "type": t, "name": n, "data": v } for t, n, v in list(zip(types, names, values))] return method else: method = AbiMethod({ "type": "fallback", "name": "__fallback__", "inputs": [], "outputs": [] }) types_def = self.signatures.get(b"__fallback__", {"inputs": []})["inputs"] types = [t["type"] for t in types_def] names = [t["name"] for t in types_def] values = decode_abi(types, s) # (type, name, data) method.inputs = [{ "type": t, "name": n, "data": v } for t, n, v in list(zip(types, names, values))] return method
def describe_constructor(self, s): """ Describe the input bytesequence (constructor arguments) s based on the loaded contract abi definition :param s: bytes constructor arguments :return: AbiMethod instance """ method = self.signatures.get(b"__constructor__") if not method: # constructor not available m = AbiMethod({"type": "constructor", "name": "", "inputs": [], "outputs": []}) return m types_def = method["inputs"] types = [t["type"] for t in types_def] names = [t["name"] for t in types_def] if not len(s): values = len(types) * ["<nA>"] else: values = decode_abi(types, s) # (type, name, data) method.inputs = [{"type": t, "name": n, "data": v} for t, n, v in list( zip(types, names, values))] return method
def describe_constructor(self, s): """ Describe the input bytesequence (constructor arguments) s based on the loaded contract abi definition :param s: bytes constructor arguments :return: AbiMethod instance """ method = self.signatures.get(b"__constructor__") if not method: # constructor not available m = AbiMethod({ "type": "constructor", "name": "", "inputs": [], "outputs": [] }) return m types_def = method["inputs"] types = [t["type"] for t in types_def] names = [t["name"] for t in types_def] if not len(s): values = len(types) * ["<nA>"] else: values = decode_abi(types, s) # (type, name, data) method.inputs = [{ "type": t, "name": n, "data": v } for t, n, v in list(zip(types, names, values))] return method
def call_eth_tester(fn_name: str, eth_tester: "EthereumTester", fn_args: Any, fn_kwargs: Optional[Any] = None) -> RPCResponse: if fn_kwargs is None: fn_kwargs = {} try: return getattr(eth_tester, fn_name)(*fn_args, **fn_kwargs) except TransactionFailed as e: possible_data = e.args[0] if isinstance(possible_data, str) and possible_data[2:10] == 'Uo\\x180\\': # EIP-3668 | CCIP Read # b"Uo\x180" is the first 4 bytes of the keccak hash for: # OffchainLookup(address,string[],bytes,bytes4,bytes) parsed_data_as_bytes = ast.literal_eval(possible_data) data_payload = parsed_data_as_bytes[ 4:] # everything but the function selector abi_decoded_data = decode_abi(OFFCHAIN_LOOKUP_FIELDS.values(), data_payload) offchain_lookup_payload = dict( zip(OFFCHAIN_LOOKUP_FIELDS.keys(), abi_decoded_data)) raise OffchainLookup(offchain_lookup_payload) raise e
def test_decode_abi(type_str, expected, abi_encoding, _): abi_type = parse(type_str) if abi_type.arrlist is not None: pytest.skip('ABI coding functions do not support array types') types = [t.to_type_str() for t in abi_type.components] actual = decode_abi(types, abi_encoding) assert actual == expected
def test_decode_abi(type_str, expected, byte_str): abi_type = parse(type_str) if abi_type.arrlist is not None: pytest.skip('ABI coding functions do not support array types') types = [str(t) for t in abi_type.components] actual = decode_abi(types, byte_str) assert actual == expected
def test_decode_various(): data = ('0x00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f10000000000000' '0000000000000000000000000000000000000000000000000017374757069642070696e6b20616e69' '6d616c000000000000000000000000000000000000000000000000000000000000000000000000000' '00000000000000000') expected = [b'82a978b3f5962a5b0957d9ee9eef472ee55b42f1', 1, b'stupid pink animal\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 0] output = decode_abi(['address', 'uint32', 'bytes32', 'int32'], data) assert output == expected
def describe_input(self, s): """ Describe the input bytesequence s based on the loaded contract abi definition :param s: bytes input :return: AbiMethod instance """ signatures = self.signatures.items() for sighash, method in signatures: if sighash is None or sighash.startswith(b"__"): continue # skip constructor if s.startswith(sighash): s = s[len(sighash):] types_def = self.signatures.get(sighash)["inputs"] types = [t["type"] for t in types_def] names = [t["name"] for t in types_def] if not len(s): values = len(types) * ["<nA>"] else: values = decode_abi(types, s) # (type, name, data) method.inputs = [{"type": t, "name": n, "data": v} for t, n, v in list( zip(types, names, values))] return method else: method = AbiMethod({"type": "fallback", "name": "__fallback__", "inputs": [], "outputs": []}) types_def = self.signatures.get(b"__fallback__", {"inputs": []})["inputs"] types = [t["type"] for t in types_def] names = [t["name"] for t in types_def] values = decode_abi(types, s) # (type, name, data) method.inputs = [{"type": t, "name": n, "data": v} for t, n, v in list( zip(types, names, values))] return method
def decode_function(self, tx_input: Union[str, bytes]): tx_input = hex_to_bytes(tx_input) selector, args = tx_input[:4], tx_input[4:] type_def = self._selector_to_func_type.get(selector, None) if not type_def: raise InputDataError("Specified method is not found in ABI") types, names = get_types_names(type_def["inputs"]) values = decode_abi(types, args) return ContractCall(type_def["name"], list(zip(types, names, values)))
def runLog(): global contract global oraclizeC if (sys.getsizeof(contract) != 520 and sys.getsizeof(contract) > 0): oraclizeC = jrpcReq('eth_call', [{ "to": oraclizeOAR, "data": "0x38cc4831" }, "latest"]).replace('0x000000000000000000000000', '0x') print('Listening @ ' + oraclizeC) k = 0 while True: # check for logs if (k == 0): filterId = jrpcReq('eth_newFilter', [{"address": oraclizeC}]) dataLog = jrpcReq('eth_getFilterChanges', [filterId]) if (type(dataLog) is list): if (len(dataLog) == 0): dataLog = None if dataLog is not None: dataLog = dataLog[0]['data'] try: types = [ 'address', 'bytes32', 'uint256', 'string', 'string', 'uint256', 'bytes1' ] result = decode_abi(types, dataLog) except: types = [ 'address', 'bytes32', 'uint256', 'string', 'string', 'string', 'uint256', 'bytes1' ] result = decode_abi(types, dataLog) print str(result) handleLog(result) sleep(0.5) k += 1
async def call_contract_method(self, method, to_int=False, to_string=False): contract_address = self.get_contract_addr() result = await self.post('eth_call', { 'to': contract_address, 'data': self.get_method_hash(method) }, 'latest') if to_int: return int(result, 16) elif to_string: return decode_abi(['string'], HexBytes(result))[0].decode() return result
def get_pseudo_abi_for_input(s, timeout=None, proxies=None): """ Lookup sighash from 4bytes.directory, create a pseudo api and try to decode it with the parsed abi. May return multiple results as sighashes may collide. :param s: bytes input :return: pseudo abi for method """ sighash = Utils.bytes_to_str(s[:4]) for pseudo_abi in FourByteDirectory.get_pseudo_abi_for_sighash(sighash, timeout=timeout, proxies=proxies): types = [ti["type"] for ti in pseudo_abi['inputs']] try: # test decoding _ = decode_abi(types, s[4:]) yield pseudo_abi except eth_abi.exceptions.DecodingError as e: continue
def get_pseudo_abi_for_input(s, timeout=None, proxies=None): """ Lookup sighash from 4bytes.directory, create a pseudo api and try to decode it with the parsed abi. May return multiple results as sighashes may collide. :param s: bytes input :return: pseudo abi for method """ sighash = Utils.bytes_to_str(s[:4]) for pseudo_abi in FourByteDirectory.get_pseudo_abi_for_sighash( sighash, timeout=timeout, proxies=proxies): types = [ti["type"] for ti in pseudo_abi['inputs']] try: # test decoding _ = decode_abi(types, s[4:]) yield pseudo_abi except eth_abi.exceptions.DecodingError as e: continue
def from_input_lookup(s): """ Return a new AbiMethod object from an input stream :param s: binary input :return: new AbiMethod object matching the provided input stream """ for pseudo_abi in FourByteDirectory.get_pseudo_abi_for_input(s): method = AbiMethod(pseudo_abi) types_def = pseudo_abi["inputs"] types = [t["type"] for t in types_def] names = [t["name"] for t in types_def] values = decode_abi(types, s[4:]) # (type, name, data) method.inputs = [{"type": t, "name": n, "data": v} for t, n, v in list( zip(types, names, values))] return method
def from_input_lookup(s): """ Return a new AbiMethod object from an input stream :param s: binary input :return: new AbiMethod object matching the provided input stream """ for pseudo_abi in FourByteDirectory.get_pseudo_abi_for_input(s): method = AbiMethod(pseudo_abi) types_def = pseudo_abi["inputs"] types = [t["type"] for t in types_def] names = [t["name"] for t in types_def] values = decode_abi(types, s[4:]) # (type, name, data) method.inputs = [{ "type": t, "name": n, "data": v } for t, n, v in list(zip(types, names, values))] return method
def decode_constructor( self, tx_input: Union[str, bytes], bytecode: Optional[Union[str, bytes]] = None, ): tx_input = hex_to_bytes(tx_input) if not self._constructor_type: raise InputDataError("Constructor is not found in ABI") if bytecode is not None: bytecode_len = len(hex_to_bytes(bytecode)) tx_input = tx_input[bytecode_len:] else: tx_input = detect_constructor_arguments(self._constructor_type, tx_input) types, names = get_types_names(self._constructor_type["inputs"]) values = decode_abi(types, tx_input) return ContractCall("constructor", list(zip(types, names, values)))
def test_empty_data_raises(): with pytest.raises(DecodingError): decode_abi(['uint32', 'uint32'], '0x')
def test_decode_two_uint32(input, expected): output = decode_abi(['uint32', 'uint32'], input) assert output == expected
def test_decode_abi_wrong_data_type_raises(): with pytest.raises(TypeError): decode_abi(['uint32', 'uint32'], '')
def test_decode_abi_empty_data_raises(): with pytest.raises(DecodingError): decode_abi(['uint32', 'uint32'], b'')
def test_decode_abi(type_str, expected, byte_str): abi_type = parse(type_str) types = [str(t) for t in abi_type.components] actual = decode_abi(types, byte_str) assert actual == expected
def test_decode_uint256_and_bytes(types, data, expected): actual = decode_abi(types, data) assert actual == expected
def decode_logs(self, abi: EventABI, data: List[Dict]) -> Iterator["ContractLog"]: if not abi.anonymous: event_id_bytes = keccak(to_bytes(text=abi.selector)) matching_logs = [ log for log in data if log["topics"][0] == event_id_bytes ] else: matching_logs = data topics_list: List[EventABIType] = [] data_list: List[EventABIType] = [] for abi_input in abi.inputs: if abi_input.indexed: topics_list.append(abi_input) else: data_list.append(abi_input) abi_topics = LogInputABICollection(abi, topics_list) abi_data = LogInputABICollection(abi, data_list) duplicate_names = set(abi_topics.names).intersection(abi_data.names) if duplicate_names: duplicate_names_str = ", ".join([n for n in duplicate_names if n]) raise DecodingError( "The following argument names are duplicated " f"between event inputs: '{duplicate_names_str}'.") for log in matching_logs: indexed_data = log["topics"] if log.get( "anonymous", False) else log["topics"][1:] log_data = hexstr_if_str(to_bytes, log["data"]) # type: ignore if len(indexed_data) != len(abi_topics.types): raise DecodingError( f"Expected '{len(indexed_data)}' log topics. Got '{len(abi_topics.types)}'." ) def decode_items(abi_types, data): def decode_value(t, v) -> Any: if t == "address": return self.decode_address(v) elif t == "bytes32": return HexBytes(v) return v return [decode_value(t, v) for t, v in zip(abi_types, data)] decoded_topic_data = [ decode_single(topic_type, topic_data) # type: ignore for topic_type, topic_data in zip(abi_topics.types, indexed_data) ] decoded_log_data = decode_abi(abi_data.types, log_data) # type: ignore event_args = dict( itertools.chain( zip(abi_topics.names, decode_items(abi_topics.types, decoded_topic_data)), zip(abi_data.names, decode_items(abi_data.types, decoded_log_data)), )) yield ContractLog( # type: ignore name=abi.name, index=log["logIndex"], event_arguments=event_args, transaction_hash=log["transactionHash"], block_hash=log["blockHash"], block_number=log["blockNumber"], ) # type: ignore