Self-verifiable contracts using solc and IPFS

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!

Background

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.

How solc encodes your contract’s metadata

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:

  1. computes the IPFS hash of the contract metadata JSON artifact

  2. encodes the computed IPFS hash using CBOR encoding

  3. appends the encoded bytes at the end of the regular compiled bytecode

How solc attaches contract metadata to the compiled bytecode
How solc attaches contract metadata to the compiled bytecode

Contract auto-verification by design

This means that from any deployed contract, you can:

  1. Get the contract bytecode using the standard RPC call eth_getCode

  2. Decode the data at the end of the bytecode using a CBOR decoder

  3. Extract the IPFS hash from the decoded data

  4. Download the original contract metadata which contains source code, ABI, etc.

How to retrieve contract metadata (ABI, sources, etc) only knowing its address
How to retrieve contract metadata (ABI, sources, etc) only knowing its address

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.

Deploying auto-verifiable contracts with thirdweb deploy

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:

  1. Detect your current project framework (hardhat, forge, truffle, etc)

  2. Compile your contracts using your own project settings

  3. After compilation, upload your contract metadata to IPFS, making sure it matches exactly the encoded IPFS hash in the compiled bytecode

  4. 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!

No ABI needed to interact with contracts

The thirdweb SDKs allow you to load any contract just by its address, and get convenient and type safe wrappers for your contracts.

const sdk = new ThirdwebSDK("goerli");
const contract = sdk.getContract("0x..."); // no ABI needed!
const nfts = await contract.erc721.getAll();

Under the hood, the thirdweb SDKs:

  1. extract the contract metadata hash from the contract bytecode

  2. download it from IPFS, extract the ABI and cache it

  3. generate a type safe API for the contract

This approach provides a much nicer dev experience, as well as the following advantages:

  1. No need to embed ABIs in the source code means faster frontend startup times

  2. Single source of truth means ABIs are always up to date

  3. 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. And of course, any contract verified on Sourcify can be used with the thirdweb SDK without needing its ABI.

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.

Subscribe to Joaquim Verges
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.