Skip to content

Commit e1d12ce

Browse files
Fix/cast abi strict args (#11189)
* fix(encode-args-length mismatch): validate inputs length match args length before encode args * feat(encode-args): add test to length validation * feat(abi-encode): fit args validation error message and add validation for packaged abi encode * chore: clippy * fmt --------- Co-authored-by: DaniPopes <[email protected]>
1 parent 4d8631d commit e1d12ce

File tree

2 files changed

+57
-8
lines changed

2 files changed

+57
-8
lines changed

crates/cast/src/lib.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,10 +1809,7 @@ impl SimpleCast {
18091809
let func = get_func(sig)?;
18101810
match encode_function_args(&func, args) {
18111811
Ok(res) => Ok(hex::encode_prefixed(&res[4..])),
1812-
Err(e) => eyre::bail!(
1813-
"Could not ABI encode the function and arguments. Did you pass in the right types?\nError\n{}",
1814-
e
1815-
),
1812+
Err(e) => eyre::bail!("Could not ABI encode the function and arguments: {e}"),
18161813
}
18171814
}
18181815

@@ -1842,10 +1839,7 @@ impl SimpleCast {
18421839
let func = get_func(sig.as_str())?;
18431840
let encoded = match encode_function_args_packed(&func, args) {
18441841
Ok(res) => hex::encode(res),
1845-
Err(e) => eyre::bail!(
1846-
"Could not ABI encode the function and arguments. Did you pass in the right types?\nError\n{}",
1847-
e
1848-
),
1842+
Err(e) => eyre::bail!("Could not ABI encode the function and arguments: {e}"),
18491843
};
18501844
Ok(format!("0x{encoded}"))
18511845
}

crates/common/src/abi.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ where
1515
I: IntoIterator<Item = S>,
1616
S: AsRef<str>,
1717
{
18+
let args: Vec<S> = args.into_iter().collect();
19+
20+
if inputs.len() != args.len() {
21+
eyre::bail!("encode length mismatch: expected {} types, got {}", inputs.len(), args.len())
22+
}
23+
1824
std::iter::zip(inputs, args)
1925
.map(|(input, arg)| coerce_value(&input.selector_type(), arg.as_ref()))
2026
.collect()
@@ -47,6 +53,16 @@ where
4753
I: IntoIterator<Item = S>,
4854
S: AsRef<str>,
4955
{
56+
let args: Vec<S> = args.into_iter().collect();
57+
58+
if func.inputs.len() != args.len() {
59+
eyre::bail!(
60+
"encode length mismatch: expected {} types, got {}",
61+
func.inputs.len(),
62+
args.len(),
63+
);
64+
}
65+
5066
let params: Vec<Vec<u8>> = std::iter::zip(&func.inputs, args)
5167
.map(|(input, arg)| coerce_value(&input.selector_type(), arg.as_ref()))
5268
.collect::<Result<Vec<_>>>()?
@@ -257,4 +273,43 @@ mod tests {
257273
assert_eq!(parsed.indexed[1], DynSolValue::Uint(U256::from_be_bytes([3; 32]), 256));
258274
assert_eq!(parsed.indexed[2], DynSolValue::Address(Address::from_word(param2)));
259275
}
276+
277+
#[test]
278+
fn test_encode_args_length_validation() {
279+
use alloy_json_abi::Param;
280+
281+
let params = vec![
282+
Param {
283+
name: "a".to_string(),
284+
ty: "uint256".to_string(),
285+
internal_type: None,
286+
components: vec![],
287+
},
288+
Param {
289+
name: "b".to_string(),
290+
ty: "address".to_string(),
291+
internal_type: None,
292+
components: vec![],
293+
},
294+
];
295+
296+
// Less arguments than parameters
297+
let args = vec!["1"];
298+
let res = encode_args(&params, &args);
299+
assert!(res.is_err());
300+
assert!(format!("{}", res.unwrap_err()).contains("encode length mismatch"));
301+
302+
// Exact number of arguments and parameters
303+
let args = vec!["1", "0x0000000000000000000000000000000000000001"];
304+
let res = encode_args(&params, &args);
305+
assert!(res.is_ok());
306+
let values = res.unwrap();
307+
assert_eq!(values.len(), 2);
308+
309+
// More arguments than parameters
310+
let args = vec!["1", "0x0000000000000000000000000000000000000001", "extra"];
311+
let res = encode_args(&params, &args);
312+
assert!(res.is_err());
313+
assert!(format!("{}", res.unwrap_err()).contains("encode length mismatch"));
314+
}
260315
}

0 commit comments

Comments
 (0)