Skip to content
This repository was archived by the owner on Apr 20, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ jobs:
fail-fast: false
matrix:
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
rust: ["stable", "1.88"]
rust: ["stable", "1.93"]
flags: ["", "--all-features"]
exclude:
# Skip because some features have higher MSRV.
- rust: "1.88" # MSRV
- rust: "1.93" # MSRV
flags: "--all-features"
steps:
- uses: actions/checkout@v5
Expand Down
22 changes: 14 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,36 +1,42 @@
[workspace]
members = ["crates/artifacts/*", "crates/core", "crates/compilers"]
resolver = "2"
resolver = "3"

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

[workspace.lints.clippy]
borrow_as_ptr = "warn"
branches_sharing_code = "warn"
clear_with_drain = "warn"
cloned_instead_of_copied = "warn"
collection_is_never_read = "warn"
dbg-macro = "warn"
explicit_iter_loop = "warn"
manual-string-new = "warn"
uninlined-format-args = "warn"
use-self = "warn"
redundant-clone = "warn"

result-large-err = "allow"
large-enum-variant = "allow"
result_large_err = "allow"
large_enum_variant = "allow"

[workspace.lints.rust]
redundant_imports = "warn"
redundant-lifetimes = "warn"
rust-2018-idioms = "warn"
# unreachable-pub = "warn"
unused-must-use = "warn"
redundant-lifetimes = "warn"
# unreachable-pub = "warn"

[workspace.lints.rustdoc]
all = "warn"
Expand Down
2 changes: 1 addition & 1 deletion clippy.toml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
msrv = "1.88"
msrv = "1.93"
2 changes: 1 addition & 1 deletion crates/artifacts/solc/src/ast/lowfidelity.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Bindings for solc's `ast` output field

use crate::serde_helpers;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use std::{collections::BTreeMap, fmt, fmt::Write, str::FromStr};

/// Represents the AST field in the solc output
Expand Down
13 changes: 6 additions & 7 deletions crates/artifacts/solc/src/bytecode.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
//! Bytecode related types.

