22

I have an ABI and the input value of the transaction and want to know what function has been called on a contract and with what arguments (one or multiple of different types), preferably using geth, JSON-RPC and some pseudo code that I can then translate into Ruby.

There are a couple of similar questions on SO but none of them really answered the question in a way that's understandable to someone new to Ethereum.

As an example, I use the MetaCoin contract generated by Truffle. I call the method getBalance('0xfd46f749f9d916122fe958d7f8d5ad033b187472') and get the input 0xf8b2cb4f000000000000000000000000fd46f749f9d916122fe958d7f8d5ad033b187472.

truffle(development)> web3.eth.getTransaction('0x5d7a91c9f068d723ac52480c0ef61b9bf3f7b52dc726046e0b47f1beaa2f44ff')
{ hash: '0x5d7a91c9f068d723ac52480c0ef61b9bf3f7b52dc726046e0b47f1beaa2f44ff',
  nonce: 5,
  blockHash: '0xd150b520eb69a621a7218722c0de5b270c9abc499a90a81ca96340e274599c28',
  blockNumber: 6,
  transactionIndex: 0,
  from: '0xfd46f749f9d916122fe958d7f8d5ad033b187472',
  to: '0x8dec2f9cccbe718c7c51e9154f223eb226bb7942',
  value: { [String: '0'] s: 1, e: 0, c: [ 0 ] },
  gas: 4712388,
  gasPrice: { [String: '100000000000'] s: 1, e: 11, c: [ 100000000000 ] },
  input: '0xf8b2cb4f000000000000000000000000fd46f749f9d916122fe958d7f8d5ad033b187472' }

The ABI is as follows:

[
    {
      "constant": false,
      "inputs": [
        {
          "name": "addr",
          "type": "address"
        }
      ],
      "name": "getBalanceInEth",
      "outputs": [
        {
          "name": "",
          "type": "uint256"
        }
      ],
      "payable": false,
      "type": "function"
    },
    {
      "constant": false,
      "inputs": [
        {
          "name": "receiver",
          "type": "address"
        },
        {
          "name": "amount",
          "type": "uint256"
        }
      ],
      "name": "sendCoin",
      "outputs": [
        {
          "name": "sufficient",
          "type": "bool"
        }
      ],
      "payable": false,
      "type": "function"
    },
    {
      "constant": false,
      "inputs": [
        {
          "name": "addr",
          "type": "address"
        }
      ],
      "name": "getBalance",
      "outputs": [
        {
          "name": "",
          "type": "uint256"
        }
      ],
      "payable": false,
      "type": "function"
    },
    {
      "inputs": [],
      "payable": false,
      "type": "constructor"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "name": "_from",
          "type": "address"
        },
        {
          "indexed": true,
          "name": "_to",
          "type": "address"
        },
        {
          "indexed": false,
          "name": "_value",
          "type": "uint256"
        }
      ],
      "name": "Transfer",
      "type": "event"
    }
  ]

How can I decode any input to know what method was called and what arguments were passed in?

Update

I've added all data of the block with the input field at the very bottom in the logs.

{"number"=>"0x09",
 "hash"=>"0xf543eba0c80d49beea1f934c0f0ad9f0babe272a8318312545d43e6b612e4006",
 "parentHash"=>
  "0xde7a61e8dd84b5e080da8e16430951f7f138347c77ed263d0093e367c9d30775",
 "nonce"=>"0x0",
 "sha3Uncles"=>
  "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
 "logsBloom"=>
  "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
 "transactionsRoot"=>
  "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
 "stateRoot"=>
  "0x269cfa04ca1fe73202f788397ece62c520c64d5da7225ba2af2d673a2e9892f2",
 "receiptRoot"=>
  "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
 "miner"=>"0x0000000000000000000000000000000000000000",
 "difficulty"=>"0x0",
 "totalDifficulty"=>"0x0",
 "extraData"=>"0x0",
 "size"=>"0x03e8",
 "gasLimit"=>"0x47e7c4",
 "gasUsed"=>"0x5a3e",
 "timestamp"=>"0x58c83fda",
 "transactions"=>
  [{"hash"=>
     "0xce1eaf03dd1dfa5898243711ebcc1dc5c6357701f5a6c19f0b1f84130cb651fa",
    "nonce"=>"0x08",
    "blockHash"=>
     "0xf543eba0c80d49beea1f934c0f0ad9f0babe272a8318312545d43e6b612e4006",
    "blockNumber"=>"0x09",
    "transactionIndex"=>"0x0",
    "from"=>"0xfd46f749f9d916122fe958d7f8d5ad033b187472",
    "to"=>"0x8dec2f9cccbe718c7c51e9154f223eb226bb7942",
    "value"=>"0x0",
    "gas"=>"0x47e7c4",
    "gasPrice"=>"0x174876e800",
    "input"=>
     "0xf8b2cb4f000000000000000000000000fd46f749f9d916122fe958d7f8d5ad033b187472"}],
 "uncles"=>[]}
3
  • 1
    When you say "input" do you mean output? Because your example seems to indicate you want to parse output. Commented Mar 14, 2017 at 16:12
  • 1
    @SamuelHawksby-Robinson I've added more details to the bottom of the question to clarify.
    – migu
    Commented Mar 14, 2017 at 19:14
  • If you want to decode data via a UI you could use a tool like the following which allows you to enter in a custom ABI or even easier would be to rely on its own massive internal ABI archive. tools.deth.net/calldata-decoder
    – MShakeG
    Commented Nov 14, 2023 at 20:47

