Python eth_abi.decode_abi() Examples

The following are 13 code examples of eth_abi.decode_abi(). You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may also want to check out all available functions/classes of the module eth_abi , or try the search function .
Example #1
Source File: exceptions.py    From brownie with MIT License 5 votes vote down vote up
def __init__(self, exc: ValueError) -> None:
        try:
            exc = yaml.safe_load(str(exc))
        except Exception:
            pass

        if isinstance(exc, dict) and "message" in exc:
            if "data" not in exc:
                raise ValueError(exc["message"]) from None

            self.message: str = exc["message"].rstrip(".")

            if isinstance(exc["data"], str):
                # handle parity exceptions - this logic probably is not perfect
                if "0x08c379a0" in exc["data"]:
                    revert_type, err_msg = [i.strip() for i in exc["data"].split("0x08c379a0", 1)]
                    err_msg = eth_abi.decode_abi(["string"], HexBytes(err_msg))
                    err_msg = f"{revert_type} '{err_msg}'"
                elif exc["data"].endswith("0x"):
                    err_msg = exc["data"][:-2].strip()
                else:
                    err_msg = exc["data"]
                raise ValueError(f"{self.message}: {err_msg}") from None

            try:
                txid, data = next((k, v) for k, v in exc["data"].items() if k.startswith("0x"))
            except StopIteration:
                raise ValueError(exc["message"]) from None

            self.txid: str = txid
            self.revert_type: str = data["error"]
            self.revert_msg: Optional[str] = data.get("reason")
            self.pc: Optional[str] = data.get("program_counter")
            self.source: str = ""
            if self.revert_type == "revert":
                self.pc -= 1
            if self.revert_msg is None and self.revert_type in ("revert", "invalid opcode"):
                self.revert_msg = brownie.project.build._get_dev_revert(self.pc)
        else:
            raise ValueError(str(exc)) from None 
Example #2
Source File: transaction.py    From brownie with MIT License 5 votes vote down vote up
def _reverted_trace(self, trace: Sequence) -> None:
        self._modified_state = False
        # get events from trace
        self._events = _decode_trace(trace)
        if self.contract_address:
            step = next((i for i in trace if i["op"] == "CODECOPY"), None)
            if step is not None and int(step["stack"][-3], 16) > 24577:
                self._revert_msg = "exceeds EIP-170 size limit"
        if self._revert_msg is not None:
            return

        # iterate over revert instructions in reverse to find revert message
        for step in (i for i in trace[::-1] if i["op"] in ("REVERT", "INVALID")):
            if step["op"] == "REVERT" and int(step["stack"][-2], 16):
                # get returned error string from stack
                data = _get_memory(step, -1)[4:]
                self._revert_msg = decode_abi(["string"], data)[0]
                return
            if self.contract_address:
                self._revert_msg = "invalid opcode" if step["op"] == "INVALID" else ""
                return
            # check for dev revert string using program counter
            self._revert_msg = build._get_dev_revert(step["pc"])
            if self._revert_msg is not None:
                return
            # if none is found, expand the trace and get it from the pcMap
            self._expand_trace()
            try:
                pc_map = _find_contract(step["address"])._build["pcMap"]
                # if this is the function selector revert, check for a jump
                if "first_revert" in pc_map[step["pc"]]:
                    i = trace.index(step) - 4
                    if trace[i]["pc"] != step["pc"] - 4:
                        step = trace[i]
                self._revert_msg = pc_map[step["pc"]]["dev"]
                return
            except (KeyError, AttributeError):
                pass

        step = next(i for i in trace[::-1] if i["op"] in ("REVERT", "INVALID"))
        self._revert_msg = "invalid opcode" if step["op"] == "INVALID" else "" 
Example #3
Source File: contract.py    From brownie with MIT License 5 votes vote down vote up
def call(self, *args: Tuple, block_identifier: Union[int, str, bytes] = None) -> Any:
        """
        Call the contract method without broadcasting a transaction.

        Arguments
        ---------
        *args
            Contract method inputs. You can optionally provide a
            dictionary of transaction properties as the last arg.
        block_identifier : int | str | bytes, optional
            A block number or hash that the call is executed at. If not given, the
            latest block used. Raises `ValueError` if this value is too far in the
            past and you are not using an archival node.

        Returns
        -------
            Contract method return value(s).
        """

        args, tx = _get_tx(self._owner, args)
        if tx["from"]:
            tx["from"] = str(tx["from"])
        del tx["required_confs"]
        tx.update({"to": self._address, "data": self.encode_input(*args)})

        try:
            data = web3.eth.call({k: v for k, v in tx.items() if v}, block_identifier)
        except ValueError as e:
            raise VirtualMachineError(e) from None

        if HexBytes(data)[:4].hex() == "0x08c379a0":
            revert_str = eth_abi.decode_abi(["string"], HexBytes(data)[4:])[0]
            raise ValueError(f"Call reverted: {revert_str}")
        if self.abi["outputs"] and not data:
            raise ValueError("No data was returned - the call likely reverted")

        return self.decode_output(data) 
