Skip to content

Commit a70e6c0

Browse files
zugdevgrandizzyonbjerg
authored
feat: cast storage --solc-version CLI argument (#11321)
* feat: storage solc version option * feat(cast): add storage solc version unwrapping test * feat(cast): add valid and invalid solc versions for cast storage tests * feat(cast): collapse if statement * chore: format * feat(cast): warn if provided version is less than min solc * feat(cast): test for min solc version warning on provided storage solc version --------- Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: onbjerg <onbjerg@users.noreply.github.com>
1 parent b8cfad5 commit a70e6c0

File tree

2 files changed

+98
-9
lines changed

2 files changed

+98
-9
lines changed

crates/cast/src/cmd/storage.rs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ pub struct StorageArgs {
7373

7474
#[command(flatten)]
7575
build: BuildOpts,
76+
77+
/// Specify the solc version to compile with. Overrides detected version.
78+
#[arg(long, value_parser = Version::parse)]
79+
solc_version: Option<Version>,
7680
}
7781

7882
impl_figment_convert_cast!(StorageArgs);
@@ -169,16 +173,24 @@ impl StorageArgs {
169173
let mut project = etherscan_project(metadata, root_path)?;
170174
add_storage_layout_output(&mut project);
171175

172-
let mut version = metadata.compiler_version()?;
176+
// Decide on compiler to use (user override -> metadata -> autodetect)
177+
let meta_version = metadata.compiler_version()?;
173178
let mut auto_detect = false;
174-
if let Some(solcc) = project.compiler.solc.as_mut()
175-
&& let SolcCompiler::Specific(solc) = solcc
176-
&& solc.version < MIN_SOLC
177-
{
178-
version = solc.version.clone();
179-
*solcc = SolcCompiler::AutoDetect;
179+
let desired = if let Some(user_version) = self.solc_version {
180+
if user_version < MIN_SOLC {
181+
sh_warn!(
182+
"The provided --solc-version is {user_version} while the minimum version for \
183+
storage layouts is {MIN_SOLC} and as a result the output may be empty."
184+
)?;
185+
}
186+
SolcCompiler::Specific(Solc::find_or_install(&user_version)?)
187+
} else if meta_version < MIN_SOLC {
180188
auto_detect = true;
181-
}
189+
SolcCompiler::AutoDetect
190+
} else {
191+
SolcCompiler::Specific(Solc::find_or_install(&meta_version)?)
192+
};
193+
project.compiler.solc = Some(desired);
182194

183195
// Compile
184196
let mut out = ProjectCompiler::new().quiet(true).compile(&project)?;
@@ -191,7 +203,7 @@ impl StorageArgs {
191203
if auto_detect && is_storage_layout_empty(&artifact.storage_layout) {
192204
// try recompiling with the minimum version
193205
sh_warn!(
194-
"The requested contract was compiled with {version} while the minimum version \
206+
"The requested contract was compiled with {meta_version} while the minimum version \
195207
for storage layouts is {MIN_SOLC} and as a result the output may be empty.",
196208
)?;
197209
let solc = Solc::find_or_install(&MIN_SOLC)?;
@@ -392,4 +404,10 @@ mod tests {
392404
let key = config.get_etherscan_api_key(None).unwrap();
393405
assert_eq!(key, "dummykey".to_string());
394406
}
407+
408+
#[test]
409+
fn parse_solc_version_arg() {
410+
let args = StorageArgs::parse_from(["foundry-cli", "addr.eth", "--solc-version", "0.8.10"]);
411+
assert_eq!(args.solc_version, Some(Version::parse("0.8.10").unwrap()));
412+
}
395413
}

crates/cast/tests/cli/main.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1939,6 +1939,77 @@ casttest!(storage, |_prj, cmd| {
19391939
"#]]);
19401940
});
19411941

1942+
casttest!(storage_with_valid_solc_version_1, |_prj, cmd| {
1943+
cmd.args([
1944+
"storage",
1945+
"0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2",
1946+
"--solc-version",
1947+
"0.8.10",
1948+
"--rpc-url",
1949+
next_http_archive_rpc_url().as_str(),
1950+
"--etherscan-api-key",
1951+
next_etherscan_api_key().as_str(),
1952+
])
1953+
.assert_success();
1954+
});
1955+
1956+
casttest!(storage_with_valid_solc_version_2, |_prj, cmd| {
1957+
cmd.args([
1958+
"storage",
1959+
"0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2",
1960+
"--solc-version",
1961+
"0.8.23",
1962+
"--rpc-url",
1963+
next_http_archive_rpc_url().as_str(),
1964+
"--etherscan-api-key",
1965+
next_etherscan_api_key().as_str(),
1966+
])
1967+
.assert_success();
1968+
});
1969+
1970+
casttest!(storage_with_invalid_solc_version_1, |_prj, cmd| {
1971+
let output = cmd
1972+
.args([
1973+
"storage",
1974+
"0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2",
1975+
"--solc-version",
1976+
"0.4.0",
1977+
"--rpc-url",
1978+
next_http_archive_rpc_url().as_str(),
1979+
"--etherscan-api-key",
1980+
next_etherscan_api_key().as_str(),
1981+
])
1982+
.assert_failure()
1983+
.get_output()
1984+
.stderr
1985+
.clone();
1986+
let stderr = String::from_utf8_lossy(&output);
1987+
assert!(
1988+
stderr.contains(
1989+
"Warning: The provided --solc-version is 0.4.0 while the minimum version for storage layouts is 0.6.5"
1990+
),
1991+
"stderr did not contain expected warning. Full stderr:\n{stderr}"
1992+
);
1993+
});
1994+
1995+
casttest!(storage_with_invalid_solc_version_2, |_prj, cmd| {
1996+
cmd.args([
1997+
"storage",
1998+
"0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2",
1999+
"--solc-version",
2000+
"0.8.2",
2001+
"--rpc-url",
2002+
next_http_archive_rpc_url().as_str(),
2003+
"--etherscan-api-key",
2004+
next_etherscan_api_key().as_str(),
2005+
])
2006+
.assert_failure()
2007+
.stderr_eq(str![[r#"
2008+
Error: Encountered invalid solc version in contracts/Create2Deployer.sol: No solc version exists that matches the version requirement: ^0.8.9
2009+
2010+
"#]]);
2011+
});
2012+
19422013
// <https://github.com/foundry-rs/foundry/issues/6319>
19432014
casttest!(storage_layout_simple, |_prj, cmd| {
19442015
cmd.args([

0 commit comments

Comments
 (0)