Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9a7fb81
adding changess
sfyll Feb 10, 2025
9ec8117
parsing EVM version
sfyll Feb 10, 2025
b49fe71
default version
sfyll Feb 10, 2025
b27a743
adding mercury
sfyll Feb 10, 2025
5fc38a5
cargo fmt --all
sfyll Feb 10, 2025
b1cf865
cargo clippy
sfyll Feb 10, 2025
bea806c
add @syfll as codeowner (#3)
cdrappi Feb 10, 2025
e9b6b13
Update README.md (#4)
sfyll Feb 10, 2025
38153cc
CI: add seismic.yml (#5)
cdrappi Feb 10, 2025
352264d
update cargo (#6)
sfyll Feb 11, 2025
b956ec3
Cargo.toml: update repo & homepage (#7)
cdrappi Feb 11, 2025
e4c30b8
add link to seismic revm's readme (#8)
cdrappi Feb 11, 2025
dcf3fab
doesnt build
cdrappi May 23, 2025
6c9c7cd
it does build
cdrappi May 23, 2025
5869868
cargo fmt; dont import mercury, instead use absolute path
cdrappi May 23, 2025
cde8c42
alloy 1
cdrappi May 23, 2025
02aa3bf
fixed solar patch
ssolit Jun 20, 2025
54a4eeb
Upstream merge: Alloy 1 (#11)
cdrappi Jun 30, 2025
51ca0d2
upstream merge through commit 0a1c495 (0.19.1)
cdrappi Sep 12, 2025
ed3a17a
codeowners
cdrappi Sep 12, 2025
067a38b
rustfmt
cdrappi Sep 12, 2025
f699299
accept all of our changes
cdrappi Sep 30, 2025
5477a89
upstream merge through commit 0a1c495 (0.19.1) (#12)
cdrappi Sep 30, 2025
fd5f73f
Add CLAUDE.md project reference (#13)
mHaines9219 Feb 17, 2026
d24431f
feat: add format_version_with_commit() for foundry to print ssolc ver…
samlaf Feb 19, 2026
5a398ff
fix: mercury versioning (#15)
samlaf Feb 20, 2026
bbb38d7
docs: cleanup readme + add some comments to code (#16)
samlaf Feb 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1 +1 @@
* @danipopes @klkvr @mattsse @grandizzy @yash-atreya @zerosnacks @onbjerg @0xrusowsky
* @cdrappi
62 changes: 62 additions & 0 deletions .github/workflows/seismic.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Seismic CI

on:
push:
branches: [ seismic ]
pull_request:
branches: [ seismic ]

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always
CARGO_NET_GIT_FETCH_WITH_CLI: true

jobs:
rustfmt:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
with:
components: rustfmt
- run: cargo fmt --all --check

build:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
shared-key: "build-cache"
- name: cargo build
run: cargo build

warnings:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
shared-key: "warnings-cache"
- name: cargo check warnings
run: RUSTFLAGS="-D warnings" cargo check

test:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
shared-key: "test-cache"
- name: cargo test
run: cargo test
112 changes: 112 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Seismic Foundry Compilers

Fork of [Foundry Compilers](https://github.com/foundry-rs/compilers) (the compilation backend for [Foundry](https://github.com/foundry-rs/foundry)) with **Seismic Mercury specification** enabled. Upstream is tracked through the `main` branch.

## What This Does

Foundry Compilers provides Solidity and Vyper compilation, caching, dependency resolution, and artifact handling for the Foundry toolchain. Seismic's fork adds the **Mercury EVM version** — when the Solc version is >= 0.8.31, all EVM version normalization resolves to `Mercury`, which enables confidential storage opcodes (`CSTORE`/`CLOAD`) on Seismic's chain. The change is minimal: a constant, a new enum variant, and normalization logic.

## Build

Rust workspace with 5 crates. MSRV: **1.88**.

### macOS

```bash
# Install Rust (if needed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Build
cargo build

# Build with all features (async, svm-solc, project-util)
cargo build --all-features
```

### Linux (Ubuntu)

```bash
# Dependencies
sudo apt-get update
sudo apt-get install -y build-essential pkg-config libssl-dev

# Install Rust (if needed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Build
cargo build

# Build with all features
cargo build --all-features
```

## Test

```bash
# Run all unit + doc tests (default features)
cargo test

# Check for warnings (CI does this)
RUSTFLAGS="-D warnings" cargo check
```

### Integration tests (require `full` + `project-util` features and network access for svm)

```bash
cargo test --all-features
```

## Code Style

- **Formatter**: `cargo +nightly fmt --all` (nightly required — see `rustfmt.toml` for settings)
- **Linter**: `cargo clippy --all-features` — warnings-as-errors in CI
- **Commit convention**: [Conventional Commits](https://www.conventionalcommits.org/) — `type(scope): message`

Key clippy lints (workspace-level):

- `dbg-macro`, `uninlined-format-args`, `use-self`, `redundant-clone` = warn
- `result-large-err`, `large-enum-variant` = allow

## Key Seismic Modifications

Files changed from upstream:

- **`crates/artifacts/solc/src/lib.rs`** — `Mercury` variant in `EvmVersion` enum, set as `#[default]`; normalization returns `Mercury` for solc >= 0.8.28; serializes as `"mercury"`; test cases validating behavior
- **`crates/core/src/utils/mod.rs`** — `MERCURY_SOLC` constant (`Version::new(0, 8, 28)`)
- **`crates/compilers/src/cache/iface.rs`** — `.1` → `.data` field access for `FlaggedStorage`
- **`crates/compilers/src/resolver/parse.rs`** — `.1` → `.data` field access for `FlaggedStorage`
- **`crates/compilers/src/compilers/vyper/parser.rs`** — `#[allow(deprecated)]` annotation
- **`Cargo.toml`** — metadata (authors, repo, homepage, description)
- **`README.md`** — fork preamble with link to upstream and PR diff
- **`.github/workflows/seismic.yml`** — Seismic CI workflow (new file)

## Feature Flags

| Feature | Description |
| -------------------- | ------------------------------------ |
| `default` | Enables `rustls` |
| `full` | `async` + `svm-solc` |
| `async` | Async methods via `tokio` |
| `svm-solc` | Auto-manage `solc` via `svm` |
| `project-util` | Temp project utilities for testing |
| `rustls` / `openssl` | TLS backend for `svm` downloads |

## CI

GitHub Actions (`.github/workflows/`):

- **seismic.yml** (seismic branch): 4 jobs — `rustfmt` (nightly fmt check), `build` (cargo build), `warnings` (`RUSTFLAGS="-D warnings" cargo check`), `test` (cargo test). Runs on push/PR to `seismic`.
- **ci.yml**: upstream-only, runs on `main` branch — not used by Seismic.

## Branches

- `seismic` — production branch (PR target)
- `main` — upstream-only tracking branch

## Troubleshooting

| Problem | Fix |
| --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `cargo fmt` warnings about unstable features | Expected on stable toolchain. CI uses nightly: `cargo +nightly fmt --all`. Install with `rustup toolchain install nightly`. |
| Integration tests don't run with `cargo test` | They require features: `cargo test --all-features`. The `project` and `mocked` tests need `full`, `project-util`, and `test-utils`. |
| `RUSTFLAGS="-D warnings"` fails on new code | This is the CI standard. Fix all warnings before pushing. |
10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ members = ["crates/artifacts/*", "crates/core", "crates/compilers"]
resolver = "2"

[workspace.package]
authors = ["Foundry Maintainers"]
authors = ["Foundry Maintainers", "Seismic Systems"]
version = "0.19.1"
rust-version = "1.88"
readme = "README.md"
license = "MIT OR Apache-2.0"
repository = "https://github.com/foundry-rs/compilers"
homepage = "https://github.com/foundry-rs/compilers"
repository = "https://github.com/SeismicSystems/seismic-compilers"
homepage = "https://github.com/SeismicSystems/seismic-compilers"
documentation = "https://docs.rs/foundry-compilers"
description = "Utilities for working with EVM language compilers"
keywords = ["foundry", "solidity", "solc", "ethereum", "ethers"]
description = "Utilities for working with SEVM language compilers"
keywords = ["foundry", "solidity", "solc", "ethereum", "ethers", "seismic"]
edition = "2021"
exclude = [".github/", "scripts/", "test-data/"]

Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
# Seismic Foundry Compilers

This repository contains Seismic's fork of Foundry Compilers.

## Main changes

Super minimal:
- Added the Seismic Mercury [Specification](https://github.com/SeismicSystems/seismic-revm?tab=readme-ov-file#mercury-specification--seismics-revm) to the EvmVersion enum.
- This is only used by foundry so that different versions can be specified/requests, and these are serialized and passed on to [ssolc](https://github.com/SeismicSystems/seismic-solidity). Currently our seismic-solidity fork is very minimal and only supports the Mercury spec so this feels overkill, but the structure is relatively easy to maintain and it will be useful in the future.
- Added the ssolc commit version to the printed output used by foundry. Given that ssolc doesn't currently adhere and support multiple semvers, it is important for debugging to know exactly which compiler build foundry is using to compile contracts.

## Structure

The upstream repository lives [here](https://github.com/foundry-rs/compilers). This fork is up-to-date with it through commit `8c5683d`. You can see this by viewing the [main](https://github.com/SeismicSystems/seismic-compilers/tree/main) branch on this repository. You can view all of our changes vs. upstream on this [here](https://github.com/SeismicSystems/seismic-compilers/compare/main...seismic).

Seismic's forks of the [reth](https://github.com/paradigmxyz/reth) stack all have the same branch structure:
- `main` or `master`: this branch only consists of commits from the upstream repository. However it will rarely be up-to-date with upstream. The latest commit from this branch reflects how recently Seismic has merged in upstream commits to the seismic branch
- `seismic`: the default and production branch for these repositories. This includes all Seismic-specific code essential to make our network run


# Foundry Compilers

| [Docs](https://docs.rs/foundry-compilers/latest/foundry_compilers/) |
Expand Down
22 changes: 17 additions & 5 deletions crates/artifacts/solc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ use foundry_compilers_core::{
error::SolcError,
utils::{
strip_prefix_owned, BERLIN_SOLC, BYZANTIUM_SOLC, CANCUN_SOLC, CONSTANTINOPLE_SOLC,
ISTANBUL_SOLC, LONDON_SOLC, OSAKA_SOLC, PARIS_SOLC, PETERSBURG_SOLC, PRAGUE_SOLC,
SHANGHAI_SOLC,
ISTANBUL_SOLC, LONDON_SOLC, MERCURY_SOLC, OSAKA_SOLC, PARIS_SOLC, PETERSBURG_SOLC,
PRAGUE_SOLC, SHANGHAI_SOLC,
},
};
pub use serde_helpers::{deserialize_bytes, deserialize_opt_bytes};
Expand Down Expand Up @@ -811,8 +811,10 @@ pub enum EvmVersion {
Paris,
Shanghai,
Cancun,
#[default]
Prague,
// Currently Mercury is built on top of Ethereum's Prague hardfork.
#[default]
Mercury,
Osaka,
}

Expand All @@ -821,7 +823,6 @@ impl EvmVersion {
pub fn default_version_solc(version: &Version) -> Option<Self> {
// In most cases, Solc compilers use the highest EVM version available at the time.
let default = Self::default().normalize_version_solc(version)?;

// However, there are some exceptions where the default is lower than the highest available.
match default {
Self::Constantinople => {
Expand Down Expand Up @@ -851,8 +852,10 @@ impl EvmVersion {
if *version >= BYZANTIUM_SOLC {
// If the Solc version is the latest, it supports all EVM versions.
// For all other cases, cap at the at-the-time highest possible fork.
let normalized = if *version >= OSAKA_SOLC {
let normalized = if *version >= MERCURY_SOLC {
self
} else if self >= Self::Osaka && *version >= OSAKA_SOLC {
Self::Osaka
} else if self >= Self::Prague && *version >= PRAGUE_SOLC {
Self::Prague
} else if self >= Self::Cancun && *version >= CANCUN_SOLC {
Expand Down Expand Up @@ -898,6 +901,7 @@ impl EvmVersion {
Self::Shanghai => "shanghai",
Self::Cancun => "cancun",
Self::Prague => "prague",
Self::Mercury => "mercury",
Self::Osaka => "osaka",
}
}
Expand Down Expand Up @@ -968,6 +972,7 @@ impl FromStr for EvmVersion {
"shanghai" => Ok(Self::Shanghai),
"cancun" => Ok(Self::Cancun),
"prague" => Ok(Self::Prague),
"mercury" => Ok(Self::Mercury),
"osaka" => Ok(Self::Osaka),
s => Err(format!("Unknown evm version: {s}")),
}
Expand Down Expand Up @@ -1960,6 +1965,7 @@ mod tests {
// Cancun
("0.8.24", Some(EvmVersion::Shanghai)),
("0.8.25", Some(EvmVersion::Cancun)),
("0.8.31", Some(EvmVersion::Mercury)),
] {
let version = Version::from_str(solc_version).unwrap();
assert_eq!(
Expand Down Expand Up @@ -2019,6 +2025,12 @@ mod tests {
("0.8.26", EvmVersion::Prague, Some(EvmVersion::Cancun)),
("0.8.27", EvmVersion::Prague, Some(EvmVersion::Prague)),
("0.8.29", EvmVersion::Osaka, Some(EvmVersion::Osaka)),
// Mercury
// This one is a bit weird... based on the version only you'd think it would clip to
// Osaka, but actually in terms EvmVersions Prague < Mercury < Osaka.
("0.8.30", EvmVersion::Mercury, Some(EvmVersion::Prague)),
("0.8.31", EvmVersion::Osaka, Some(EvmVersion::Osaka)),
("0.8.31", EvmVersion::Mercury, Some(EvmVersion::Mercury)),
] {
let version = Version::from_str(solc_version).unwrap();
assert_eq!(
Expand Down
5 changes: 3 additions & 2 deletions crates/compilers/src/cache/iface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ pub(crate) fn interface_representation_ast(
}
}
}
let updates =
spans_to_remove.iter().map(|&span| (sess.source_map().span_to_source(span).unwrap().1, ""));
let updates = spans_to_remove
.iter()
.map(|&span| (sess.source_map().span_to_source(span).unwrap().data, ""));
let content = replace_source_content(content, updates).replace("\n", "");
crate::utils::RE_TWO_OR_MORE_SPACES.replace_all(&content, "").into_owned()
}
Expand Down
13 changes: 7 additions & 6 deletions crates/compilers/src/compilers/solc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,12 @@ impl Compiler for SolcCompiler {

fn available_versions(&self, _language: &Self::Language) -> Vec<CompilerVersion> {
match self {
Self::Specific(solc) => vec![CompilerVersion::Installed(Version::new(
solc.version.major,
solc.version.minor,
solc.version.patch,
))],
Self::Specific(solc) => {
let mut v =
Version::new(solc.version.major, solc.version.minor, solc.version.patch);
v.build = solc.version.build.clone();
vec![CompilerVersion::Installed(v)]
}

#[cfg(feature = "svm-solc")]
Self::AutoDetect => {
Expand Down Expand Up @@ -158,7 +159,7 @@ impl CompilerInput for SolcVersionedInput {
}

fn compiler_name(&self) -> Cow<'static, str> {
"Solc".into()
"ssolc".into()
}

fn strip_prefix(&mut self, base: &Path) {
Expand Down
33 changes: 27 additions & 6 deletions crates/compilers/src/report/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,19 +323,18 @@ impl Reporter for BasicStdoutReporter {
/// [`Compiler::compile()`]: crate::compilers::Compiler::compile
fn on_compiler_spawn(&self, compiler_name: &str, version: &Version, dirty_files: &[PathBuf]) {
println!(
"Compiling {} files with {} {}.{}.{}",
"Compiling {} files with {} {}",
dirty_files.len(),
compiler_name,
version.major,
version.minor,
version.patch
format_version_with_commit(version),
);
}

fn on_compiler_success(&self, compiler_name: &str, version: &Version, duration: &Duration) {
println!(
"{} {}.{}.{} finished in {duration:.2?}",
compiler_name, version.major, version.minor, version.patch
"{} {} finished in {duration:.2?}",
compiler_name,
format_version_with_commit(version),
);
}

Expand Down Expand Up @@ -375,6 +374,28 @@ pub fn format_unresolved_imports(imports: &[(&Path, &Path)], remappings: &[Remap
)
}

/// Extract short commit hash from version build metadata.
/// Handles format like "commit.676bdecc.Darwin.appleclang" → "676bdec"
pub fn extract_short_commit(version: &Version) -> Option<&str> {
let build = version.build.as_str();
let hash = build.strip_prefix("commit.")?;
let end = hash.find('.').unwrap_or(hash.len()).min(7);
Some(&hash[..end])
}

/// Format version with optional short commit hash for display.
/// Returns e.g. "0.8.31 (676bdec)" or "0.8.31" if no commit metadata.
/// Seismic note: changed the formatting here to show the commit version given that ssolc
/// is not mature enough to follow proper semver so its useful to know which exact commit foundry is
/// using.
pub fn format_version_with_commit(version: &Version) -> String {
if let Some(hash) = extract_short_commit(version) {
format!("{}.{}.{} ({hash})", version.major, version.minor, version.patch)
} else {
format!("{}.{}.{}", version.major, version.minor, version.patch)
}
}

/// Returned if setting the global reporter fails.
#[derive(Debug)]
pub struct SetGlobalReporterError {
Expand Down
Loading