Logo do site Logo do site
  • Services
  • Venture
  • Content Hub
  • Contact Us
Close
  • Services
  • Venture
  • Content Hub
  • Contact Us
Blogpost

Solidity Spotlight: ABI encoding

July 24, 2023 3 min

Written by

  • Miguel Palhas
    Miguel Palhas

Chapter

  • Introduction
  • Making sense of bytecode
  • Reverting the process
  • Conclusion

Share article

Coppied!

Category

Engineering

When developing Ethereum apps, a common source of confusion for newcomers to the space is the ABI-encoded hex that represents function calls in a transaction

For example, an ERC20 transfer will show up as a blob of hex data on-chain:

0xa9059cbb0000000000000000000000004b7f6bfd248f541eb5474f591d54bc29444946db00000000000000000000000000000000000000000000003635c9adc5dea00000

Making sense of bytecode

To understand this blob, we first need to grab the first 8 bytes, which represent the truncated signature of the function being called:

0xa9059cbb

This is the function selector, used by the called contract to route to the appropriate function, and determined by hashing the corresponding function signature as seen on the contract’s ABI:

transfer(address,uint256)

Hashing this signature with keccak256 gives us a hash, of which we can take the first 4 bytes to get back the same sequence above. Go ahead, try it.

Reverting the process

Since hashing is a 1-way operation, there is no built-in way to retrieve the original ABI function from its signature. Furthermore, this process doesn’t guarantee uniqueness. Many known function headers hash to the same hex signature.

To reverse the process, the Ethereum community maintains databases of known ABI signatures, allowing developers to do a reverse lookup on them

The handiest way to query these is to use cast, part of the Foundry toolkit:

$ cast 4byte 0xa9059cbb
transfer(address,uint256)

In fact, cast can go even further, and decode the entire function call we used above:

$ cast 4byte-decode 0xa9059cbb0000000000000000000000004b7f6bfd248f541eb5474f591d54bc29444946db00000000000000000000000000000000000000000000003635c9adc5dea00000
1) "transfer(address,uint256)"
0x4b7f6bfD248f541eB5474f591D54Bc29444946db
1000000000000000000000 [1e21]

This will print out the signature first, and a sequential list of each decoded argument

We can also use cast calldata to encode a chosen function call:

$ cast calldata "transfer(address,uint256)" 0xa9059cbb0000000000000000000000004b7f6bfd248f541eb5474f591d54bc29444946db00000000000000000000000000000000000000000000003635c9adc5dea00000

Conclusion

We’ve seen how function encoding works for Solidity contracts, and how to use cast to make sense of it. cast is a much bigger Swiss-army knife of utility functions to interact with EVM chains. Check out its documentation to learn what else it can do

Share article

Coppied!

Category

Engineering

You may also like

ethui Stacks: One-Click Testnets
Blogpost
ethui Stacks: One-Click Testnets
Engineering
Stablecoins
Web3
January 27, 2026 5 min
Miguel Palhas
Miguel Palhas
Liquity V2 and How Liquidation Bots Work
Blogpost
Liquity V2 and How Liquidation Bots Work
Blockchain
Engineering
Web3
December 2, 2025 4 min
Gabriel Poça
Gabriel Poça
Subscribe to Subvisual Inspo

Go to

  • Services
  • Ventures
  • Blog
  • Jobs / Careers

We're social

  • Git
  • Dri
  • In
  • X

Contact us

[email protected]

Offices

Remote. Work anywhere in Europe.
Or join our mothership, landed in Braga, Portugal