diff --git a/crates/evm/src/executor/inspector/cheatcodes/parse.rs b/crates/evm/src/executor/inspector/cheatcodes/parse.rs index 904a3d502574e..d956731304bb3 100644 --- a/crates/evm/src/executor/inspector/cheatcodes/parse.rs +++ b/crates/evm/src/executor/inspector/cheatcodes/parse.rs @@ -1,7 +1,7 @@ use super::{fmt_err, Cheatcodes, Result}; use crate::abi::HEVMCalls; use ethers::{ - abi::{ParamType, Token}, + abi::{ethereum_types::FromDecStrErr, ParamType, Token}, prelude::*, }; use foundry_macros::UIfmt; @@ -48,32 +48,53 @@ fn parse_token(s: &str, ty: &ParamType) -> Result { } fn parse_int(s: &str) -> Result { - // hex string may start with "0x", "+0x", or "-0x" which needs to be stripped for + // Only parse hex strings prefixed by 0x or decimal integer strings + + // Hex string may start with "0x", "+0x", or "-0x" which needs to be stripped for // `I256::from_hex_str` if s.starts_with("0x") || s.starts_with("+0x") || s.starts_with("-0x") { - s.replacen("0x", "", 1).parse::().map_err(|err| err.to_string()) - } else { - match I256::from_dec_str(s) { + return s + .replacen("0x", "", 1) + .parse::() + .map_err(|err| err.to_string()) + .map(|v| v.into_raw()) + } + + // Decimal string may start with '+' or '-' followed by numeric characters + if s.chars().all(|c| c.is_numeric() || c == '+' || c == '-') { + return match I256::from_dec_str(s) { Ok(val) => Ok(val), Err(dec_err) => s.parse::().map_err(|hex_err| { format!("could not parse value as decimal or hex: {dec_err}, {hex_err}") }), } - } - .map(|v| v.into_raw()) + .map(|v| v.into_raw()) + }; + + // Throw if string doesn't conform to either of the two patterns + Err(ParseI256Error::InvalidDigit.to_string()) } fn parse_uint(s: &str) -> Result { + // Only parse hex strings prefixed by 0x or decimal numeric strings + + // Hex strings prefixed by 0x if s.starts_with("0x") { - s.parse::().map_err(|err| err.to_string()) - } else { - match U256::from_dec_str(s) { + return s.parse::().map_err(|err| err.to_string()) + }; + + // Decimal strings containing only numeric characters + if s.chars().all(|c| c.is_numeric()) { + return match U256::from_dec_str(s) { Ok(val) => Ok(val), Err(dec_err) => s.parse::().map_err(|hex_err| { format!("could not parse value as decimal or hex: {dec_err}, {hex_err}") }), } - } + }; + + // Throw if string doesn't conform to either of the two patterns + Err(FromDecStrErr::InvalidCharacter.to_string()) } fn parse_bytes(s: &str) -> Result, String> { @@ -128,7 +149,7 @@ mod tests { let decoded = U256::decode(&parsed).unwrap(); assert_eq!(val, decoded); - let parsed = parse(pk.strip_prefix("0x").unwrap(), &ParamType::Uint(256)).unwrap(); + let parsed = parse(pk, &ParamType::Uint(256)).unwrap(); let decoded = U256::decode(&parsed).unwrap(); assert_eq!(val, decoded); diff --git a/testdata/repros/Issue5808.t.sol b/testdata/repros/Issue5808.t.sol index 2c5845a0b1bcb..b721dfa105c02 100644 --- a/testdata/repros/Issue5808.t.sol +++ b/testdata/repros/Issue5808.t.sol @@ -9,9 +9,13 @@ contract Issue5808Test is DSTest { Vm constant vm = Vm(HEVM_ADDRESS); function testReadInt() public { - string memory json = '["ffffffff","00000010"]'; - int256[] memory ints = vm.parseJsonIntArray(json, ""); - assertEq(ints[0], 4294967295); - assertEq(ints[1], 10); + string memory str1 = '["ffffffff","00000010"]'; + vm.expectRevert(); + int256[] memory ints1 = vm.parseJsonIntArray(str1, ""); + + string memory str2 = '["0xffffffff","0x00000010"]'; + int256[] memory ints2 = vm.parseJsonIntArray(str2, ""); + assertEq(ints2[0], 4294967295); + assertEq(ints2[1], 10); } }