use crate::{
serde_helpers,
FunctionDebugData, GeneratedSource, Offsets, serde_helpers,
sourcemap::{self, SourceMap, SyntaxError},
FunctionDebugData, GeneratedSource, Offsets,
};
use alloy_primitives::{hex, Address, Bytes};
use alloy_primitives::{Address, Bytes, hex};
use foundry_compilers_core::utils;
use serde::{Deserialize, Serialize, Serializer};
use std::collections::BTreeMap;
Expand Down Expand Up @@ -286,10 +285,10 @@ impl BytecodeObject {
///
/// Returns the string if it is a valid
pub fn resolve(&mut self) -> Option<&Bytes> {
if let Self::Unlinked(unlinked) = self {
if let Ok(linked) = hex::decode(unlinked) {
*self = Self::Bytecode(linked.into());
}
if let Self::Unlinked(unlinked) = self
&& let Ok(linked) = hex::decode(unlinked)
{
*self = Self::Bytecode(linked.into());
}
self.as_bytes()
}
Expand Down
8 changes: 4 additions & 4 deletions crates/artifacts/solc/src/configurable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ impl ConfigurableContractArtifact {
links.extend(bcode.link_references.clone());
}

if let Some(d_bcode) = &self.deployed_bytecode {
if let Some(bcode) = &d_bcode.bytecode {
links.extend(bcode.link_references.clone());
}
if let Some(d_bcode) = &self.deployed_bytecode
&& let Some(bcode) = &d_bcode.bytecode
{
links.extend(bcode.link_references.clone());
}
links
}
Expand Down
19 changes: 10 additions & 9 deletions crates/artifacts/solc/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
//! Contract related types.

use crate::{
DevDoc, Evm, Ewasm, LosslessMetadata, Offsets, StorageLayout, UserDoc,
bytecode::{
Bytecode, BytecodeObject, CompactBytecode, CompactDeployedBytecode, DeployedBytecode,
},
serde_helpers, DevDoc, Evm, Ewasm, LosslessMetadata, Offsets, StorageLayout, UserDoc,
serde_helpers,
};
use alloy_json_abi::JsonAbi;
use alloy_primitives::Bytes;
Expand Down Expand Up @@ -101,10 +102,10 @@ impl ContractBytecode {
links.extend(bcode.link_references.clone());
}

if let Some(d_bcode) = &self.deployed_bytecode {
if let Some(bcode) = &d_bcode.bytecode {
links.extend(bcode.link_references.clone());
}
if let Some(d_bcode) = &self.deployed_bytecode
&& let Some(bcode) = &d_bcode.bytecode
{
links.extend(bcode.link_references.clone());
}
links
}
Expand Down Expand Up @@ -146,10 +147,10 @@ impl CompactContractBytecode {
links.extend(bcode.link_references.clone());
}

if let Some(d_bcode) = &self.deployed_bytecode {
if let Some(bcode) = &d_bcode.bytecode {
links.extend(bcode.link_references.clone());
}
if let Some(d_bcode) = &self.deployed_bytecode
&& let Some(bcode) = &d_bcode.bytecode
{
links.extend(bcode.link_references.clone());
}
links
}
Expand Down
26 changes: 14 additions & 12 deletions crates/artifacts/solc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
extern crate tracing;

use semver::Version;
use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Visitor};
use std::{
collections::{BTreeMap, HashSet},
fmt,
Expand Down Expand Up @@ -37,9 +37,8 @@ use crate::output_selection::{ContractOutputSelection, OutputSelection};
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,
BERLIN_SOLC, BYZANTIUM_SOLC, CANCUN_SOLC, CONSTANTINOPLE_SOLC, ISTANBUL_SOLC, LONDON_SOLC,
OSAKA_SOLC, PARIS_SOLC, PETERSBURG_SOLC, PRAGUE_SOLC, SHANGHAI_SOLC, strip_prefix_owned,
},
};
pub use serde_helpers::{deserialize_bytes, deserialize_opt_bytes};
Expand Down Expand Up @@ -341,11 +340,11 @@ impl Settings {
meta.cbor_metadata = None;
}

if let Some(model_checker) = &mut self.model_checker {
if let Some(solvers) = &mut model_checker.solvers {
// elf solver introduced in 0.8.18 <https://github.com/ethereum/solidity/releases/tag/v0.8.18>
solvers.retain(|solver| *solver != ModelCheckerSolver::Eld);
}
if let Some(model_checker) = &mut self.model_checker
&& let Some(solvers) = &mut model_checker.solvers
{
// elf solver introduced in 0.8.18 <https://github.com/ethereum/solidity/releases/tag/v0.8.18>
solvers.retain(|solver| *solver != ModelCheckerSolver::Eld);
}
}

