Interacting with deployed contracts using web3 libraries like ethers.js requires having a copy of the contract ABI somewhere in your code, and keeping it up to date is a manual and error prone process. Using the thirdweb SDKs, ABIs are automatically inferred from any deployed contracts. All you need is the contract address. No ABI copy pasting, or maintenance required.
So how does it work under the hood? The answer might surprise you!
No databases, no servers - all it takes is a powerful, yet rarely discussed feature of the Solidity compiler. Let's take a closer look!
The solidity team had the incredible foresight and ingenuity to make any contract auto verifiable from its bytecode alone. No etherscan verification needed. The idea is to make the solc compiler encode some information about the contracts in the bytecode itself during the compilation process. Enough information to be able to safely auto verify any contract in a decentralized way.
When you compile a contract using any of the popular frameworks like hardhat, forge, truffle, etc, it enables the bytecodeHash: "ipfs"
compiler flag by default. It's such a powerful feature, yet so few people know about it. Let's see how it works.
The solidity compiler, solc, produces artifacts at the end of a successful compilation. Amongst these artifacts is one called contract metadata. This a standardized JSON object, containing useful information about the contract like its name, ABI, source code, formatted code comments and compiler settings.
When solc produces the compiled bytecode for a contract, it appends a few extra bytes at the end, allowing anyone to retrieve the original contract metadata that was produced when compiling this bytecode. But how?
The genius trick is taking advantage of my favorite property of IPFS and other content addressable storage solutions: knowing the address of a file before it's uploaded.
Here’s what solc does by default when compiling any solidity contract:
computes the IPFS hash of the contract metadata JSON artifact
encodes the computed IPFS hash using CBOR encoding
appends the encoded bytes at the end of the regular compiled bytecode
This means that from any deployed contract, you can:
Get the contract bytecode using the standard RPC call eth_getCode
Decode the data at the end of the bytecode using a CBOR decoder
Extract the IPFS hash from the decoded data
Download the original contract metadata which contains source code, ABI, etc.
Since IPFS hashes are immutable, the contract metadata encoded this way is guaranteed to be correct and unmodified. This means that all contracts are auto-verifiable by design and without needing any third party!
So where’s the catch? Why is everybody still using centralized, closed source services to verify their contracts manually? The reason is that the compiler only computes the IPFS hash and encodes it, it does not actually upload anything to IPFS! This is where the thirdweb CLI comes in.
If you didn’t know already, thirdweb’s CLI is the swiss knife of web3 development. One of my favorites commands is npx thirdweb deploy
- it takes advantage of the solc contract metadata standard and makes deploying and integrating solidity contracts simpler and safer.
Here’s what happens when you run npx thirdweb deploy
on your solidity projects:
Detect your current project framework (hardhat, forge, truffle, etc)
Compile your contracts using your own project settings
After compilation, upload your contract metadata to IPFS, making sure it matches exactly the encoded IPFS hash in the compiled bytecode
Open up a web browser to fill in constructor parameters and deploy the contract without needing to hardcode private keys
By following the solidity contract metadata standard, contracts deployed using the thirdweb CLI are not only automatically verifiable, but also usable in any web3 app without worrying about copy pasting ABIs around!
The thirdweb stack allow you to load any contract just by its address, and get convenient and type safe wrappers for your contracts.
Here’s an example contract on Base that is not verified on any explorer, yet resolves just fine on the thirdweb dashboard just by looking at its bytecode:
You can also do this programmatically with the SDK:
import { prepareContractCall, resolveMethod, toWei } from "thirdweb";
const tx = prepareContractCall({
contract,
method: resolveMethod("mintTo"), // no abi needed!
params: ["0x123...", toWei("100")],
});
Under the hood, the resolvedMethod
will:
extract the contract metadata hash from the contract bytecode
download it from IPFS, extract the ABI and cache it
use this ABI to encode the transaction
This approach provides a much nicer dev experience, as well as the following advantages:
No need to embed ABIs in the source code means faster frontend startup times
Single source of truth means ABIs are always up to date
Works with any contract, on any EVM compatible chain
Since the solc contract metadata is an industry wide standard, it works with a variety of tools that also follow this standard! For example, contracts deployed with the thirdweb CLI are auto-verified on Sourcify, a decentralized contract verification service.
Powerful standards like these is what makes the web3 ecosystem magical, and this one deserves more love from the community!
Interested in more technical deep dives like these? Follow me on Twitter or join our community of web3 builders on Discord.