foundry-rs / foundry

Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.
https://getfoundry.sh
Apache License 2.0
8.1k stars 1.67k forks source link

Etherscan verification fails for complex directory structure #4060

Open haydenshively opened 1 year ago

haydenshively commented 1 year ago

Component

Forge

Have you ensured that all of these are up to date?

What version of Foundry are you on?

forge 0.2.0 (a44aa13 2023-01-09T00:10:29.992832Z)

What command(s) is the bug in?

forge script --broadcast --verify

Operating System

macOS (Apple Silicon)

Describe the bug

I've created a simple repo to reproduce the issue here. I've got a non-standard repository structure. It works perfectly for every command I've tried, with this one exception: Etherscan verification fails for any periphery contract that depends on files nested inside of core/src. i.e., it's fine for periphery/src/MyHelper.sol to import core/src/MyContract.sol, but if core/MyContract.sol imports something from core/src/<any-other-directory>/<any-other-file.sol>, verification fails (see error below).

Interestingly, the output build json for periphery/src/MyHelper.sol does list core/src/<any-other-directory>/<any-other-file.sol> as a source. For some reason it's just not being uploaded to Etherscan.

Submitted contract for verification:
        Response: `OK`
        GUID: `bjzmvh3dmrwgi3r5aizqkhwytv6psxefyzfvekppi84y5hynsp`
        URL:
        https://api-goerli.etherscan.io/apiaddress/0xddcfbbe2c2fbf750c472d354fc08e8d98f01651e
Contract verification status:
Response: `NOTOK`
Details: `Pending in queue`
Contract verification status:
Response: `NOTOK`
Details: `Fail - Unable to verify. Solidity Compilation Error: Source "lib/core/src/libraries/Foo.sol" not found: File not found. Searched the following locations: "".`
Contract failed to verify.
Fiddlekins commented 1 year ago

We've run into this same issue now too, trying to run forge verify-contract. (version: forge 0.2.0 (7398b65 2023-03-29T00:20:50.782162Z))

Response: `NOTOK`
Details: `Fail - Unable to verify. Solidity Compilation Error: Source "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol" not found: File not found. Searched the following locations: "".`
Contract failed to verify.

We looked into it a bit and can provide some more insight into what the surface level cause is.

We output the JSON payload to examine (using the --show-standard-json-input flag) and get the following: verification-json

The project's top level remappings.txt actually only contains the following:

@openzeppelin-contracts=lib/openzeppelin-contracts/contracts

This corresponds to the payload's settings.remappings[1], with the settings.remappings[0] entry coming from the mock-contracts dependency which also uses the OZ lib.

Checking the contents of the values listed in the payloads sources map we see the imports are in their original form

import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol";

It's not clear to me why etherscan would resolve that using settings.remappings[1] before settings.remappings[0], but nevertheless it does so, trying to find lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol only to return an error because there's no corresponding entry in the sources map.

We briefly experimented with manually modifying and submitting the payload JSON, such that we duplicated the lib/mock-contracts/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol entry and renamed the key to lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol. This resolved the missing file error, instead failing because the final bytecode didn't match due to the OZ lib version being different between the top level dep and the dep's dep.

To summarise, forge seems to be incorrectly de-duping dependencies based on either file or contract name, when it should be using their filepath instead.

davidbrai commented 1 year ago

I've had a similar issue, what worked as a temporary fix is applying the following change to my foundry.toml:

[profile.default]
 src = 'contracts'
-libs = ['lib', '../../node_modules']
+libs = ['lib', '/full-path-to-project/my-monorepo/node_modules']
ryanio commented 1 year ago

+1 i am also having the same issue as @Fiddlekins

ryanio commented 1 year ago

Adding auto_detect_remappings = false to foundry.toml fixed this issue for me!

Evalir commented 1 year ago

So, this is expected behavior regarding ambiguous paths: https://book.getfoundry.sh/forge/deploying?highlight=verify-contra#known-issues ; sadly etherscan only really handle relative paths. @ryanio 's fix works!

ShubhSensei commented 1 year ago

May I work on this issue, if it's still there?

charlescrain commented 1 year ago

Adding auto_detect_remappings = false to foundry.toml fixed this issue for me!

This worked for me. No idea why it fixes it but adding a foundry.toml like this:

[profile.default]
 auto_detect_remappings = false

caused it to work.

DJViau commented 11 months ago

I spent some time running forge remappings with auto_detect_remappings = true and auto_detect_remappings = false and comparing the two outputs against the file Etherscan complained about,but for me, leaving auto_detect_remappings = false and explicitly adding a remapping from a submodule to my top level foundry.toml did the job.