Skip to content

Commit

Permalink
fix: improve compiler version check (#6920)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattsse authored Jan 27, 2024
1 parent 47e458b commit e0db5f2
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 12 deletions.
29 changes: 17 additions & 12 deletions crates/forge/bin/cmd/verify/etherscan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::{provider::VerificationProvider, VerifyArgs, VerifyCheckArgs};
use crate::cmd::retry::RETRY_CHECK_ON_VERIFY;
use alloy_json_abi::Function;
use eyre::{eyre, Context, Result};
use forge::hashbrown::HashSet;
use foundry_block_explorers::{
errors::EtherscanError,
utils::lookup_compiler_version,
Expand Down Expand Up @@ -394,23 +395,27 @@ impl EtherscanVerificationProvider {
"If cache is disabled, compiler version must be either provided with `--compiler-version` option or set in foundry.toml"
)?;
let artifacts = entry.artifacts_versions().collect::<Vec<_>>();
if artifacts.len() == 1 {
let mut version = artifacts[0].0.to_owned();
version.build = match RE_BUILD_COMMIT.captures(version.build.as_str()) {
Some(cap) => BuildMetadata::new(cap.name("commit").unwrap().as_str())?,
_ => BuildMetadata::EMPTY,
};
return Ok(version)
}

if artifacts.is_empty() {
warn!("No artifacts detected")
} else {
let versions = artifacts.iter().map(|a| a.0.to_string()).collect::<Vec<_>>();
eyre::bail!("No matching artifact found for {}", args.contract.name);
}

// ensure we have a single version
let unique_versions = artifacts.iter().map(|a| a.0.to_string()).collect::<HashSet<_>>();
if unique_versions.len() > 1 {
let versions = unique_versions.into_iter().collect::<Vec<_>>();
warn!("Ambiguous compiler versions found in cache: {}", versions.join(", "));
eyre::bail!("Compiler version has to be set in `foundry.toml`. If the project was not deployed with foundry, specify the version through `--compiler-version` flag.")
}

eyre::bail!("Compiler version has to be set in `foundry.toml`. If the project was not deployed with foundry, specify the version through `--compiler-version` flag.")
// we have a unique version
let mut version = artifacts[0].0.clone();
version.build = match RE_BUILD_COMMIT.captures(version.build.as_str()) {
Some(cap) => BuildMetadata::new(cap.name("commit").unwrap().as_str())?,
_ => BuildMetadata::EMPTY,
};

Ok(version)
}

/// Return the optional encoded constructor arguments. If the path to
Expand Down
51 changes: 51 additions & 0 deletions crates/forge/tests/cli/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,29 @@ function doStuff() external {}
.unwrap();
}

fn add_single_verify_target_file(prj: &TestProject) {
let timestamp = utils::millis_since_epoch();
let contract = format!(
r#"
contract Unique {{
uint public _timestamp = {timestamp};
}}
contract Verify is Unique {{
function doStuff() external {{}}
}}
"#
);

prj.add_source("Verify.sol", &contract).unwrap();
}

fn parse_verification_result(cmd: &mut TestCommand, retries: u32) -> eyre::Result<()> {
// give etherscan some time to verify the contract
let retry = Retry::new(retries, Some(Duration::from_secs(30)));
retry.run(|| -> eyre::Result<()> {
let output = cmd.unchecked_output();
let out = String::from_utf8_lossy(&output.stdout);
println!("{}", out);
if out.contains("Contract successfully verified") {
return Ok(())
}
Expand Down Expand Up @@ -75,6 +92,7 @@ fn verify_on_chain(info: Option<EnvExternalities>, prj: TestProject, mut cmd: Te
info.chain.to_string(),
address,
contract_path.to_string(),
"--etherscan-api-key".to_string(),
info.etherscan.to_string(),
"--verifier".to_string(),
info.verifier.to_string(),
Expand Down Expand Up @@ -114,6 +132,26 @@ fn verify_on_chain(info: Option<EnvExternalities>, prj: TestProject, mut cmd: Te
}
}

/// Executes create --verify on the given chain
fn create_verify_on_chain(info: Option<EnvExternalities>, prj: TestProject, mut cmd: TestCommand) {
// only execute if keys present
if let Some(info) = info {
println!("verifying on {}", info.chain);
add_single_verify_target_file(&prj);

let contract_path = "src/Verify.sol:Verify";
cmd.arg("create").args(info.create_args()).args([
contract_path,
"--etherscan-api-key",
info.etherscan.as_str(),
"--verify",
]);

let out = cmd.stdout_lossy();
assert!(out.contains("Contract successfully verified"), "{}", out);
}
}

// tests `create && contract-verify && verify-check` on Fantom testnet if correct env vars are set
forgetest!(can_verify_random_contract_fantom_testnet, |prj, cmd| {
verify_on_chain(EnvExternalities::ftm_testnet(), prj, cmd);
Expand All @@ -123,3 +161,16 @@ forgetest!(can_verify_random_contract_fantom_testnet, |prj, cmd| {
forgetest!(can_verify_random_contract_optimism_kovan, |prj, cmd| {
verify_on_chain(EnvExternalities::optimism_kovan(), prj, cmd);
});

// tests `create && contract-verify && verify-check` on Sepolia testnet if correct env vars are set
forgetest!(can_verify_random_contract_sepolia, |prj, cmd| {
verify_on_chain(EnvExternalities::sepolia(), prj, cmd);
});

// tests `create --verify on Sepolia testnet if correct env vars are set
// SEPOLIA_RPC_URL=https://rpc.sepolia.org
// TEST_PRIVATE_KEY=0x...
// ETHERSCAN_API_KEY=
forgetest!(can_create_verify_random_contract_sepolia, |prj, cmd| {
create_verify_on_chain(EnvExternalities::sepolia(), prj, cmd);
});

0 comments on commit e0db5f2

Please sign in to comment.