Signature-based decoding
How to decode calldata without an ABI
You can often decode Ethereum transaction input without possessing the contract’s full ABI. The first four bytes provide a function-selector clue; candidate signatures provide the types needed to interpret the remaining bytes. The result is useful, but it is not the same as verifying the exact contract ABI.
The short answer
“Without an ABI” really means without the full ABI. Decoding still needs a schema. A selector database can supply one or more function signatures—such as transfer(address,uint256)—and those input types act as a minimal, one-function ABI.
A worked ERC-20 example
Consider this 68-byte payload. Whitespace and labels are not part of the input.
a9059cbb selector
0000000000000000000000002222222222222222222222222222222222222222 word 1
0000000000000000000000000000000000000000000000000de0b6b3a7640000 word 2- 1
Extract the selector
The first four bytes are
0xa9059cbb. They identify a set of possible signatures, not the argument values. - 2
Find candidate signatures
Bundled ABIs or public signature databases associate this selector with
transfer(address,uint256). Its two input types now tell us how to split and interpret the argument block. - 3
Decode using those types
The first word becomes address
0x2222…2222. The second becomes the integer1000000000000000000. Calling it “one token” requires separate knowledge that this token uses 18 decimals. - 4
Re-encode and compare
Encode the recovered values with the same candidate signature. If the result matches the original bytes exactly, the interpretation is structurally consistent. That is stronger evidence than decoding alone, but it proves structural consistency—not which contract produced or accepted the call. Another colliding signature can fit too.
What the bytes can—and cannot—tell you
| Question | From calldata alone | Additional context needed |
|---|---|---|
| Which function? | Only a 4-byte selector, not a unique function | Target contract ABI or code to confirm it |
| What are the values? | Decodable if a candidate type layout fits | Verified target ABI or code for confidence |
| What are parameters called? | Names are not encoded | A source ABI with parameter names |
| What does an integer mean? | Only its numeric value | Token decimals, units, enums, or protocol rules |
| Which contract and chain? | Neither is included | Transaction or call context |
| Did the call succeed? | Calldata is input, not an execution result | Receipt, return data, revert data, or trace |
A reliable ABI-less decoding workflow
Start locally. Normalize the hex, require at least four bytes, extract the selector, and check known ABIs. A bundled or user-supplied ABI provides a richer schema and often preserves parameter names; only contract-specific verification makes it stronger evidence than an anonymous database entry.
Show an exact local match immediately when one exists, then look up the selector in more than one signature database to check for collisions and long-tail signatures. Parse every valid signature, attempt decoding against each candidate, then re-encode the recovered values. Rank exact byte-for-byte round trips above approximate matches, but keep alternative exact interpretations visible.
Finally, add transaction context when accuracy matters: the chain, destination address, verified implementation ABI, and—when the destination is a proxy—the implementation active at that block. These facts can turn a plausible decode into a confirmed one.
How calldata.dev applies this workflow
The decoder checks your saved ABIs and the bundled standards in this browser, and shows an exact local match as soon as it is available. In the background it queries Sourcify and 4byte.directory with the 4-byte selector, never the complete calldata or argument bytes. Candidate signatures are decoded locally and ranked using an exact re-encoding check. To use your own schema, add any JSON ABI, compiler artifact, or human-readable signatures to the local ABI library; its functions then participate in automatic matching. A saved ABI is still a candidate, not proof that it belongs to the destination address.
When two interpretations are both exact
The selector 0x42966c68 is shared by burn(uint256) and collate_propagate_storage(bytes16). The following argument word is valid under both schemas:
42966c68
11223344556677889900aabbccddeeff00000000000000000000000000000000- As
burn(uint256), the word is one very large unsigned integer. - As
collate_propagate_storage(bytes16), it is0x11223344556677889900aabbccddeefffollowed by the required right padding.
Both candidates re-encode to exactly the same bytes. No ranking trick can prove which meaning was intended; the destination contract’s ABI or bytecode must break the tie.
Inspect the ambiguous call →When you still need a contract-specific ABI
Unknown or private selectors
A selector database cannot return a signature nobody has submitted. The bytes do not contain enough type information to reconstruct an arbitrary schema reliably.
Selector collisions
Multiple signatures can share four bytes, and more than one layout can decode successfully. Only contract-specific evidence resolves the ambiguity.
Names and domain meaning
ABI encoding omits parameter names, token units, enum labels, and business rules. A verified ABI and source code restore that meaning.
Non-call payloads
Constructor arguments, fallback-specific formats, packed data, return values, revert data, and event logs require different context or decoding rules.
Common ABI-less decoding questions
Can the parameter types be inferred directly from 32-byte words?
Not reliably. A zero-padded word may be a number, address, boolean, fixed bytes, or an offset. Dynamic values add structure, but the correct interpretation still depends on the candidate ABI types.
Why does a decoder show several function signatures?
Their selectors collide, and each displayed type layout could decode the payload. Prefer a verified ABI for the target contract; otherwise compare exactness, source, and transaction context rather than trusting the first result.
Can nested calldata be decoded too?
Yes. When an outer ABI identifies a bytes value, calldata.dev offers a nested-decode control beside values that are at least four bytes long. Expanding it repeats the same local-first selector workflow and can recurse through calls such as Safe → Multicall3 → ERC-20. Raw hex always remains visible because the outer ABI does not prove what the inner bytes mean. No inner selector is looked up publicly until you expand that value.
Is it safe to paste sensitive calldata into calldata.dev?
Encoding and decoding run locally. In automatic lookup mode, the selector is the only calldata-derived value sent to the public signature services; no complete calldata or argument bytes are sent. Like any web service, those providers also receive normal request metadata such as your IP address and request origin. Calldata submitted in an on-chain transaction is public by design.
Continue learning
How Ethereum calldata works
Build real calls and see how selectors, 32-byte words, offsets, arrays, tuples, and nested calldata fit together.
Read guide →Core conceptEthereum function selectors
Learn how a canonical function signature becomes a 4-byte selector—and why the selector is not a unique function ID.
Read guide →