Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extending hardhat-etherscan to support multiple API keys #1448

Closed
wschwab opened this issue May 9, 2021 · 15 comments
Closed

Extending hardhat-etherscan to support multiple API keys #1448

wschwab opened this issue May 9, 2021 · 15 comments
Assignees
Labels
type:feature Feature request

Comments

@wschwab
Copy link

wschwab commented May 9, 2021

Extending hardhat-etherscan to support multiple API keys

Summary:

The hardhat-etherscan plugin currently provides an interface to provide one API key for auto-verification. In the current ecosystem there is a need for being able to support multiple API keys. This feature request looks at how hardhat-etherscan works now, and outlines potential solutions.

Current structure of hardhat-etherscan

The hardhat-etherscan enables auto-verification via an etherscan object in hardhat.config:

module.exports = {
  networks: {
    mainnet: { ... }
  },
  etherscan: {
    // Your API key for Etherscan
    // Obtain one at https://etherscan.io/
    apiKey: "YOUR_ETHERSCAN_API_KEY"
  }
};

(code taken from docs for hardhat-etherscan)

Problems

In today's ecosystem, Etherscan has spun off block explorers for popular sidechains such as BSC (BSCScan) and Fantom (FTMScan), making the naming convention of the plugin itself slightly misleading. This recommends renaming in future versions to hardhat-verification. If Blockscout explorers become available, this will be doubly true.

In addition, calling the object in the config etherscan has the same concern.

Neither of these are meant to be the primary issue, though. The larger issue is that the etherscan object can only hold one API key at a time (via etherscan.apiKey). It would be valuable for projects deploying in multiple ecosystems to support multiple API keys.

Proposed Solutions

1. Long-term proposal

In the long term we would like to recommend renaming the plugin to hardhat-verification, and replacing the etherscan object in the config with explorerApiKeys, with the key being the name of a supported block explorer, something akin to:

module.exports = {
  networks: {
    mainnet: { ... }
  },
  explorerApiKeys: {
    etherscan: "YOUR_ETHERSCAN_API_KEY",
    bscScan: "YOUR_BSCSCAN_API_KEY",
    ftmScan: "YOUR_FTMSCAN_API_KEY",
  }
};

Renaming the plugin and the object has the added benefit of backwards compatability - the hardhat-etherscan and corresponding etherscan object could remain supported without conflict.

This could in turn involve code on the backend matching block explorers with chainIds, so that Hardhat knows, for example, to match a chainId of 56 with Binance Smart Chain. (This would likely mean giving the key values of block explorers, as in the example above). Alternatively, the name of the key could be matched with networks provided in the networks object (in which case, instead of the keys above, they would carry the same name as the networks, for example bsc or fantom). This would likely be an inferior option, as it would require pasting the same key multiple times in order to cover testnets. (Especially in the case of Ethereum/Etherscan, it could require separate mainnet, Ropsten, Rinkeby, Kovan, and Goerli keys, even though all work with the same Etherscan API key.)

2. Short-term proposal

The most urgent item imho is supporting multiple API keys. Without introducing a new name and new structure, the current hardhat-etherscan plugin could be extended to support multiple keys by introducing an additionalNetworks object into the etherscan object:

module.exports = {
  networks: {
    mainnet: { ... },
    bsc: { ... }.
    fantom: { ... },
  },
  etherscan: {
    apiKey: "YOUR_ETHERSCAN_API_KEY",
    additionalNetworks: {
          bsc: "YOUR_BSCSCAN_API_KEY",
          fantom: "YOUR_FTMSCAN_API_KEY",
    }
  }
};

Here the keys in additionalNetworks could be matched to the names of provided networks. This would require providing the same key for, say, BSC's main and test networks, as mentioned above, but does not have the same overhead as Etherscan (also mentioned above), and might be acceptable.

Closing

This doesn't include the particulars of implementing any of the ideas here. I also don't intend for the suggested naming conventions and structures to be written in stone - there very well may be better ways to name or structure this. I'd be happy to work on a potential PR for this.

