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

Surya
  • 173
  • 1
  • 1
  • 9

4 Answers4

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
xuhcc
  • 191
  • 1
  • 5
  • 1
    Where can I find the normalize_name method as of now (2021)? pyethereum is not supported anymore. :( – dvdblk May 22 '21 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'])
osolmaz
  • 409
  • 4
  • 6
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 ()
tintin
  • 275
  • 3
  • 8
1

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

int( _value, 16)

Surya
  • 173
  • 1
  • 1
  • 9