Example #4
Source File: contract.py    From brownie with MIT License 5 votes vote down vote up
def decode_output(self, hexstr: str) -> Tuple:
        """Decodes hexstring data returned by this method.

        Args:
            hexstr: Hexstring of returned call data

        Returns: Decoded values."""
        types_list = get_type_strings(self.abi["outputs"])
        result = eth_abi.decode_abi(types_list, HexBytes(hexstr))
        result = format_output(self.abi, result)
        if len(result) == 1:
            result = result[0]
        return result 
Example #5
Source File: base.py    From clove with GNU General Public License v3.0 5 votes vote down vote up
def extract_secret_from_redeem_transaction(self, tx_address: str) -> str:
        '''
        Extracting secret from redeem transaction.

        Args:
            tx_address (str): address of the redeem transaction

        Returns:
            str,: Secret string

        Raises:
            ValueError: When given transaction was not a redeem type transaction

        Example:
            >>> from clove.network import EthereumTestnet
            >>> network = EthereumTestnet()
            >>> network.extract_secret_from_redeem_transaction('0x9e41847c3cc780e4cb59902cf55657f0ee92642d9dee4145e090cbf206d4748f')  # noqa: E501
            b2eefaadbbefeb9d9467092b612464db7c6724f71b5c1d70c85853845728f0e9
        '''
        tx_dict = self.get_transaction(tx_address)
        method_id = self.extract_method_id(tx_dict['input'])
        if method_id != self.redeem:
            logger.debug('Not a redeem transaction.')
            raise ValueError('Not a redeem transaction.')
        method_name = self.get_method_name(method_id)
        input_types = get_abi_input_types(find_matching_fn_abi(self.abi, fn_identifier=method_name))
        input_values = decode_abi(input_types, Web3.toBytes(hexstr=tx_dict['input'][10:]))
        return input_values[0].hex() 
Example #6
Source File: contract.py    From clove with GNU General Public License v3.0 5 votes vote down vote up
def __init__(self, network, tx_dict):

        self.network = network
        self.tx_dict = tx_dict
        self.abi = self.network.abi
        self.method_id = self.network.extract_method_id(tx_dict['input'])
        self.type = self.network.get_method_name(self.method_id)
        self.token = None

        if self.method_id != self.network.initiate:
            logger.warning('Not a contract transaction.')
            raise ValueError('Not a contract transaction.')

        input_types = get_abi_input_types(find_matching_fn_abi(self.abi, fn_identifier=self.type))
        input_names = get_abi_input_names(find_matching_fn_abi(self.abi, fn_identifier=self.type))
        input_values = decode_abi(input_types, Web3.toBytes(hexstr=self.tx_dict['input'][10:]))
        self.inputs = dict(zip(input_names, input_values))

        self.locktime = datetime.utcfromtimestamp(self.inputs['_expiration'])
        self.recipient_address = Web3.toChecksumAddress(self.inputs['_participant'])
        self.refund_address = self.tx_dict['from']
        self.secret_hash = self.inputs['_hash'].hex()
        self.contract_address = Web3.toChecksumAddress(self.tx_dict['to'])
        self.block_number = self.tx_dict['blockNumber']
        self.confirmations = self.network.get_latest_block - self.block_number
        self.balance = self.get_balance()

        if self.is_token_contract:
            self.value_base_units = self.inputs['_value']
            self.token_address = Web3.toChecksumAddress(self.inputs['_token'])
            self.token = self.network.get_token_by_address(self.token_address)
            self.value = self.token.value_from_base_units(self.value_base_units)
            self.symbol = self.token.symbol
        else:
            self.value_base_units = self.tx_dict['value']
            self.value = self.network.value_from_base_units(self.value_base_units)
            self.symbol = self.network.default_symbol 
Example #7
Source File: contract.py    From tron-api-python with MIT License 5 votes vote down vote up
def decode_function_input(self, data):
        data = HexBytes(data)
        selector, params = data[:4], data[4:]
        func = self.get_function_by_selector(selector)
        names = [x['name'] for x in func.abi['inputs']]
        types = [x['type'] for x in func.abi['inputs']]
        decoded = decode_abi(types, params)
        normalized = map_abi_data(BASE_RETURN_NORMALIZERS, types, decoded)
        return func, dict(zip(names, normalized)) 
Example #8
Source File: sdk.py    From erc20token-sdk-python with GNU General Public License v2.0 5 votes vote down vote up
def get_transaction_data(self, tx_id):
        """Gets transaction data for the provided transaction id.

        :param str tx_id: transaction id (hash)
        :return: transaction data
        :rtype: :class:`~erc20token.TransactionData`
        """
        tx_data = TransactionData()
        tx = self.web3.eth.getTransaction(tx_id)
        if not tx:
            return tx_data
        tx_data.from_address = tx['from']
        tx_data.to_address = tx['to']
        tx_data.ether_amount = self.web3.fromWei(tx['value'], 'ether')
        tx_data.status = self._get_tx_status(tx)
        if not tx.get('blockNumber'):
            tx_data.num_confirmations = 0
        else:
            tx_block_number = int(tx['blockNumber'])
            cur_block_number = int(self.web3.eth.blockNumber)
            tx_data.num_confirmations = cur_block_number - tx_block_number + 1
        tx_input = tx.get('input')
        if tx_input and (tx_input.lower().startswith(ERC20_TRANSFER_ABI_PREFIX.lower())):
            to, amount = decode_abi(['uint256', 'uint256'], tx_input[len(ERC20_TRANSFER_ABI_PREFIX):])
            tx_data.to_address = to_hex(to)
            tx_data.token_amount = self.web3.fromWei(amount, 'ether')
        return tx_data 