6 Answers 6

11

You can refer to a packaged developed by Consensys https://github.com/ConsenSys/abi-decoder

4
  • 2
    Awesome. This works very well and returns the name of the method (getBalance), the name of each argument passed in (receiver) and the value passed in (0xfd46f749f9d916122fe958d7f8d5ad033b187472) for each argument. It doesn't return the type of the argument though?
    – migu
    Commented Mar 15, 2017 at 10:21
  • 2
    Yeah. It does not return the type of arguments Commented Mar 16, 2017 at 8:01
  • 1
    I opened an issue, one friendly maintainer of the repo already added it
    – migu
    Commented Mar 16, 2017 at 10:12
  • 1
    Cool. Quick work Commented Mar 17, 2017 at 8:39
4

Ah ok, I understand what you are asking. You can do this web3.toAscii(transactionID.input) to get a human readable format.

See web3.toAscii https://github.com/ethereum/wiki/wiki/JavaScript-API#web3toascii

So with your code it would be:

transaction = web3.eth.getTransaction('0x5d7a91c9f068d723ac52480c0ef61b9bf3f7b52dc726046e0b47f1beaa2f44ff')
input = web3.toAscii(transaction.input)
console.log(input)
4
  • 12
    This gives me 'ø²ËO\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000ýF÷IùÙ\u0016\u0012/éX×øÕ­\u0003;\u0018tr'. I'm not familiar with Ascii and I don't know how I could derive from this string that the method getBalance(address) was called with the argument 0xfd46f749f9d916122fe958d7f8d5ad033b187472.
    – migu
    Commented Mar 14, 2017 at 22:00
  • 1
    @Samuel Hawksby-Robinson I used your command for my Tx hash (0x37361fd8eb5f78c7558ccfaa338c1935ecbc3d486f7a63c5b3e1b245779bc90e) However i receive these errors : "TypeError: web3.toAscii is not a function" and also "ReferenceError: input is not defined" Thanks
    – Questioner
    Commented May 7, 2018 at 13:59
  • @Questioner use web3.hexToAscii for later version of web3js
    – Rafid
    Commented Oct 20, 2019 at 0:36
  • 1
    @migu because this answer is wrong, you can't decode tx data without knowing abi, since first 4 bytes of data is function selector and rest decodes according to abi arg types and sizes.
    – lebed2045
    Commented Sep 23, 2021 at 21:35
4

You can now use the web3.eth.abi.decodeLog function (web3 1.0).

Example from the documentation:

web3.eth.abi.decodeLog([{
    type: 'string',
    name: 'myString'
},{
    type: 'uint256',
    name: 'myNumber',
    indexed: true
},{
    type: 'uint8',
    name: 'mySmallNumber',
    indexed: true
}],
'0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000748656c6c6f252100000000000000000000000000000000000000000000000000',
['0x000000000000000000000000000000000000000000000000000000000000f310', '0x0000000000000000000000000000000000000000000000000000000000000010']);
> Result {
    '0': 'Hello%!',
    '1': '62224',
    '2': '16',
    myString: 'Hello%!',
    myNumber: '62224',
    mySmallNumber: '16'
}
3

You can use the tool ethereum-input-data-decoder for decoding transaction input data given the ABI.

Example:

const InputDataDecoder = require('ethereum-input-data-decoder');
const decoder = new InputDataDecoder(`${__dirname}/abi.json`);

const data = `0x67043cae0000000000000000000000005a9dac9315fdd1c3d13ef8af7fdfeb522db08f020000000000000000000000000000000000000000000000000000000058a20230000000000000000000000000000000000000000000000000000000000040293400000000000000000000000000000000000000000000000000000000000000a0f3df64775a2dfb6bc9e09dced96d0816ff5055bf95da13ce5b6c3f53b97071c800000000000000000000000000000000000000000000000000000000000000034254430000000000000000000000000000000000000000000000000000000000`;

const result = decoder.decodeData(data);

console.log(result);

{
  "name": "registerOffChainDonation",
  "types": [
    "address",
    "uint256",
    "uint256",
    "string",
    "bytes32"
    ],
    "inputs": [
      <BN: 5a9dac9315fdd1c3d13ef8af7fdfeb522db08f02>,
      <BN: 58a20230>,
      <BN: 402934>,
      "BTC",
      <Buffer f3 df ... 71 c8>
    ]
}
2

I have developed a simple ruby gem for decoding and encoding transactions input data in EVM based blockchains: https://github.com/rkotov93/evm-tx-input-decoder

Here's usage example regarding your case:

# abi = parsed JSON ABI you provided
input = '0xf8b2cb4f000000000000000000000000fd46f749f9d916122fe958d7f8d5ad033b187472'
EvmTxInput::Decoder.new(abi).decode_input(input)

# Result:
# 
# #<EvmTxInput::Function:0x000000010b29a638
#  @arguments=[#<EvmTxInput::Argument:0x000000010b29ba88 @name="addr", @type="address", @value="0xfd46f749f9d916122fe958d7f8d5ad033b187472">],
#  @id="f8b2cb4f",
#  @name="getBalance">
1
  • Welcome to the Ethereum Stack Exchange! Nice way to start!
    – eth
    Commented Aug 9, 2023 at 6:57
0

On new web3.js 1.0 you must use: web3.utils.toAscii(transaction.input).

Some times you should do a let input = transaction.input.replace(/^0x/, ``); to remove these useless characters from string start.

See docs.

Your Answer

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

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