Compiled bytecode differs depending on unrelated contracts - cannot verify contract

Hi people,

I've been reading as much around this as possible, but cannot verify a contract which relies on openzeppelin imports, because the compiled bytecode differs from the deployed bytecode.

All compiled and deployed with hardhat, solc 0.8.0

1: a contract was compiled and deployed to rinkeby and mainnet, while there were other contracts (i.e. a backup version of the main contract) in the same project.
2: I did not verify the contract immediately (silly I know)
3: some small changes are made to the non-dependent files in the same project (i.e. backup .sol files are renamed and replaced with the deployed contract)
4: Trying to verify the deployed contract some days later fails (following @abcoathup 's tutorial using hardhat-etherscan, and via direct verification on etherscan with flattened contract)

I have read and used this guide (thanks for writing it!)

I have tried directly verifying on etherscan, with a flattened contract (manually copied all dependencies into the same Contract.sol)

I have tried the hardhat-etherscan method:
npx hardhat verify --network network contractAddress constructorArgs)

In all attempts I get the same error:

"Error in plugin @nomiclabs/hardhat-etherscan: The address provided as argument contains a contract, but its bytecode doesn't match any of your local contracts.

Possible causes are:
  - Contract code changed after the deployment was executed. This includes code for seemingly unrelated contracts.
  - A solidity file was added, moved, deleted or renamed after the deployment was executed. This includes files for seemingly unrelated contracts.
  - Solidity compiler settings were modified after the deployment was executed (like the optimizer, target EVM, etc.).
  - The given address is wrong.
  - The selected network (mainnet) is wrong."

Or from etherscan:
unable to find a matching bytecode

So my question is: does the state of the project directory at compile/deployment (i.e. the existence of other .sol files) affect the deployed bytecode for a contract?

If so, is it impossible to reproduce the same bytecode for verification if the non-dependent file structure or non-dependent file names have changed?

I'm beginning to tear my hair out over this one - any help would be really appreciated!

Thanks everyone :grinning:

It actually can affect the bytecode but in a way that Etherscan (and Hardhat) know to ignore.

I don't understand from your post, what method did you use the deploy the contract initially?

2 Likes

Thanks @frangio
I deployed with hardhat-ethers via a .js script in the command line:
npx hardhat run ./scripts/deploy.js --network mainnet

// ./scripts/deploy.js 

async function main() {
	const Contract = await ethers.getContractFactory("MyContract");
	const contract = await Contract.deploy(constructorArg);

...subsequent changes to other .sol files in the same project...

then have been attempting verification with hardhat-etherscan:
npx hardhat verify --network mainnet <contract address> <constructorArg>

Do you have any ideas? I am CERTAIN the contract has not been modified since deployment. Confirmed with version control rollbacks etc.

Issues https://github.com/ethereum/solidity/issues/9573
and https://github.com/nomiclabs/hardhat/issues/804
are similar, but are considered fixed by solc 0.7.0...

Thanks for your help! :+1:

Are you also sure that the compilation configuration (e.g. optimizer) hasn't changed? Are you sure you're providing constructor arguments correctly?

1 Like

Thanks - optimizer was left to default, so ought to be the same for deployment compilation and verification. I've just tried again with {optimizer: true, runs: 200} and get the same result.
Constructor arguments are the same - this part of the bytecode actually matches :sweat_smile:

Any other ideas? I'm starting to lean towards redeployment and this being a LESSON. But would rather exhaust every possibility before doing that!

No more ideas, sorry.

1 Like

No worries mate, thank you for helping!

Do you have the contract metadata from the original deployment? It should be possible to track down the thing that's different by comparing it with the metadata you are getting now. If the compiler options are different or some specific file changed, you'll see it there. And if the metadata is identical, you should be getting identical bytecode.

It's probably obvious but I'll ask just in case: are you using the same exact compiler release? The bytecode produced by 0.8.0 is not guaranteed to be the same as from another 0.8.x release. They're only compatible at the source code level.

Finally, do you explicitly set the EVM version? If not and the tools you are using are automatically setting it to the latest version (rather than relying on compiler's default), and you happened to deploy just before the recent London hard fork, you might be getting different bytecode after it.

1 Like

Thank you very much for your reply - I ended up re-deploying and verifying immediately afterwards :sweat_smile:

The compiler was the same version, but I did not set the EVM version - that may have been it.

I'm happy to move on and chalk this up as a lesson in version control...