Skip to content

Commit

Permalink
feat(verify): default to sourcify if etherscan key not provided (#9630
Browse files Browse the repository at this point in the history
)

* feat(`verify`): default to sourcify if etherscan key not provided

* clippy

* nit

Co-authored-by: zerosnacks <[email protected]>

---------

Co-authored-by: zerosnacks <[email protected]>
  • Loading branch information
yash-atreya and zerosnacks authored Jan 7, 2025
1 parent d2dbe3e commit 95442fa
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 31 deletions.
10 changes: 10 additions & 0 deletions crates/forge/tests/cli/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@ impl EnvExternalities {
})
}

pub fn sepolia_empty_verifier() -> Option<Self> {
Some(Self {
chain: NamedChain::Sepolia,
rpc: network_rpc_key("sepolia")?,
pk: network_private_key("sepolia")?,
etherscan: String::new(),
verifier: String::new(),
})
}

/// Returns the arguments required to deploy the contract
pub fn create_args(&self) -> Vec<String> {
vec![
Expand Down
91 changes: 64 additions & 27 deletions crates/forge/tests/cli/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,29 @@ fn parse_verification_result(cmd: &mut TestCommand, retries: u32) -> eyre::Resul
})
}

fn verify_check(
guid: String,
chain: String,
etherscan_api_key: Option<String>,
verifier: Option<String>,
mut cmd: TestCommand,
) {
let mut args = vec!["verify-check", &guid, "--chain-id", &chain];

if let Some(etherscan_api_key) = &etherscan_api_key {
args.push("--etherscan-api-key");
args.push(etherscan_api_key);
}

if let Some(verifier) = &verifier {
args.push("--verifier");
args.push(verifier);
}
cmd.forge_fuse().args(args);

parse_verification_result(&mut cmd, 6).expect("Failed to verify check")
}

fn await_verification_response(info: EnvExternalities, mut cmd: TestCommand) {
let guid = {
// Give Etherscan some time to detect the transaction.
Expand All @@ -110,48 +133,57 @@ fn await_verification_response(info: EnvExternalities, mut cmd: TestCommand) {
};

// verify-check
cmd.forge_fuse()
.arg("verify-check")
.arg(guid)
.arg("--chain-id")
.arg(info.chain.to_string())
.arg("--etherscan-api-key")
.arg(info.etherscan)
.arg("--verifier")
.arg(info.verifier);
let etherscan = (!info.etherscan.is_empty()).then_some(info.etherscan.clone());
let verifier = (!info.verifier.is_empty()).then_some(info.verifier.clone());
verify_check(guid, info.chain.to_string(), etherscan, verifier, cmd);
}

parse_verification_result(&mut cmd, 6).expect("Failed to verify check")
fn deploy_contract(
info: &EnvExternalities,
contract_path: &str,
prj: TestProject,
cmd: &mut TestCommand,
) -> String {
add_unique(&prj);
add_verify_target(&prj);
let output = cmd
.forge_fuse()
.arg("create")
.args(info.create_args())
.arg(contract_path)
.assert_success()
.get_output()
.stdout_lossy();
utils::parse_deployed_address(output.as_str())
.unwrap_or_else(|| panic!("Failed to parse deployer {output}"))
}

#[allow(clippy::disallowed_macros)]
fn 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_unique(&prj);
add_verify_target(&prj);

let contract_path = "src/Verify.sol:Verify";
let output = cmd
.arg("create")
.args(info.create_args())
.arg(contract_path)
.assert_success()
.get_output()
.stdout_lossy();
let address = utils::parse_deployed_address(output.as_str())
.unwrap_or_else(|| panic!("Failed to parse deployer {output}"));
let address = deploy_contract(&info, contract_path, prj, &mut cmd);

cmd.forge_fuse().arg("verify-contract").root_arg().args([
let mut args = vec![
"--chain-id".to_string(),
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(),
]);
];

if !info.etherscan.is_empty() {
args.push("--etherscan-api-key".to_string());
args.push(info.etherscan.clone());
}

if !info.verifier.is_empty() {
args.push("--verifier".to_string());
args.push(info.verifier.clone());
}
cmd.forge_fuse().arg("verify-contract").root_arg().args(args);

await_verification_response(info, cmd)
}
Expand Down Expand Up @@ -247,3 +279,8 @@ forgetest!(can_create_verify_random_contract_sepolia, |prj, cmd| {
forgetest!(can_guess_constructor_args, |prj, cmd| {
guess_constructor_args(EnvExternalities::goerli(), prj, cmd);
});

// tests `create && verify-contract && verify-check` on sepolia with default sourcify verifier
forgetest!(can_verify_random_contract_sepolia_default_sourcify, |prj, cmd| {
verify_on_chain(EnvExternalities::sepolia_empty_verifier(), prj, cmd);
});
12 changes: 10 additions & 2 deletions crates/verify/src/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ impl fmt::Display for VerificationProviderType {

#[derive(Clone, Debug, Default, PartialEq, Eq, clap::ValueEnum)]
pub enum VerificationProviderType {
#[default]
Etherscan,
#[default]
Sourcify,
Blockscout,
Oklink,
Expand All @@ -170,14 +170,22 @@ pub enum VerificationProviderType {
impl VerificationProviderType {
/// Returns the corresponding `VerificationProvider` for the key
pub fn client(&self, key: &Option<String>) -> Result<Box<dyn VerificationProvider>> {
if key.as_ref().is_some_and(|k| !k.is_empty()) && matches!(self, Self::Sourcify) {
return Ok(Box::<EtherscanVerificationProvider>::default());
}
match self {
Self::Etherscan => {
if key.as_ref().is_none_or(|key| key.is_empty()) {
eyre::bail!("ETHERSCAN_API_KEY must be set")
}
Ok(Box::<EtherscanVerificationProvider>::default())
}
Self::Sourcify => Ok(Box::<SourcifyVerificationProvider>::default()),
Self::Sourcify => {
sh_println!(
"Attempting to verify on Sourcify, pass the --etherscan-api-key <API_KEY> to verify on Etherscan OR use the --verifier flag to verify on any other provider"
)?;
Ok(Box::<SourcifyVerificationProvider>::default())
}
Self::Blockscout => Ok(Box::<EtherscanVerificationProvider>::default()),
Self::Oklink => Ok(Box::<EtherscanVerificationProvider>::default()),
Self::Custom => Ok(Box::<EtherscanVerificationProvider>::default()),
Expand Down
4 changes: 2 additions & 2 deletions crates/verify/src/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::provider::VerificationContext;
#[derive(Clone, Debug, Parser)]
pub struct VerifierArgs {
/// The contract verification provider to use.
#[arg(long, help_heading = "Verifier options", default_value = "etherscan", value_enum)]
#[arg(long, help_heading = "Verifier options", default_value = "sourcify", value_enum)]
pub verifier: VerificationProviderType,

/// The verifier API KEY, if using a custom provider.
Expand All @@ -44,7 +44,7 @@ pub struct VerifierArgs {
impl Default for VerifierArgs {
fn default() -> Self {
Self {
verifier: VerificationProviderType::Etherscan,
verifier: VerificationProviderType::Sourcify,
verifier_api_key: None,
verifier_url: None,
}
Expand Down

0 comments on commit 95442fa

Please sign in to comment.