Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: better parse error messages #6499

Merged
merged 2 commits into from
Dec 2, 2023
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
15 changes: 5 additions & 10 deletions crates/cast/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use alloy_dyn_abi::{DynSolType, DynSolValue, FunctionExt};
use alloy_json_abi::{ContractObject, Function};
use alloy_json_abi::ContractObject;
use alloy_primitives::{Address, I256, U256};
use alloy_rlp::Decodable;
use base::{Base, NumberWithBase, ToBase};
Expand All @@ -16,7 +16,7 @@ use evm_disassembler::{disassemble_bytes, disassemble_str, format_operations};
use eyre::{Context, ContextCompat, Result};
use foundry_block_explorers::Client;
use foundry_common::{
abi::encode_function_args,
abi::{encode_function_args, get_func},
fmt::*,
types::{ToAlloy, ToEthers},
TransactionReceiptWithRevertReason,
Expand Down Expand Up @@ -1561,12 +1561,7 @@ impl SimpleCast {
/// # Ok::<_, eyre::Report>(())
/// ```
pub fn abi_encode(sig: &str, args: &[impl AsRef<str>]) -> Result<String> {
let func = match Function::parse(sig) {
Ok(func) => func,
Err(err) => {
eyre::bail!("Could not process human-readable ABI. Please check if you've left the parenthesis unclosed or if some type is incomplete.\nError:\n{}", err)
}
};
let func = get_func(sig)?;
let calldata = match encode_function_args(&func, args) {
Ok(res) => hex::encode(res),
Err(e) => eyre::bail!("Could not ABI encode the function and arguments. Did you pass in the right types?\nError\n{}", e),
Expand All @@ -1589,7 +1584,7 @@ impl SimpleCast {
/// # Ok::<_, eyre::Report>(())
/// ```
pub fn calldata_encode(sig: impl AsRef<str>, args: &[impl AsRef<str>]) -> Result<String> {
let func = Function::parse(sig.as_ref())?;
let func = get_func(sig.as_ref())?;
let calldata = encode_function_args(&func, args)?;
Ok(hex::encode_prefixed(calldata))
}
Expand Down Expand Up @@ -1909,7 +1904,7 @@ impl SimpleCast {
eyre::bail!("number of leading zeroes must not be greater than 4");
}
if optimize == 0 {
let selector = Function::parse(signature)?.selector();
let selector = get_func(signature)?.selector();
return Ok((selector.to_string(), String::from(signature)))
}
let Some((name, params)) = signature.split_once('(') else {
Expand Down
32 changes: 12 additions & 20 deletions crates/common/src/abi.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! ABI related helper functions.

use alloy_dyn_abi::{DynSolType, DynSolValue, FunctionExt, JsonAbiExt};
use alloy_json_abi::{AbiItem, Event, Function};
use alloy_json_abi::{Event, Function};
use alloy_primitives::{hex, Address, Log};
use eyre::{ContextCompat, Result};
use eyre::{Context, ContextCompat, Result};
use foundry_block_explorers::{contract::ContractMetadata, errors::EtherscanError, Client};
use foundry_config::Chain;
use std::{future::Future, pin::Pin};
Expand All @@ -28,7 +28,7 @@ pub fn abi_decode_calldata(
input: bool,
fn_selector: bool,
) -> Result<Vec<DynSolValue>> {
let func = Function::parse(sig)?;
let func = get_func(sig)?;
let calldata = hex::decode(calldata)?;

let mut calldata = calldata.as_slice();
Expand Down Expand Up @@ -56,7 +56,7 @@ pub fn abi_decode_calldata(
pub trait IntoFunction {
/// Consumes self and produces a function
///
/// # Panic
/// # Panics
///
/// This function does not return a Result, so it is expected that the consumer
/// uses it correctly so that it does not panic.
Expand All @@ -70,38 +70,30 @@ impl IntoFunction for Function {
}

impl IntoFunction for String {
#[track_caller]
fn into(self) -> Function {
IntoFunction::into(self.as_str())
}
}

impl<'a> IntoFunction for &'a str {
#[track_caller]
fn into(self) -> Function {
Function::parse(self).expect("could not parse function")
match get_func(self) {
Ok(func) => func,
Err(e) => panic!("could not parse function: {e}"),
}
}
}

/// Given a function signature string, it tries to parse it as a `Function`
pub fn get_func(sig: &str) -> Result<Function> {
if let Ok(func) = Function::parse(sig) {
Ok(func)
} else {
// Try to parse as human readable ABI.
let item = match AbiItem::parse(sig) {
Ok(item) => match item {
AbiItem::Function(func) => func,
_ => return Err(eyre::eyre!("Expected function, got {:?}", item)),
},
Err(e) => return Err(e.into()),
};
Ok(item.into_owned().to_owned())
}
Function::parse(sig).wrap_err("could not parse function signature")
}

/// Given an event signature string, it tries to parse it as a `Event`
pub fn get_event(sig: &str) -> Result<Event> {
let sig = sig.strip_prefix("event").unwrap_or(sig).trim();
Ok(Event::parse(sig)?)
Event::parse(sig).wrap_err("could not parse event signature")
}

/// Given an event without indexed parameters and a rawlog, it tries to return the event with the
Expand Down
4 changes: 2 additions & 2 deletions crates/evm/fuzz/src/strategies/param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,14 @@ pub fn fuzz_param_from_state(
#[cfg(test)]
mod tests {
use crate::strategies::{build_initial_state, fuzz_calldata, fuzz_calldata_from_state};
use alloy_json_abi::Function;
use foundry_common::abi::get_func;
use foundry_config::FuzzDictionaryConfig;
use revm::db::{CacheDB, EmptyDB};

#[test]
fn can_fuzz_array() {
let f = "testArray(uint64[2] calldata values)";
let func = Function::parse(f).unwrap();
let func = get_func(f).unwrap();
let db = CacheDB::new(EmptyDB::default());
let state = build_initial_state(&db, &FuzzDictionaryConfig::default());
let strat = proptest::strategy::Union::new_weighted(vec![
Expand Down
4 changes: 2 additions & 2 deletions crates/forge/bin/cmd/script/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use forge::{
};
use foundry_cli::opts::MultiWallet;
use foundry_common::{
abi::encode_function_args,
abi::{encode_function_args, get_func},
contracts::get_contract_name,
errors::UnlinkedByteCode,
evm::{Breakpoints, EvmArgs},
Expand Down Expand Up @@ -445,7 +445,7 @@ impl ScriptArgs {
///
/// Note: We assume that the `sig` is already stripped of its prefix, See [`ScriptArgs`]
fn get_method_and_calldata(&self, abi: &Abi) -> Result<(Function, Bytes)> {
let (func, data) = if let Ok(func) = Function::parse(&self.sig) {
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),
Expand Down