bug(`cheatcodes`): `vm.parseJsonUint` can't parse numbers with scientific notation
Component
Forge
Have you ensured that all of these are up to date?
- [X] Foundry
- [ ] Foundryup
What version of Foundry are you on?
forge 0.2.0 (VERGEN_IDEMPOTENT_OUTPUT 2024-07-15T11:19:03.935375000Z)
What command(s) is the bug in?
forge script
Operating System
macOS (Apple Silicon)
Describe the bug
With the following JSON:
"1284": {
"addRewardInfo": {
"amount": 74258225772486694040708e18,
"endTimestamp": 1725593400,
"pid": 15,
"rewardPerSec": 0.03069536448928848133e18,
"target": "STELLASWAP_REWARDER"
},
...
Using vm.parseJsonUint
string memory key = ".1284.addRewardInfo.amount";
uint parsedUint = vm.parseJsonUint(data, key);
Output:
├─ [0] VM::parseJsonUint("<stringified JSON>", ".1284.addRewardInfo.amount") [staticcall]
│ └─ ← [Revert] failed parsing "74258.225772486694040708e18" as type `uint256`: parser error:
74258.225772486694040708e18
When using vm.parseJson it's parse just fine
I tried to replicate the issue but did not receive the same error message. Instead, I encountered the following: failed parsing "74258225772486694040708e18" as type uint256: missing hex prefix ("0x") for hex string. Nevertheless, I think it's something that needs to be fixed. Am I overlooking something? 👀
Expand to see the test contract
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.18;
import "ds-test/test.sol";
import "cheats/Vm.sol";
// https://github.com/foundry-rs/foundry/issues/8566
contract Issue8566Test is DSTest {
Vm constant vm = Vm(HEVM_ADDRESS);
function testParseJsonUint() public {
string memory data = "{\"helper\": {\"myStruct\": {\"amount\": 74258225772486694040708000000000000000000000}}}";
string memory key = ".helper.myStruct.amount";
uint parsedUint = vm.parseJsonUint(data, key);
assertEq(parsedUint, 74258225772486694040708000000000000000000000);
}
function testParseJsonUint2() public {
string memory data = "{\"helper\": {\"myStruct\": {\"amount\": 74258225772486694040708e18}}}";
string memory key = ".helper.myStruct.amount";
uint parsedUint = vm.parseJsonUint(data, key);
assertEq(parsedUint, 74258225772486694040708e18);
}
function testParseJson() pure public {
string memory data = "{\"helper\": {\"myStruct\": {\"amount\": 74258225772486694040708000000000000000000000}}}";
string memory key = ".helper.myStruct.amount";
vm.parseJson(data, key);
}
function testParseJson2() pure public {
string memory data = "{\"helper\": {\"myStruct\": {\"amount\": 74258225772486694040708e18}}}";
string memory key = ".helper.myStruct.amount";
vm.parseJson(data, key);
}
}
Expand to see the output of the test
$ forge --version
forge 0.2.0 (6de15b0 2024-07-15T00:22:57.628408000Z)
$ forge test --match-contract Issue8566Test -vvvv
[⠊] Compiling...
[⠢] Compiling 1 files with Solc 0.8.18
[⠆] Solc 0.8.18 finished in 118.38ms
Compiler run successful with warnings:
Ran 4 tests for default/repros/Issue8566.t.sol:Issue8566Test
[PASS] testParseJson() (gas: 4344)
[PASS] testParseJson2() (gas: 4246)
[PASS] testParseJsonUint() (gas: 4001)
[FAIL. Reason: failed parsing "74258225772486694040708e18" as type `uint256`: missing hex prefix ("0x") for hex string] testParseJsonUint2() (gas: 3736)
Traces:
[3736] DefaultTestContract::testParseJsonUint2()
├─ [0] VM::parseJsonUint("<stringified JSON>", ".helper.myStruct.amount") [staticcall]
│ └─ ← [Revert] failed parsing "74258225772486694040708e18" as type `uint256`: missing hex prefix ("0x") for hex string
└─ ← [Revert] failed parsing "74258225772486694040708e18" as type `uint256`: missing hex prefix ("0x") for hex string
Suite result: FAILED. 3 passed; 1 failed; 0 skipped; finished in 737.54µs (820.13µs CPU time)
Ran 1 test suite in 175.55ms (737.54µs CPU time): 3 tests passed, 1 failed, 0 skipped (4 total tests)
Failing tests:
Encountered 1 failing test in default/repros/Issue8566.t.sol:Issue8566Test
[FAIL. Reason: failed parsing "74258225772486694040708e18" as type `uint256`: missing hex prefix ("0x") for hex string] testParseJsonUint2() (gas: 3736)
Encountered a total of 1 failing tests, 3 tests succeeded
The error is raised here
// More lenient parsers than `coerce_str`.
fn parse_value_fallback(s: &str, ty: &DynSolType) -> Option<Result<DynSolValue, &'static str>> {
match ty {
DynSolType::Bool => {
let b = match s {
"1" => true,
"0" => false,
s if s.eq_ignore_ascii_case("true") => true,
s if s.eq_ignore_ascii_case("false") => false,
_ => return None,
};
return Some(Ok(DynSolValue::Bool(b)));
}
DynSolType::Int(_) |
DynSolType::Uint(_) |
DynSolType::FixedBytes(_) |
DynSolType::Bytes => {
if !s.starts_with("0x") && s.chars().all(|c| c.is_ascii_hexdigit()) {
return Some(Err("missing hex prefix (\"0x\") for hex string"));
}
}
_ => {}
}
None
}
the fallback is not able to convert scientific notation to U256. @zerosnacks should we fix this here in forge or should we open a pull request to alloy's types to fix this?
Hi @francesco-gaglione, thanks for narrowing this down. I think the correct place to implement this would be alloy/core.
I am applying to this issue via OnlyDust platform.
My background and how it can be leveraged
I have been working as fullstack developer for WEB2 for 3 years, I'll like to explore WEB3 world so looks like a fun and benefit project to start with 🙂
potentially need to move this issue to https://github.com/alloy-rs/core
keeping this open until alloy issue is created
Opened https://github.com/alloy-rs/core/issues/816, but I would still like to keep this open for when this lands in Foundry.
May I be assigned to this?