10

I am trying to decode input data from token sale transactions. This is one of the transactions I am trying to parse 0xf7b7196ca9eab6e4fb6e7bce81aeb25a4edf04330e57b3c15bece9d260577e2b Which has the following input data: 0xa9059cbb00000000000000000000000067fa2c06c9c6d4332f330e14a66bdf1873ef3d2b0000000000000000000000000000000000000000000000000de0b6b3a7640000

I know that the first 4 bytes represent the function (0xa9059cbb --> transfer)

The first parameter is the _to address (0x00000000000000000000000067fa2c06c9c6d4332f330e14a66bdf1873ef3d2b)

The second is _value who's type is uint256 (0x0000000000000000000000000000000000000000000000000de0b6b3a7640000).

How do I decode _value in python to get the amount of tokens being moved? I understand that for javascript there is abi-decoder which does something similar but I would like to know how to perform this myself in python.

I have read that the value is stored as a big endian int but when I try to read it, I do not get the value listed on etherscan for the transaction (https://etherscan.io/tx/0xf7b7196ca9eab6e4fb6e7bce81aeb25a4edf04330e57b3c15bece9d260577e2b)

The information I have about the parameter coding is from here: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI

4 Answers 4

6

If you know the contract ABI, call data could be decoded using pyethereum:

from ethereum.abi import (
    decode_abi,
    normalize_name as normalize_abi_method_name,
    method_id as get_abi_method_id)
from ethereum.utils import encode_int, zpad, decode_hex

def decode_contract_call(contract_abi: list, call_data: str):
    call_data_bin = decode_hex(call_data)
    method_signature = call_data_bin[:4]
    for description in contract_abi:
        if description.get('type') != 'function':
            continue
        method_name = normalize_abi_method_name(description['name'])
        arg_types = [item['type'] for item in description['inputs']]
        method_id = get_abi_method_id(method_name, arg_types)
        if zpad(encode_int(method_id), 4) == method_signature:
            try:
                args = decode_abi(arg_types, call_data_bin[4:])
            except AssertionError:
                # Invalid args
                continue
            return method_name, args
1
  • 1
    Where can I find the normalize_name method as of now (2021)? pyethereum is not supported anymore. :(
    – David
    May 22, 2021 at 20:34
5

If you are using web3.py, you don't need an external module. You just need to initiate the Contract instance with its ABI.

Then you run its decode_function_input method

decoded_input = contract.decode_function_input(tx['input'])
2

ethereum-input-decoder (pypi) uses the eth-abi project to create a high-level interface where you provide the json-abi and decode inputs to human readable representations (or access the decoded structures internally).

install:

python3 -m pip install ethereum-input-decoder

use:

python -m ethereum_input_decoder -a abi.json -c 0x0000...7a7a7a -t 0x797a...3d7707

or

from ethereum_input_decoder import ContractAbi

ca = ContractAbi(json.loads(json_abi_str))
print(ca.describe_input(b'797aaf...3d7707'))
# function confirm ((bytes32) _h = b'\x98\xd7\x90\xd3\x13>\x00I!Vi\xe0\x9bU\xa0\xb5\x9dXl\x95\xf9L-V\xb2\x81 @\x13=w\x07') returns ((bool) )
print(ca.describe_constructor(b'000000...5ba46b")))
# constructor None ((address[]) _owners = ('0x2903cadbe271e057edef157340b52a5898d7424f', '0xba7ca1bcf210c1b37cf5818816c4a819c3040ea7', '0x14cd6536d449e3f6878f2d6859e1ff92ae0990e6', '0x0c24441e42277445e38e02dfc3494577c05ba46b'), (uint256) _required = 2, (uint256) _daylimit = 1000000000000000000) returns ()
1

The value is plain hex, so it can be converted like so

int( _value, 16)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.