Skip to content

Commit

Permalink
feat: allow supplying function name via forge script --sig (#7518)
Browse files Browse the repository at this point in the history
* feat: allow supplying fn name via forge script --sig

* fmt

* clippy

* add test
  • Loading branch information
klkvr authored Mar 30, 2024
1 parent a16714e commit d94e3c6
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 22 deletions.
18 changes: 18 additions & 0 deletions crates/forge/tests/cli/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1179,3 +1179,21 @@ forgetest_async!(can_sign_with_script_wallet_multiple, |prj, cmd| {
.await
.simulate(ScriptOutcome::OkRun);
});

forgetest_async!(fails_with_function_name_and_overloads, |prj, cmd| {
let script = prj
.add_script(
"Sctipt.s.sol",
r#"
contract Script {
function run() external {}
function run(address,uint256) external {}
}
"#,
)
.unwrap();

cmd.arg("script").args([&script.to_string_lossy(), "--sig", "run"]);
assert!(cmd.stderr_lossy().contains("Multiple functions with the same name"));
});
52 changes: 30 additions & 22 deletions crates/script/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use build::PreprocessedState;
use clap::{Parser, ValueHint};
use dialoguer::Confirm;
use ethers_signers::Signer;
use eyre::{ContextCompat, Result, WrapErr};
use eyre::{ContextCompat, Result};
use forge_verify::RetryArgs;
use foundry_cli::{opts::CoreBuildArgs, utils::LoadConfig};
use foundry_common::{
Expand Down Expand Up @@ -311,30 +311,38 @@ impl ScriptArgs {
///
/// Note: We assume that the `sig` is already stripped of its prefix, See [`ScriptArgs`]
fn get_method_and_calldata(&self, abi: &JsonAbi) -> Result<(Function, Bytes)> {
let (func, data) = if let Ok(func) = get_func(&self.sig) {
(
abi.functions().find(|&abi_func| abi_func.selector() == func.selector()).wrap_err(
format!("Function `{}` is not implemented in your script.", self.sig),
)?,
encode_function_args(&func, &self.args)?.into(),
)
} else {
let decoded = hex::decode(&self.sig).wrap_err("Invalid hex calldata")?;
if let Ok(decoded) = hex::decode(&self.sig) {
let selector = &decoded[..SELECTOR_LEN];
(
abi.functions().find(|&func| selector == &func.selector()[..]).ok_or_else(
|| {
eyre::eyre!(
"Function selector `{}` not found in the ABI",
hex::encode(selector)
)
},
)?,
decoded.into(),
)
let func =
abi.functions().find(|func| selector == &func.selector()[..]).ok_or_else(|| {
eyre::eyre!(
"Function selector `{}` not found in the ABI",
hex::encode(selector)
)
})?;
return Ok((func.clone(), decoded.into()));
}

let func = if self.sig.contains('(') {
let func = get_func(&self.sig)?;
abi.functions()
.find(|&abi_func| abi_func.selector() == func.selector())
.wrap_err(format!("Function `{}` is not implemented in your script.", self.sig))?
} else {
let matching_functions =
abi.functions().filter(|func| func.name == self.sig).collect::<Vec<_>>();
match matching_functions.len() {
0 => eyre::bail!("Function `{}` not found in the ABI", self.sig),
1 => matching_functions[0],
2.. => eyre::bail!(
"Multiple functions with the same name `{}` found in the ABI",
self.sig
),
}
};
let data = encode_function_args(func, &self.args)?;

Ok((func.clone(), data))
Ok((func.clone(), data.into()))
}

/// Checks if the transaction is a deployment with either a size above the `CONTRACT_MAX_SIZE`
Expand Down

0 comments on commit d94e3c6

Please sign in to comment.