Thanks for taking the time to read this, and I'm looking forward to the feedback!

@iangregsondev
Copy link

iangregsondev commented Jul 11, 2021

I was about to write an issue. You nailed it. 100% should need to support multiple api-keys on different networks.

The only thing I would say is it could take the same format as "networks", i.e.

module.exports = {
  networks: {
    eth_mainnet: { ... },
    bsc_testnet: { ... },
    ...... etc
  },
  verify: {
    eth_mainnet: { ... },
    bsc_testnet: { 
       "api-key": "blalblalbla"
     },
    ...... etc
  },

then you could do a

hardhat etherscan-verify --network bsc_testnet

I agree that calling it etherscan works, but it would be way better to support .. I don't know

hardhat explorer-verify --network bsc_testnet

or

hardhat verify --network bsc_testnet

Cheers.

@frangio
Copy link
Contributor

frangio commented Nov 19, 2021

Is there a good workaround for this?

@Synvox
Copy link

Synvox commented Dec 3, 2021

@frangio I was able to work around this by adding the chainId to hardhat.config.js:

module.exports = {
  networks: {
    mumbai: {
      chainId: 80001, // <- add this
      url: MUMBAI_API_URL,
    },
  },
};

With the chainId property, hardhat will correctly select the mumbai network. See here.

After adding chainId you can run npx hardhat verify --network mumbai [contract_address] without issues. Doesn't solve the multiple api key problem, but I couldn't verify my deployed contract without it. 🤷

kanej added a commit that referenced this issue Dec 3, 2021
The config has been extended to allow both a string as api key or an object that can contain multiple api keys, keyed by network.

Relates to #1448.
@kanej kanej self-assigned this Dec 3, 2021
@kanej kanej mentioned this issue Dec 6, 2021
7 tasks
kanej added a commit that referenced this issue Dec 7, 2021
The config has been extended to allow both a string as api key or an object that can contain multiple api keys, keyed by chain.

Relates to #1448.
kanej added a commit that referenced this issue Dec 7, 2021
The config has been extended to allow both a string as api key or an object that can contain multiple api keys, keyed by chain.

Relates to #1448.
@kanej kanej linked a pull request Dec 8, 2021 that will close this issue
7 tasks
@wschwab
Copy link
Author

wschwab commented Dec 8, 2021

lol, it looks like Hardhat literally opened a PR as I was working on a hacky solution, but I figured I'd put it here just because

I realized you could get around a bunch of this by having apiKey run a function:

etherscan: {
    apiKey: getApiKey()
  },

and then use process.env.HARDHAT_NETWORK to figure it out (this assumes you're storing your API keys in a .env file:

const getApiKey = () => {
  switch (process.env.HARDHAT_NETWORK) {
    case "mainnet" || "rinkeby" || "goerli" || "ropsten":
      return process.env.ETHERSCAN_API_KEY;
    case "polygon" || "mumbai":
      return process.env.POLYGONSCAN_API_KEY;
    case "fantom" || "fantom_testnet":
      return process.env.FTMSCAN_API_KEY;
    default:
      return "";
  }
}

I haven't tested this out yet, so please let me know if this doesn't work like I think it does, but it seems valid. ofc, HH looks like they're working on something jucier, looking forward!

@kanej kanej removed a link to a pull request Dec 15, 2021
7 tasks
@pandurand
Copy link

I haven't tested this out yet, so please let me know if this doesn't work like I think it does, but it seems valid. ofc, HH looks like they're working on something jucier, looking forward!

@wschwab almost correct but does not respect the fall-through technique for multi-criteria. Here's a proper fix:

const getApiKey = () =>
  switch (process.env.HARDHAT_NETWORK) {
    case "mainnet":
    case "rinkeby":
    case "goerli":
    case "ropsten":
      return process.env.ETHERSCAN_API_KEY;
    case "polygon":
    case "mumbai":
      return process.env.POLYGONSCAN_API_KEY;
    default:
      return "";
  }
}

Another solution, since you'd use the same apiKey for multiple networks would be to create 2 hardhad.config.js files: one for ethereum and one for polygon, with the appropriate environment variable uses, and specify which file to use when running hardhat.

@frangio
Copy link
Contributor

frangio commented Dec 18, 2021

If Blockscout explorers become available, this will be doubly true.

Blockscout has just merged an (apparently) Etherscan-compatible API for verification: blockscout/blockscout#4908

@fvictorio
Copy link
Member

This feature was (finally!) added in @nomiclabs/hardhat-etherscan@3.0.0. Notice that this is a new major version, so you need to upgrade the package accordingly.

Check the release notes to learn more, or read this section of the docs.

@dohomi
Copy link

dohomi commented Jan 23, 2022

@fvictorio I checked out the feature but it does not seem to work for polygonMumbai:

  etherscan: {
    apiKey: {
      mainnet: process.env.ETHERSCAN_API_KEY,
      rinkeby: process.env.ETHERSCAN_API_KEY,
      polygon: process.env.POLYGON_API_KEY,
      polygonMumbai: process.env.POLYGON_API_KEY,
    },
  }

This is my config but if I select the network of polygonMumbai I still receive following error:

error occured NomicLabsHardhatPluginError: Invalid API Key
    at verifyContract (/hardhat/node_modules/@nomiclabs/hardhat-etherscan/src/etherscan/EtherscanService.ts:68:11)

UPDATE

everything works as expected! Upgraded, removed node_modules and after cleaned install everything worked.

@villarode
Copy link

Should not this be just mumbai, not polygonMumbai in your construction:

etherscan: {
apiKey: {
mainnet: process.env.ETHERSCAN_API_KEY,
rinkeby: process.env.ETHERSCAN_API_KEY,
polygon: process.env.POLYGON_API_KEY,
mumbai: process.env.POLYGON_API_KEY,
},
}

@villarode
Copy link

This feature was (finally!) added in @nomiclabs/hardhat-etherscan@3.0.0. Notice that this is a new major version, so you need to upgrade the package accordingly.

Check the release notes to learn more, or read this section of the docs.

Are you meaning you absoluely need to upgrade to @nomiclabs/hardhat-etherscan@3.0.0 to let your multiple apiKey construction to work? I woulf not work on lowere versions of nomiclabs?

@villarode
Copy link

Should not this be just mumbai, not polygonMumbai in your construction:

etherscan: { apiKey: { mainnet: process.env.ETHERSCAN_API_KEY, rinkeby: process.env.ETHERSCAN_API_KEY, polygon: process.env.POLYGON_API_KEY, mumbai: process.env.POLYGON_API_KEY, }, }

I take it back, it should be exactly polygonMumbai:

mumbai: {
url: MUMBAI_URL,
chainID: 80001,
accounts: [PRIVATE_KEY]
}
},
/////etherscan: {
/////apiKey: ETHERSCAN_API
///// apiKey: POLYGONSCAN_API
/////}

etherscan: {
apiKey: {
mainnet: process.env.ETHERSCAN_API,
rinkeby: process.env.ETHERSCAN_API,
polygon: process.env.POLYGONSCAN_API,
polygonMumbai: process.env.POLYGONSCAN_API,
},
}

@kanej
Copy link
Member

kanej commented Feb 6, 2022

@villarode yes you need to upgrade to version 3.0.0 to take advantage of multiple api keys.

@villarode
Copy link

villarode commented Feb 17, 2022 via email

@magnetto90
Copy link

What about using custom networks? How can I verify in multiple custom networks at the same time?

@fvictorio
Copy link
Member

@ESNJS how to use custom networks is explained in the readme.

Verifying in multiple networks at the same time is not supported at the moment. Feel free to open a new issue with that feature request.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
type:feature Feature request
Projects
None yet
Development

No branches or pull requests