Example #9
Source File: sdk.py    From erc20token-sdk-python with GNU General Public License v2.0 5 votes vote down vote up
def _check_parse_contract_tx(self, tx, filter_args):
        """Parse contract transaction and check whether it matches the supplied filter.
        If the transaction matches the filter, the first returned value will be True, and the rest will be
        correctly filled. If there is no match, the first returned value is False and the rest are empty.

        :param dict tx: transaction object

        :param dict filter_args: a filter that contains fields 'to', 'from' or both.

        :returns: matching status, from address, to address, token amount
        :rtype: tuple
        """
        if not tx.get('to') or tx['to'].lower() != self.token_contract.address.lower():  # must be sent to our contract
            return False, '', '', 0
        tx_input = tx.get('input')
        if not tx_input or tx_input == '0x':  # not a contract transaction
            return False, '', '', 0
        if not tx_input.lower().startswith(ERC20_TRANSFER_ABI_PREFIX.lower()):
            # only interested in calls to 'transfer' method
            return False, '', '', 0

        to, amount = decode_abi(['uint256', 'uint256'], tx_input[len(ERC20_TRANSFER_ABI_PREFIX):])
        to = to_hex(to)
        amount = self.web3.fromWei(amount, 'ether')
        if (('from' in filter_args and tx['from'].lower() == filter_args['from'].lower() and
                ('to' not in filter_args or to.lower() == filter_args['to'].lower())) or
            ('to' in filter_args and to.lower() == filter_args['to'].lower())):
                return True, tx['from'], to, amount
        return False, '', '', 0 
Example #10
Source File: throws_contract.py    From eth-tester with MIT License 5 votes vote down vote up
def _decode_throws_result(contract_name, fn_name, result):
    from eth_abi import decode_abi

    fn_abi = THROWS_ABI[contract_name][fn_name]
    output_types = [
        output_abi['type']
        for output_abi
        in fn_abi['outputs']
    ]

    return decode_abi(output_types, decode_hex(result)) 
Example #11
Source File: math_contract.py    From eth-tester with MIT License 5 votes vote down vote up
def _decode_math_result(fn_name, result):
    from eth_abi import decode_abi

    fn_abi = MATH_ABI[fn_name]
    output_types = [
        output_abi['type']
        for output_abi
        in fn_abi['outputs']
    ]

    return decode_abi(output_types, decode_hex(result)) 
Example #12
Source File: test_contract_call_interface.py    From web3.py with MIT License 5 votes vote down vote up
def test_call_get_string_value(string_contract, call):
    result = call(contract=string_contract,
                  contract_function='getValue')
    # eth_abi.decode_abi() does not assume implicit utf-8
    # encoding of string return values. Thus, we need to decode
    # ourselves for fair comparison.
    assert result == "Caqalai" 
Example #13
Source File: decoder.py    From django-eth-events with MIT License 4 votes vote down vote up
def decode_log(self, log):
        """
        Decodes an ethereum log and returns the recovered parameters along with the method from the abi that was used
        in decoding. Raises a LookupError if the log's topic is unknown,
        :param log: ethereum log
        :return: dictionary of decoded parameters, decoding method reference
        """
        method_id = remove_0x_head(log['topics'][0])

        if method_id not in self.methods:
            raise LookupError("Unknown log topic.")

        # method item has the event name, inputs and types
        method = self.methods[method_id]
        decoded_params = []
        data_i = 0
        topics_i = 1
        data_types = []

        # get param types from properties not indexed
        for param in method['inputs']:
            if not param['indexed']:
                data_types.append(param['type'])

        # decode_abi expect data in bytes format instead of str starting by 0x
        log_data_bytes = HexBytes(log['data'])
        decoded_data = decode_abi(data_types, log_data_bytes)

        for param in method['inputs']:
            decoded_p = {
                'name': param['name']
            }
            if param['indexed']:
                decoded_p['value'] = log['topics'][topics_i]
                topics_i += 1
            else:
                decoded_p['value'] = decoded_data[data_i]
                data_i += 1

            if '[]' in param['type']:
                if 'address' in param['type']:
                    decoded_p['value'] = [self.decode_address(address) for address in decoded_p['value']]
                else:
                    decoded_p['value'] = list(decoded_p['value'])
            elif 'address' == param['type']:
                decoded_p['value'] = self.decode_address(decoded_p['value'])

            decoded_params.append(decoded_p)

        decoded_event = {
            'params': decoded_params,
            'name': method['name'],
            'address': self.decode_address(log['address']),
            'transaction_hash': self.decode_transaction(log['transactionHash'])
        }

        return decoded_event