Transaction Calldata Explained: How to Decode Input Data

Every Ethereum transaction that touches a smart contract carries a block of hexadecimal data. That block is the calldata, and it tells the contract which function to run and what arguments to pass. On its own it looks like a wall of random hex — something like 0xa9059cbb000.... Decode it, and the wall turns into a plain instruction: send 1 token to this address.

A plain ETH transfer between two wallets has no calldata at all; the data field is empty. The moment a transaction calls a contract — a token transfer, a swap, an approval — calldata appears and carries the full intent of the call.

This guide covers what transaction calldata is, how it’s structured, and how to decode it with and without the contract’s ABI. It also looks at what calldata costs in gas and how it differs from Solidity’s calldata keyword, memory, and storage — two things people often mix up.

What Is Transaction Input Data?

Calldata is the input data attached to a transaction and sent to a smart contract when the transaction runs. In a transaction object it lives in the data field. When you fetch a transaction back from an Ethereum endpoint, the same bytes appear under the input field.

The contract reads those bytes to decide what to do. Calldata is read-only and exists only for the duration of the call, which makes it the cheapest place a contract can read inputs from.

If the data field is empty (0x), the transaction simply moves ETH. If it contains bytes, the transaction is calling a function — and those bytes encode both the function and its arguments.

How Is Input Data Structured?

Calldata follows a fixed layout defined by the Ethereum Contract ABI (Application Binary Interface). The first 4 bytes identify the function. Everything after that is the function’s arguments, encoded in 32-byte chunks.

What Is a Function Selector?

The function selector is the first 4 bytes of the calldata, and it’s how a contract knows which function you want. It’s calculated as the first 4 bytes of the Keccak-256 hash of the function’s signature — the name plus its parameter types, with no spaces.

For the ERC-20 transfer function, the signature is transfer(address,uint256). Hash it, take the first 4 bytes, and you get 0xa9059cbb. Any transfer on any ERC-20 token starts with those same 4 bytes.

How Arguments Are Encoded

After the selector, each argument is padded to 32 bytes and laid out in order. Fixed-size types like address and uint256 sit inline. Dynamic types like bytes or arrays store an offset that points to their real data further along the calldata.

Here’s the full calldata for a transfer of 1 token (18 decimals) to a sample address, split into its parts:

0xa9059cbb
0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4
0000000000000000000000000000000000000000000000000de0b6b3a7640000
PartBytesValue (trimmed)Meaning
Selector4a9059cbbtransfer(address,uint256)
Argument 132…56beddC4recipient address, left-padded
Argument 232…a7640000amount: 1000000000000000000 base units

Read top to bottom: call transfer, send to 0x5B38…ddC4, move one token’s worth of base units. Nothing is hidden in there. Calldata is complete and deterministic.

Why Does Decoding Input Data Matter?

Raw calldata hides intent behind hex. Decoding it is the only reliable way to see what a transaction actually does, before or after it runs.

The clearest case is security. Wallet-drainer scams work by getting a user to sign a transaction whose calldata grants a token approval — often an unlimited one — to an attacker’s address. The wallet screen might show a harmless label, but the calldata is the ground truth. Decoding it reveals the real function and the real spender.

Decoding also drives everyday development: working out why a transaction reverted, confirming a contract call was built correctly, and labeling on-chain activity in analytics and explorers. If you’ve ever seen a wallet preview that reads “Approve USDC for Uniswap,” that line came from decoding calldata.

Who Needs to Read Transaction Input?

Anyone who needs to know what a transaction does, not just that it happened. In practice that includes:

  • Smart-contract developers debugging failed or unexpected transactions.
  • Security researchers and auditors checking approvals, spender addresses, and malicious payloads.
  • Wallet engineers building human-readable transaction previews and simulations.
  • Analytics and indexing teams classifying activity by function and protocol.
  • Searchers and bot operators reading pending transactions to understand intent.

How to Decode Transaction Input Data

Decoding follows the same three moves every time: get the input bytes, read the selector, then decode the arguments. How you handle the last step depends on whether you have the contract’s ABI.

  1. Get the input. Copy it from a block explorer, or fetch it in code — an Ethereum endpoint’s eth_getTransactionByHash method returns the transaction with its input field.
  2. Read the selector. Take the first 10 characters (0x plus 8 hex digits). That’s your function fingerprint.
  3. Decode the arguments. Use the ABI if you have it; look the selector up in a signature database if you don’t.

Decoding With the Contract ABI

If you have the contract’s ABI, decoding is exact and unambiguous. Libraries do the work in a line or two.

With ethers.js (v6), Interface.parseTransaction takes the calldata and returns the function name and typed arguments:

js

import { Interface } from "ethers";

const abi = ["function transfer(address to, uint256 amount)"];
const iface = new Interface(abi);

const data =
  "0xa9059cbb0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4" +
  "0000000000000000000000000000000000000000000000000de0b6b3a7640000";

