Decoding EVM Transaction Calldata
Calldata is the binary payload that travels with every contract transaction on Ethereum and EVM-compatible chains. The first 4 bytes are a function selector. Everything after is ABI-encoded arguments. If you can read calldata, you can answer the question every wallet user should ask before signing: what is this transaction actually going to do.
Try it now
ABI Decoder
Runs in your browser, nothing leaves your device.
Every external function call begins with a 4-byte selector, the first 4 bytes of keccak256 of the function's canonical signature. For example, transfer(address,uint256) hashes to 0xa9059cbb. When you see calldata starting with 0xa9059cbb, you are looking at an ERC-20 transfer. Selectors are not unique by design, two unrelated functions can collide, but in practice common selectors are well known.
After the selector, arguments are packed in 32-byte slots. Static types (address, uint256, bool) take exactly one slot. Dynamic types (bytes, string, arrays) use a head/tail layout where the head holds an offset into the tail section. A transfer(address,uint256) call always has 68 bytes of calldata: 4 for the selector, 32 for the recipient, 32 for the amount.
Match the selector against a database to identify the function. Confirm the destination address in the transaction matches the contract you expected. Decode the parameters and check that recipients and amounts make sense. If the UI says you are swapping 1 ETH for USDC but the calldata calls approve() with max uint256, the UI is lying.
Examples
ERC-20 transfer
0xa9059cbb000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa960450000000000000000000000000000000000000000000000000de0b6b3a7640000
transfer(address to=0xd8dA...6045, uint256 amount=1000000000000000000) — 1.0 token (assuming 18 decimals)
ERC-20 unlimited approval
0x095ea7b3000000000000000000000000<spender>ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
approve(address spender=<spender>, uint256 amount=2^256-1) — grants the spender permission to drain every token of this type from your wallet
Security context
Wallet UIs simulate transactions, but simulations can be fooled by contracts that branch on msg.sender or block number. Reading the raw calldata is the only ground truth you have before signing. If your wallet shows you a friendly description but cannot decode the calldata yourself, treat the transaction as unverified.
Frequently asked
Dynamic types like bytes and arrays add length prefixes and padding. A function taking a single bytes argument might produce 100+ bytes of calldata even for a small input. The ABI specification requires every argument slot to be a multiple of 32 bytes.
Yes. Selectors are 4 bytes (32 bits), so collisions exist. Attackers occasionally craft function names that collide with well-known selectors to confuse decoders. Always verify against the contract's actual ABI when stakes are high.
Related techniques
Detecting Token Approval Phishing in Calldata
Spot malicious approve(), permit(), and setApprovalForAll() calls before signing. Learn the calldata patterns wallet drainers use to empty wallets in a single signature.
Reverse Lookup of EVM Function Selectors
Identify unknown 4-byte function selectors by computing keccak256 of candidate signatures. Useful when reading calldata against unverified contracts.
Decoding Raw RLP-Encoded Ethereum Transactions
Parse signed and unsigned Ethereum transactions in RLP form. Inspect nonce, gas, value, chain ID, and signature fields across Legacy, EIP-2930, and EIP-1559 transaction types.
Reading Smart Contract Calldata
Use calldata decoding and selector lookups to spot honeypot contracts before interacting. Identify hidden fees, transfer-blocking logic, and admin backdoors without running the contract.