Unlocking the Secrets of an Ethereum Transaction

Decoding Input Data with Python

Logan Bonsignore
Coinmonks
Published in
4 min readJun 24, 2021

--

If you’re taking your first steps as a blockchain engineer, a great place to start can be building an app that decodes transactions — specifically input data. Decoding input data is key to understanding what actually took place in a transaction. For example, take a look at this transaction below.

You can see that it contains high-level details about the transaction including to and from addresses, gas used, value of the transaction, signature components and more. But what actually took place in this transaction? Which tokens were exchanged? Whose smart contract was used? To truly understand the details we need to decode the input data.

Input data… what’s that?

Before we get to the code, let’s take a moment to understand input data and how it is used on the blockchain. We will use the transaction shown above as our example.

When we search for the transaction on Etherscan we see that someone sent 4.195472736637743549 ETH to a SushiSwap smart contract in exchange for 20 BOR tokens. The user likely initiated the transaction in the SushiSwap user interface which lead to the transaction being executed by the smart contract. But how did the smart contract know what to do? You guessed it — input data.

Input data is described by ethereum.org as extra information required by the transaction. This information’s structure varies depending on which type of transaction is taking place. If the transaction is a message call (signed by an Externally Owned Account (EOA) or from a smart contract to an EOA) the input data holds information needed to properly execute the smart contract’s function. If it’s a contract creation transaction the input data will hold the contracts bytecode and any encoded arguments required by the constructor. If the transaction is a funds transfer between two EOA’s, the input data will be empty as there is no extra information required.

In our example the transaction is a message call as we are invoking a function on a deployed smart contract. The input data looks like this:

0x8803dbee000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000000000000000000000000000003a4837fc5242c4ec00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000009a7ed54b8c2c5816c1800476f5111a1e886575020000000000000000000000000000000000000000000000000000000060cfee3f0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000003c9d6c1c73b31c837832c72e04d3152f051fc1a9

This hexadecimal value is used by the smart contract to determine which function it needs to execute and which arguments it needs to ensure the function is executed as intended by the SushiSwap user. When decoded, you get the function definition:

swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] path, address to, uint256 deadline)

And it’s arguments:

amountOut: 20000000000000000000
amountInMax: 4199668209374381292
path: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, 0x3c9d6c1C73b31c837832c72E04D3152f051fc1A9
to: 0x9A7eD54b8c2c5816C1800476F5111A1e88657502
deadline: 1624239679

But how can we use Python to transform this hexadecimal input to plain text? Let’s break down the code.

Decoding input data

We will use the Web3 library to interact with an Ethereum node. For installation and getting started requirements see the Web3 documentation.

Our first step is to get the transaction summary by passing the transaction hash to Web3’s get_transaction() method. This returns a dictionary containing relevant information to our transaction as shown at the beginning of this article.

Next we need to get the smart contract’s Application Binary Interface (ABI). This allows us to create a Contract object which we use to interact with the smart contract. We can do this by calling the Etherscan API. You’ll need an Etherscan API key and can get one for free by setting up and account on Etherscan’s developer page.

Note that we are using the to value from our transaction as the smart contract address. For transactions that invoke a smart contract’s function the smart contract address will always be the to address of the transaction.

Next we will create our Contract object by passing the smart contract’s address and ABI as arguments to the contract() method. The returned object contains many helpful methods and properties we can use to interact with our smart contract.

Once we have our Contract object we use the decode_function_input() method to decode our input.

And bam! We did it. The method returns a tuple which we can unpack into two objects. func_obj is an instance of the smart contract function used by our transaction.

<class 'web3._utils.datatypes.swapTokensForExactTokens'>swapTokensForExactTokens(unit256,united256,address[],unit256)

This object includes the smart contract’s ABI, the function name, a gas estimator tool and other methods and properties we can use to build and call new transactions.

func_params is a dictionary holding the transaction’s parameters as keys and it’s arguments as values.

With our input data decoded we can now see the amount of ETH paid by the SushiSwap user, the amount of BOR tokens they received, the smart contract addresses of the tokens involved and the transaction’s deadline. This gives us true insight into what took place in this transaction.

Up next…

This foundational skill can be applied to many applications including blockchain intelligence, blockchain data analytics and more. My next article will be about decoding transaction logs. Hit the follow button so you don’t miss it.

If you found this article helpful it would be greatly appreciated if you could leave a comment and applaud. Thank you!

Join Coinmonks Telegram Channel and Youtube Channel get daily Crypto News

Also, Read

--

--