Skip to content

Commit 0543c04

Browse files
committed
fix(cast): consistent serialization of Uint/Ints depending on actual type
The current implementation dynamically tries to determine if the runtime value can fit in 64 bits, but this leads to inconsistent serialization. For instance if you were decoding an `uint[]`, some of the values that fit in 64 bits will serialize as number while others serialize as string making it require special handling on the user that is consuming the json. This change makes it so it uses the type information to determine the serialization. So the user will always know that specific types will always serialize to a number or a string depending on the number of bits that type uses.
1 parent 8dffbdc commit 0543c04

File tree

5 files changed

+16
-16
lines changed

5 files changed

+16
-16
lines changed

crates/cast/tests/cli/selectors.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ casttest!(event_decode_with_sig, |_prj, cmd| {
140140

141141
cmd.args(["--json"]).assert_success().stdout_eq(str![[r#"
142142
[
143-
78,
143+
"78",
144144
"0x0000000000000000000000000000000000D0004F"
145145
]
146146
@@ -168,7 +168,7 @@ casttest!(error_decode_with_sig, |_prj, cmd| {
168168

169169
cmd.args(["--json"]).assert_success().stdout_eq(str![[r#"
170170
[
171-
101,
171+
"101",
172172
"0x0000000000000000000000000000000000D0004F"
173173
]
174174

crates/cheatcodes/src/json.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -590,10 +590,10 @@ fn _json_value_to_token(value: &Value, defs: &StructDefinitions) -> Result<DynSo
590590
}
591591

592592
if let Ok(n) = s.parse() {
593-
return Ok(DynSolValue::Uint(n, 256));
593+
return Ok(DynSolValue::Uint(n, 64));
594594
}
595595
if let Ok(n) = s.parse() {
596-
return Ok(DynSolValue::Int(n, 256));
596+
return Ok(DynSolValue::Int(n, 64));
597597
}
598598
}
599599
}
@@ -1064,7 +1064,7 @@ mod tests {
10641064
// Serialize the value to JSON and verify that the order is preserved.
10651065
let json_value = serialize_value_as_json(item_struct, Some(&struct_defs.into())).unwrap();
10661066
let json_string = serde_json::to_string(&json_value).unwrap();
1067-
assert_eq!(json_string, r#"{"name":"Test Item","id":123,"active":true}"#);
1067+
assert_eq!(json_string, r#"{"name":"Test Item","id":"123","active":true}"#);
10681068
}
10691069

10701070
#[test]
@@ -1100,7 +1100,7 @@ mod tests {
11001100
let json_string = serde_json::to_string(&json_value).unwrap();
11011101
assert_eq!(
11021102
json_string,
1103-
format!(r#"{{"owner":"{owner_address}","balance":5000,"id":"{wallet_id}"}}"#)
1103+
format!(r#"{{"owner":"{owner_address}","balance":"5000","id":"{wallet_id}"}}"#)
11041104
);
11051105

11061106
// Resolve the type, which should also respect the struct definition order.

crates/common/fmt/src/dynamic.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -175,20 +175,20 @@ fn _serialize_value_as_json(value: DynSolValue, defs: &StructDefinitions) -> Res
175175
}
176176
DynSolValue::Bytes(b) => Ok(Value::String(hex::encode_prefixed(b))),
177177
DynSolValue::FixedBytes(b, size) => Ok(Value::String(hex::encode_prefixed(&b[..size]))),
178-
DynSolValue::Int(i, _) => {
179-
if let Ok(n) = i64::try_from(i) {
178+
DynSolValue::Int(i, bits) => {
179+
if bits <= 64 {
180180
// Use `serde_json::Number` if the number can be accurately represented.
181-
Ok(Value::Number(n.into()))
181+
Ok(Value::Number(TryInto::<i64>::try_into(i)?.into()))
182182
} else {
183183
// Otherwise, fallback to its string representation to preserve precision and ensure
184184
// compatibility with alloy's `DynSolType` coercion.
185185
Ok(Value::String(i.to_string()))
186186
}
187187
}
188-
DynSolValue::Uint(i, _) => {
189-
if let Ok(n) = u64::try_from(i) {
188+
DynSolValue::Uint(i, bits) => {
189+
if bits <= 64 {
190190
// Use `serde_json::Number` if the number can be accurately represented.
191-
Ok(Value::Number(n.into()))
191+
Ok(Value::Number(TryInto::<u64>::try_into(i)?.into()))
192192
} else {
193193
// Otherwise, fallback to its string representation to preserve precision and ensure
194194
// compatibility with alloy's `DynSolType` coercion.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
2-
"a": 123,
2+
"a": "123",
33
"b": "test",
44
"c": {
5-
"a": 123,
5+
"a": "123",
66
"b": "test"
77
}
88
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
a = 123
1+
a = "123"
22
b = "test"
33

44
[c]
5-
a = 123
5+
a = "123"
66
b = "test"

0 commit comments

Comments
 (0)