Skip to content

Commit

Permalink
chore: better parse error messages (#6499)
Browse files Browse the repository at this point in the history
* chore: better parse error messages

* chore: clippy
  • Loading branch information
DaniPopes authored Dec 2, 2023
1 parent de73dde commit 87bf7e4
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 34 deletions.
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

0 comments on commit 87bf7e4

Please sign in to comment.