const decoded = iface.parseTransaction({ data });
console.log(decoded.name);        // "transfer"
console.log(decoded.args.to);     // 0x5B38Da...ddC4
console.log(decoded.args.amount); // 1000000000000000000n

In Python, web3.py exposes contract.decode_function_input(data), and Foundry’s cast decode-calldata does the same from the command line when you supply the signature.

Decoding Without the ABI

Unverified contracts don’t publish an ABI, so you only have the selector to go on. Signature databases map known selectors back to function signatures.

The Ethereum Signature Database at 4byte.directory holds over 1.4 million signatures contributed by the community. Foundry queries it directly: cast 4byte 0xa9059cbb returns transfer(address,uint256), and cast 4byte-calldata decodes the whole payload at once.

One catch: a 4-byte selector isn’t unique. Different function signatures can hash to the same 4 bytes, so a lookup can return several candidates. Treat the result as a strong hint, not proof, and verify against the contract where it matters.

To decode at scale, you need the transactions in the first place. Pulling the input field for live or historical transactions means calling eth_getTransactionByHash against an Ethereum endpoint — for example, a NOWNodes Ethereum endpoint:

bash

curl https://eth.nownodes.io \
  -H "api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_getTransactionByHash","params":["0xYOUR_TX_HASH"]}'

The response includes an input field — that’s the calldata, ready to decode with any tool above. When a transaction reverts and the calldata alone doesn’t explain why, Debug & Trace methods such as debug_traceTransaction expose the internal calls and their calldata step by step. For a quick visual check of a single transaction, the NOWNodes Ethereum explorer shows the decoded call without any code, and you can test the method against free public endpoints before wiring in an API key.

What Does Input Data Cost in Gas?

Calldata isn’t free to include in a transaction. Under Ethereum’s gas rules, each zero byte of calldata costs 4 gas and each non-zero byte costs 16 gas. That’s why gas-optimized contracts and addresses try to keep calldata small and zero-heavy.

Since the Pectra upgrade went live on May 7, 2025, a second rule applies. EIP-7623 added a floor cost for calldata: transactions that carry a lot of data but do little computation now pay at least 10 gas per calldata “token,” where a zero byte counts as 1 token and a non-zero byte as 4. The aim was to push rollups to store their data in blobs instead of calldata, freeing up block space.

For most everyday transactions — a transfer, a swap — the floor changes nothing, because they do enough computation to stay above it. It mainly bites on data-heavy, low-execution transactions.

Where Solidity Keeps Data During a Call

The word calldata also shows up inside Solidity code, where it means something related but narrower. In a contract, calldata is one of three data locations, alongside memory and storage.

LocationLifetimeMutableRelative costTypical use
calldataOne call, read-onlyNoCheapestExternal function inputs
memoryOne callYesModerateTemporary working data
storagePersistentYesMost expensiveContract state kept on-chain

When a function parameter is marked calldata, Solidity reads it straight from the transaction’s input without copying it, which is the cheapest option for external inputs. memory is a mutable scratch space that lasts for a single call. storage is the contract’s permanent state, written to the chain and the most expensive to touch.

So “calldata” can mean two things: the raw input bytes of a transaction, and the Solidity location that reads them. They point at the same data from different angles.

Conclusion

Decoding calldata is how you turn an opaque hex string into a clear statement of what a transaction does. The method is always the same: isolate the 4-byte selector, then decode the arguments — exactly with the ABI, or approximately through a signature database when no ABI is available.

For a one-off check, a block explorer or a 4byte lookup is enough. For anything programmatic — monitoring, analytics, auditing — you’ll decode in code against an Ethereum endpoint, with Debug & Trace on hand for the transactions that revert. And before you sign anything, decoding the calldata is the surest way to confirm a transaction does what its label claims.

FAQ

What does the “0x” prefix on input data mean?

It only signals that what follows is hexadecimal. The 0x is a formatting marker, not part of the data itself. A selector written as 0xa9059cbb is really the 4 bytes a9 05 9c bb.

Is transaction input stored on-chain permanently?

Yes. Calldata is part of the transaction, so it stays in the chain’s history and can be retrieved later with eth_getTransactionByHash, including through archive access for older transactions. It isn’t the same as contract storage, though — it was never part of the contract’s persistent state.

How is input data different from an EIP-4844 blob?

Blobs, introduced by EIP-4844, are a separate and cheaper data space built for rollups. Unlike calldata, blob data isn’t readable by the EVM — contracts only see a hash of it — and the network prunes it after about 18 days. Calldata is readable during execution and kept permanently.

Can a function selector match more than one function?

Yes. A selector is only 4 bytes, so different function signatures can produce the same one, which is called a collision. Signature databases return every known match for a selector, so a decoder can show the wrong name if it picks the wrong candidate. When accuracy matters, verify the signature against the contract’s own ABI.