Skip to content

forge verify-contract --flatten produces different flattened code than forge flatten command #11754

@0xLaz3r

Description

@0xLaz3r

Component

Forge

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

  • Foundry
  • Foundryup

What version of Foundry are you on?

1.3.5-stable

What version of Foundryup are you on?

0.3.3

What command(s) is the bug in?

forge flatten / forge verify-contract --flatten

Operating System

macOS (Apple Silicon)

Describe the bug

The forge verify-contract --flatten command produces different flattened source code compared to the standalone forge flatten command. This inconsistency causes verification failures on Etherscan because the bytecode generated from the two different flattened versions doesn't match.

Specific Differences Found:

  1. SPDX License Identifier Placement:
  • forge flatten: Places SPDX license at the very top of the file (line 1).
  • forge verify-contract --flatten: Places SPDX license after the first file's content.
  1. Interface Name Handling:
  • forge flatten: Adds suffixes to disambiguate duplicate interface names (e.g., IContract_0, IContract_1)
  • forge verify-contract --flatten: Creates interfaces without suffixes (e.g., IContract)

Impact:

  • Verification failures on Etherscan due to bytecode mismatch
  • Inconsistent behavior between two commands that should produce identical output
  • Developers cannot rely on forge flatten output to match what gets sent for verification

Reproduction Steps:

  1. Create a project with multiple files containing duplicate interface names
  2. Run forge flatten src/Contract.sol --output flat.sol
  3. Run forge verify-contract --flatten --skip-is-verified-check <address> src/Contract.sol:Contract. To capture the source, you can create a fake local verifier server.
  4. Compare the two outputs - they will differ in SPDX placement and interface naming

Expected Behavior:

Both commands should produce identical flattened source code, ensuring that local flattening matches what gets sent for verification.

Evidence:

  • File size difference
  • Different checksums
  • Interface naming differences cause different bytecode generation

This bug makes contract verification unreliable and forces developers to use workarounds or manual verification processes.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions