Etherscan is the biggest explorer in the Ethereum space. And one of its big features is the possibility to verify the source code of smart contracts. This allows users of smart contracts to understand what a contract is doing before actually sending any Eth to it. This increases trust in a smart contract, and benefits the developer of the contract as users will feel more comfortable using their smart contracts.

The main way smart contract developers can add their verified code on Etherscan is through the form on their website, but unfortunately this is a lot of manual work. You need to manually enter things like compiler version and constructor parameters, and you need to provide the contract source code in a flattened format that needs to exactly match the flattened deployed code.

A solution that some people use is to flatten their Truffle contracts using a command line tool and using the browser-based Remix IDE to deploy the flattened contract. Then they copy the same flattened code to the Etherscan verification form. This is a very cumbersome and manual process that should be automated.

This is exactly why I created truffle-plugin-verify, a Truffle plugin that can be used to automatically verify your Truffle contracts through the Etherscan API. The plugin is an Open Source project with automatic code flattening contributed by the developers at Ren Project. With this plugin you are able to verify your contracts with just a simple command:

truffle run verify ContractName

Prerequisites

For this guide we assume you already have a Truffle project with a deployment process set up. If you don't, you can refer to this official Truffle tutorial that shows how to set up deployment of Truffle projects with Infura.

Note: You can also check out the source code for this guide on GitHub.

The contract

If you've read any of my previous articles, you know that I'm a fan of using a simple Casino contract as an example. With this contract a player can bet ether on a number from 1 to 10. To make sure the contract does not go underwater, the player can only bet a small percentage of the contract's total balance. The winning number is generated as a modulo operation on the current block number, which is fine for testing, but can be easily abused in production.

In this guide, we will specifically split up the contract further so it's spread out over multiple files. This allows us to showcase the full functionality of the plugin.

contracts/Killable.sol

pragma solidity ^0.5.8;

contract Killable {
    address payable public owner;

    constructor() public {
        owner = msg.sender;
    }

    function kill() external {
        require(msg.sender == owner, "Only the owner can kill this contract");
        selfdestruct(owner);
    }
}

contracts/Casino.sol

pragma solidity ^0.5.8;

import "./Killable.sol";

contract Casino is Killable {
    event Play(address payable indexed player, uint256 betSize, uint8 betNumber, uint8 winningNumber);
    event Payout(address payable winner, uint256 payout);

    function fund() external payable {}

    function bet(uint8 number) external payable {
        require(msg.value <= getMaxBet(), "Bet amount can not exceed max bet size");
        require(msg.value > 0, "A bet should be placed");

        uint8 winningNumber = generateWinningNumber();
        emit Play(msg.sender, msg.value, number, winningNumber);

        if (number == winningNumber) {
            payout(msg.sender, msg.value * 10);
        }
    }

    function getMaxBet() public view returns (uint256) {
        return address(this).balance / 100;
    }

    function generateWinningNumber() internal view returns (uint8) {
        return uint8(block.number % 10 + 1); // Don't do this in production
    }

    function payout(address payable winner, uint256 amount) internal {
        assert(amount > 0);
        assert(amount <= address(this).balance);

        winner.transfer(amount);
        emit Payout(winner, amount);
    }
}

Verifying the contract

Now that we have our contract ready, we can show how simple it is to verify this contract with truffle-plugin-verify.

1. Install & enable truffle-plugin-verify

You can install the Truffle plugin using npm or yarn:

npm install truffle-plugin-verify
yarn add truffle-plugin-verify

When it is installed, you should add the following to your truffle-config.js or truffle.js file to enable the plugin with Truffle:

module.exports = {
  /* ... rest of truffle-config */

  plugins: [
    'truffle-plugin-verify'
  ]
}

2. Create an Etherscan API key and add it to Truffle

To create an Etherscan API key, you first need to create an account on the Etherscan website. After creating an account, you can add a new API key on your profile page, as seen in the image above.

After creating a new key, it should be added to truffle-config.js or truffle.js under api_keys:

module.exports = {
  /* ... rest of truffle-config */

  api_keys: {
    etherscan: 'MY_API_KEY'
  }
}

Of course you shouldn't commit this API key to your Git repository, so I suggest using dotenv to store the API key in a gitignored .env file and read it from there.

After following these steps, your full config file should look like this:

var HDWalletProvider = require("truffle-hdwallet-provider");
require('dotenv').config();

module.exports = {
  networks: {
    rinkeby: {
      provider: function() {
        return new HDWalletProvider(`${process.env.MNEMONIC}`, `https://rinkeby.infura.io/v3/${process.env.INFURA_ID}`)
      },
      network_id: 4
    }
  },
  plugins: [
    'truffle-plugin-verify'
  ],
  api_keys: {
    etherscan: process.env.ETHERSCAN_API_KEY
  }
};

Your specific config file might be different, but as long as you have a public network deployment set up, and your plugins and api_keys lists are set correctly, you should be good to go.

3. Deploy & verify the contract

Now that everything is set up to use truffle-plugin-verify, the only thing left is to actually deploy and verify the smart contract.

truffle migrate --network rinkeby

This should take some time, and will show information about the deployment, finally displaying something similar to this:

Summary
=======
> Total deployments:   2
> Final cost:          0.0146786 ETH

With the contract deployed we can use truffle-plugin-verify to run the Etherscan verification of our Casino contract:

truffle run verify Casino --network rinkeby

This will again take some time, and eventually return:

Pass - Verified

Conclusion

We've discussed how cumbersome Etherscan verification can be when doing it through their online form, as there are several manual steps to go through every time you deploy a contract. In this article we have shown that truffle-plugin-verify offers a simple and automatic replacement for the manual verification process. It is easy to install, and can be used to verify any smart contract with just one easy command.


If you found this guide useful and wish to use truffle-plugin-verify inside your own projects, check it out on npm or GitHub. If you enjoyed using the plugin or if you have any suggestions, let me know in the comment section below. And don't forget to share this with your network on Facebook, Twitter and LinkedIn.