Verify Your Contracts On Etherscan 100% Of The Time

It is a well known fact that the hardest part of being a solidity developer is verifying your deployed contracts on etherscan. (See here, here, here, and here)

As a defi veteran (8 months and counting), I've had countless nightmarish encounters with verifying contracts on etherscan. Now that I've emerged victorious from the battle field, I would like to share my experiences, and a new tool made by my good friend hjubb on verifying your contracts on etherscan, 100% of the time, 99.99% of the time.

Why Does it Fail?

One of the most common verification methods is to flatten your contracts after compilation and deployment and verify the flatten contracts.

This works on simple contracts, but on more complicated contracts where pragma experimental ABIEncoderV2 is being used, the location and presence of that declaration changes the output bytecode significantly. This is demonstrated here.

More concretely, if:

  1. You have 2 files: A.sol, and B.sol
  2. If A.sol contains ABIEncoderV2 and was compiled with standard frameworks, B.sol's generated bytecode will be compiled without ABIEncoderV2.
  3. However, if A.sol and B.sol were to be flatten, ABIEncoderV2 will be present in both files, resulting in a different bytecode.

There are also other suspects, such as truffle compiling contracts with absolute filepaths, resulting in a different swarmhash when compiled on a different machine (etherscan has however stated that it shouldn't affect anything).

Standard JSON

Fortunately, there is another format the etherscan verification process supports – the standard json format.

It looks something like:

{
  "language": "Solidity",
  "sources": {
    "contracts/ContractA.sol": {
      "content": "<SOURCE_CODE A>"
    },
    "contracts/ContractB.sol": {
      "content": "<SOURCE_CODE B>"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    }
  }
}

This input format allows us to verify contracts that spans across multiple files without needing to flatten them.

Enter – solc-sjw

solc-sjw stands for solc-standard-json-writer. It is a static binary written in Kotlin-Native (tm) that helps you format your solidity contracts into the standard input format. Its written by my good friend hjubb, and you can find the source code here.

Installation

Linux

wget https://github.com/hjubb/solc-sjw/releases/download/v0.2.0/solc-sjw-linux-x64 -O ~/.local/bin/solc-sjw
chmod +x ~/.local/bin/solc-sjw

Mac

Note that I'm not familiar with Mac, so you might have to change the static binary location to somewhere in your $PATH

wget https://github.com/hjubb/solc-sjw/releases/download/v0.2.0/solc-sjw-mac.kexe -O ~/.local/bin/solc-sjw
chmod +x ~/.local/bin/solc-sjw

Usage Example

In this example, we'll walk through an example on how to generate a standard input json format, and verify it on etherscan.

  1. Generate your standard-input json. We'll be using yearn's protocol in this example.
git clone https://github.com/iearn-finance/yearn-protocol.git
cd yearn-protocol
solc-sjw --dir contracts

# A new file called solc-input.json should be present in the current working directory
  1. Go to deployed contract's location on etherscan and select Solidity: Standard-Json-Input as the verification method.

  1. Follow the process and upload the generated solc-input.json click, click, click…

And it should be verified now.

Conclusion

Tl;dr: standard json good.

Have fun verifying!