Expand Down Expand Up @@ -394,7 +393,7 @@ impl Settings {
/// Inserts the value for all files and contracts
///
/// ```
/// use foundry_compilers_artifacts_solc::{output_selection::ContractOutputSelection, Settings};
/// use foundry_compilers_artifacts_solc::{Settings, output_selection::ContractOutputSelection};
/// let mut selection = Settings::default();
/// selection.push_output_selection(ContractOutputSelection::Metadata);
/// ```
Expand Down Expand Up @@ -1857,7 +1856,7 @@ mod tests {
object.object
}

let bytecode = "6060604052341561000f57600080fd5b60f48061001d6000396000f300606060405260043610603e5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166326121ff081146043575b600080fd5b3415604d57600080fd5b60536055565b005b73__lib2.sol:L____________________________6326121ff06040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038186803b151560b357600080fd5b6102c65a03f4151560c357600080fd5b5050505600a165627a7a723058207979b30bd4a07c77b02774a511f2a1dd04d7e5d65b5c2735b5fc96ad61d43ae40029";
let bytecode = "6060604052341561000f57600080fd5b60f48061001d6000396000f300606060405260043610603e5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166326121ff081146043575b600080fd5b3415604d57600080fd5b60536055565b005b73__lib2.sol:L____________________________6326121ff06040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038186803b151560b357600080fd5b6102c65a03f4151560c357600080fd5b5050505600a165627a7a723058207979b30bd4a07c77b02774a511f2a1dd04d7e5d65b5c2735b5fc96ad61d43ae40029";

let mut object = parse_bytecode(bytecode);
assert!(object.is_unlinked());
Expand Down Expand Up @@ -2201,7 +2200,10 @@ mod tests {

let value: serde_json::Value = serde_json::from_str(s).unwrap();
let c: Contract = serde_json::from_value(value).unwrap();
assert_eq!(c.metadata.as_ref().unwrap().raw_metadata, "{\"compiler\":{\"version\":\"0.4.18+commit.9cf6e910\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}],\"devdoc\":{\"methods\":{\"transferOwnership(address)\":{\"details\":\"Allows the current owner to transfer control of the contract to a newOwner.\",\"params\":{\"newOwner\":\"The address to transfer ownership to.\"}}},\"title\":\"Ownable\"},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"src/Contract.sol\":\"Ownable\"},\"libraries\":{},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":src/=src/\"]},\"sources\":{\"src/Contract.sol\":{\"keccak256\":\"0x3e0d611f53491f313ae035797ed7ecfd1dfd8db8fef8f82737e6f0cd86d71de7\",\"urls\":[\"bzzr://9c33025fa9d1b8389e4c7c9534a1d70fad91c6c2ad70eb5e4b7dc3a701a5f892\"]}},\"version\":1}");
assert_eq!(
c.metadata.as_ref().unwrap().raw_metadata,
"{\"compiler\":{\"version\":\"0.4.18+commit.9cf6e910\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}],\"devdoc\":{\"methods\":{\"transferOwnership(address)\":{\"details\":\"Allows the current owner to transfer control of the contract to a newOwner.\",\"params\":{\"newOwner\":\"The address to transfer ownership to.\"}}},\"title\":\"Ownable\"},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"src/Contract.sol\":\"Ownable\"},\"libraries\":{},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":src/=src/\"]},\"sources\":{\"src/Contract.sol\":{\"keccak256\":\"0x3e0d611f53491f313ae035797ed7ecfd1dfd8db8fef8f82737e6f0cd86d71de7\",\"urls\":[\"bzzr://9c33025fa9d1b8389e4c7c9534a1d70fad91c6c2ad70eb5e4b7dc3a701a5f892\"]}},\"version\":1}"
);

let value = serde_json::to_string(&c).unwrap();
assert_eq!(s, value);
Expand Down
4 changes: 2 additions & 2 deletions crates/artifacts/solc/src/output_selection.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Bindings for standard json output selection.

use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer};
use serde::{Deserialize, Deserializer, Serialize, Serializer, ser::SerializeMap};
use std::{collections::BTreeMap, fmt, str::FromStr};

/// Represents the desired outputs based on a File `(file -> (contract -> [outputs]))`
Expand Down Expand Up @@ -169,7 +169,7 @@ impl Serialize for OutputSelection {
}

let mut map = serializer.serialize_map(Some(self.0.len()))?;
for (file, selection) in self.0.iter() {
for (file, selection) in &self.0 {
if selection.is_empty() {
map.serialize_entry(file, &EmptyFileOutput {})?;
} else {
Expand Down
43 changes: 20 additions & 23 deletions crates/artifacts/solc/src/remappings/find.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::Remapping;
use foundry_compilers_core::utils;
use rayon::prelude::*;
use std::{
collections::{btree_map::Entry, BTreeMap, HashSet},
collections::{BTreeMap, HashSet, btree_map::Entry},
fs::FileType,
path::{Path, PathBuf},
sync::Mutex,
Expand Down Expand Up @@ -325,19 +325,17 @@ fn find_remapping_candidates(
// ├── dep/node_modules
// ├── symlink to `my-package`
// ```
if path_is_symlink {
if let Ok(target) = utils::canonicalize(&subdir) {
if !visited_symlink_dirs.lock().unwrap().insert(target.clone()) {
// short-circuiting if we've already visited the symlink
return Vec::new();
}
// the symlink points to a parent dir of the current window
if open.components().count() > target.components().count()
&& utils::common_ancestor(open, &target).is_some()
{
// short-circuiting
return Vec::new();
}
if path_is_symlink && let Ok(target) = utils::canonicalize(&subdir) {
if !visited_symlink_dirs.lock().unwrap().insert(target.clone()) {
// short-circuiting if we've already visited the symlink
return Vec::new();
}
// the symlink points to a parent dir of the current window
if open.components().count() > target.components().count()
&& utils::common_ancestor(open, &target).is_some()
{
// short-circuiting
return Vec::new();
}
}

Expand Down Expand Up @@ -449,11 +447,7 @@ fn dir_distance(root: &Path, current: &Path) -> usize {
if root == current {
return 0;
}
if let Ok(rem) = current.strip_prefix(root) {
rem.components().count()
} else {
0
}
if let Ok(rem) = current.strip_prefix(root) { rem.components().count() } else { 0 }
}

/// This finds the next window between `root` and `current`
Expand Down Expand Up @@ -511,11 +505,14 @@ mod tests {
"/var/folders/l5/lprhf87s6xv8djgd017f0b2h0000gn/T/lib.Z6ODLZJQeJQa/repo1/lib",
);
let b = Path::new(
"/var/folders/l5/lprhf87s6xv8djgd017f0b2h0000gn/T/lib.Z6ODLZJQeJQa/repo1/lib/ds-test/src"
"/var/folders/l5/lprhf87s6xv8djgd017f0b2h0000gn/T/lib.Z6ODLZJQeJQa/repo1/lib/ds-test/src",
);
assert_eq!(
next_nested_window(a, b),
Path::new(
"/var/folders/l5/lprhf87s6xv8djgd017f0b2h0000gn/T/lib.Z6ODLZJQeJQa/repo1/lib/ds-test"
)
);
assert_eq!(next_nested_window(a, b),Path::new(
"/var/folders/l5/lprhf87s6xv8djgd017f0b2h0000gn/T/lib.Z6ODLZJQeJQa/repo1/lib/ds-test"
));
}

#[test]
Expand Down
16 changes: 6 additions & 10 deletions crates/artifacts/solc/src/serde_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ where

pub mod json_string_opt {
use serde::{
de::{self, DeserializeOwned},
Deserialize, Deserializer, Serialize, Serializer,
de::{self, DeserializeOwned},
};

pub fn serialize<T, S>(value: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
Expand Down Expand Up @@ -64,8 +64,8 @@ pub mod json_string_opt {
/// deserializes empty json object `{}` as `None`
pub mod empty_json_object_opt {
use serde::{
de::{self, DeserializeOwned},
Deserialize, Deserializer, Serialize, Serializer,
de::{self, DeserializeOwned},
};

pub fn serialize<T, S>(value: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
Expand Down Expand Up @@ -117,16 +117,12 @@ pub mod string_bytes {
D: Deserializer<'de>,
{
let value = String::deserialize(deserializer)?;
if let Some(rem) = value.strip_prefix("0x") {
Ok(rem.to_string())
} else {
Ok(value)
}
if let Some(rem) = value.strip_prefix("0x") { Ok(rem.to_string()) } else { Ok(value) }
}
}

pub mod display_from_str_opt {
use serde::{de, Deserialize, Deserializer, Serializer};
use serde::{Deserialize, Deserializer, Serializer, de};
use std::{fmt, str::FromStr};

pub fn serialize<T, S>(value: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
Expand Down Expand Up @@ -156,7 +152,7 @@ pub mod display_from_str_opt {
}

pub mod display_from_str {
use serde::{de, Deserialize, Deserializer, Serializer};
use serde::{Deserialize, Deserializer, Serializer, de};
use std::{fmt, str::FromStr};

pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
Expand All @@ -179,7 +175,7 @@ pub mod display_from_str {

/// (De)serialize vec of tuples as map
pub mod tuple_vec_map {
use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize, Serializer};
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned};

pub fn serialize<K, V, S>(data: &[(K, V)], serializer: S) -> Result<S::Ok, S::Error>
where
Expand Down
Loading
Loading