From 62c1ddea5d907158add8b2384769c37dbb0e9ded Mon Sep 17 00:00:00 2001 From: bernard-wagner Date: Fri, 9 Feb 2024 13:32:16 +0200 Subject: [PATCH] feat(cast): abi-encode-packed --- crates/cast/bin/main.rs | 8 ++++++-- crates/cast/bin/opts.rs | 4 ++++ crates/cast/src/lib.rs | 32 ++++++++++++++++++++++++++++++++ crates/common/src/abi.rs | 17 +++++++++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index c4ee0e56388e..93c686cb31e0 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -160,8 +160,12 @@ async fn main() -> Result<()> { let tokens = format_tokens(&tokens); tokens.for_each(|t| println!("{t}")); } - CastSubcommand::AbiEncode { sig, args } => { - println!("{}", SimpleCast::abi_encode(&sig, &args)?); + CastSubcommand::AbiEncode { sig, packed, args } => { + if !packed { + println!("{}", SimpleCast::abi_encode(&sig, &args)?); + } else { + println!("{}", SimpleCast::abi_encode_packed(&sig, &args)?); + } } CastSubcommand::CalldataDecode { sig, calldata } => { let tokens = SimpleCast::calldata_decode(&sig, &calldata, true)?; diff --git a/crates/cast/bin/opts.rs b/crates/cast/bin/opts.rs index 2f09c2534830..9cce3349474f 100644 --- a/crates/cast/bin/opts.rs +++ b/crates/cast/bin/opts.rs @@ -491,6 +491,10 @@ pub enum CastSubcommand { /// The function signature. sig: String, + /// Whether to use packed encoding. + #[clap(long)] + packed: bool, + /// The arguments of the function. #[clap(allow_hyphen_values = true)] args: Vec, diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 0c941913cf14..7d701cb5095c 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -36,6 +36,7 @@ use std::{ use tokio::signal::ctrl_c; use tx::{TxBuilderOutput, TxBuilderPeekOutput}; +use foundry_common::abi::encode_function_args_packed; pub use foundry_evm::*; pub use rusoto_core::{ credential::ChainProvider as AwsChainProvider, region::Region as AwsRegion, @@ -1551,6 +1552,37 @@ impl SimpleCast { Ok(format!("0x{encoded}")) } + /// Performs packed ABI encoding based off of the function signature or tuple. + /// + /// # Examplez + /// + /// ``` + /// use cast::SimpleCast as Cast; + /// + /// assert_eq!( + /// "0x0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000012c00000000000000c8", + /// Cast::abi_encode_packed("(uint128[] a, uint64 b)", &["[100, 300]", "200"]).unwrap().as_str() + /// ); + /// + /// assert_eq!( + /// "0x8dbd1b711dc621e1404633da156fcc779e1c6f3e68656c6c6f20776f726c64", + /// Cast::abi_encode_packed("foo(address a, string b)", &["0x8dbd1b711dc621e1404633da156fcc779e1c6f3e", "hello world"]).unwrap().as_str() + /// ); + /// # Ok::<_, eyre::Report>(()) + /// ``` + pub fn abi_encode_packed(sig: &str, args: &[impl AsRef]) -> Result { + // If the signature is a tuple, we need to prefix it to make it a function + let sig = + if sig.trim_start().starts_with('(') { format!("foo{sig}") } else { sig.to_string() }; + + let func = get_func(sig.as_str())?; + let encoded = match encode_function_args_packed(&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), + }; + Ok(format!("0x{encoded}")) + } + /// Performs ABI encoding to produce the hexadecimal calldata with the given arguments. /// /// # Example diff --git a/crates/common/src/abi.rs b/crates/common/src/abi.rs index 011f51cb807c..fc3e8083e4a3 100644 --- a/crates/common/src/abi.rs +++ b/crates/common/src/abi.rs @@ -21,6 +21,23 @@ where func.abi_encode_input(params.as_slice()).map_err(Into::into) } +/// Given a function and a vector of string arguments, it proceeds to convert the args to alloy +/// [DynSolValue]s and encode them using the packed encoding. +pub fn encode_function_args_packed(func: &Function, args: I) -> Result> +where + I: IntoIterator, + S: AsRef, +{ + let params: Vec> = std::iter::zip(&func.inputs, args) + .map(|(input, arg)| coerce_value(&input.selector_type(), arg.as_ref())) + .collect::>>()? + .into_iter() + .map(|v| v.abi_encode_packed()) + .collect(); + + Ok(params.concat()) +} + /// Decodes the calldata of the function pub fn abi_decode_calldata( sig: &str,