foundry_common_fmt/
dynamic.rs1use super::{format_int_exp, format_uint_exp};
2use alloy_dyn_abi::{DynSolType, DynSolValue};
3use alloy_primitives::hex;
4use eyre::Result;
5use serde_json::Value;
6use std::fmt;
7
8struct DynValueFormatter {
10 raw: bool,
11}
12
13impl DynValueFormatter {
14 fn value(&self, value: &DynSolValue, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16 match value {
17 DynSolValue::Address(inner) => write!(f, "{inner}"),
18 DynSolValue::Function(inner) => write!(f, "{inner}"),
19 DynSolValue::Bytes(inner) => f.write_str(&hex::encode_prefixed(inner)),
20 DynSolValue::FixedBytes(word, size) => {
21 f.write_str(&hex::encode_prefixed(&word[..*size]))
22 }
23 DynSolValue::Uint(inner, _) => {
24 if self.raw {
25 write!(f, "{inner}")
26 } else {
27 f.write_str(&format_uint_exp(*inner))
28 }
29 }
30 DynSolValue::Int(inner, _) => {
31 if self.raw {
32 write!(f, "{inner}")
33 } else {
34 f.write_str(&format_int_exp(*inner))
35 }
36 }
37 DynSolValue::Array(values) | DynSolValue::FixedArray(values) => {
38 f.write_str("[")?;
39 self.list(values, f)?;
40 f.write_str("]")
41 }
42 DynSolValue::Tuple(values) => self.tuple(values, f),
43 DynSolValue::String(inner) => {
44 if self.raw {
45 write!(f, "{}", inner.escape_debug())
46 } else {
47 write!(f, "{inner:?}") }
49 }
50 DynSolValue::Bool(inner) => write!(f, "{inner}"),
51 DynSolValue::CustomStruct { name, prop_names, tuple } => {
52 if self.raw {
53 return self.tuple(tuple, f);
54 }
55
56 f.write_str(name)?;
57
58 if prop_names.len() == tuple.len() {
59 f.write_str("({ ")?;
60
61 for (i, (prop_name, value)) in std::iter::zip(prop_names, tuple).enumerate() {
62 if i > 0 {
63 f.write_str(", ")?;
64 }
65 f.write_str(prop_name)?;
66 f.write_str(": ")?;
67 self.value(value, f)?;
68 }
69
70 f.write_str(" })")
71 } else {
72 self.tuple(tuple, f)
73 }
74 }
75 }
76 }
77
78 fn list(&self, values: &[DynSolValue], f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 for (i, value) in values.iter().enumerate() {
81 if i > 0 {
82 f.write_str(", ")?;
83 }
84 self.value(value, f)?;
85 }
86 Ok(())
87 }
88
89 fn tuple(&self, values: &[DynSolValue], f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 f.write_str("(")?;
92 self.list(values, f)?;
93 f.write_str(")")
94 }
95}
96
97struct DynValueDisplay<'a> {
99 value: &'a DynSolValue,
101 formatter: DynValueFormatter,
103}
104
105impl<'a> DynValueDisplay<'a> {
106 fn new(value: &'a DynSolValue, raw: bool) -> Self {
108 Self { value, formatter: DynValueFormatter { raw } }
109 }
110}
111
112impl fmt::Display for DynValueDisplay<'_> {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 self.formatter.value(self.value, f)
115 }
116}
117
118pub fn parse_tokens<'a, I: IntoIterator<Item = (&'a DynSolType, &'a str)>>(
120 params: I,
121) -> alloy_dyn_abi::Result<Vec<DynSolValue>> {
122 params.into_iter().map(|(param, value)| DynSolType::coerce_str(param, value)).collect()
123}
124
125pub fn format_tokens(tokens: &[DynSolValue]) -> impl Iterator<Item = String> + '_ {
127 tokens.iter().map(format_token)
128}
129
130pub fn format_tokens_raw(tokens: &[DynSolValue]) -> impl Iterator<Item = String> + '_ {
132 tokens.iter().map(format_token_raw)
133}
134
135pub fn format_token(value: &DynSolValue) -> String {
137 DynValueDisplay::new(value, false).to_string()
138}
139
140pub fn format_token_raw(value: &DynSolValue) -> String {
146 DynValueDisplay::new(value, true).to_string()
147}
148
149pub fn serialize_value_as_json(value: DynSolValue) -> Result<Value> {
151 match value {
152 DynSolValue::Bool(b) => Ok(Value::Bool(b)),
153 DynSolValue::String(s) => {
154 if let Ok(map) = serde_json::from_str(&s) {
157 Ok(Value::Object(map))
158 } else {
159 Ok(Value::String(s))
160 }
161 }
162 DynSolValue::Bytes(b) => Ok(Value::String(hex::encode_prefixed(b))),
163 DynSolValue::FixedBytes(b, size) => Ok(Value::String(hex::encode_prefixed(&b[..size]))),
164 DynSolValue::Int(i, _) => {
165 if let Ok(n) = i64::try_from(i) {
166 Ok(Value::Number(n.into()))
168 } else {
169 Ok(Value::String(i.to_string()))
172 }
173 }
174 DynSolValue::Uint(i, _) => {
175 if let Ok(n) = u64::try_from(i) {
176 Ok(Value::Number(n.into()))
178 } else {
179 Ok(Value::String(i.to_string()))
182 }
183 }
184 DynSolValue::Address(a) => Ok(Value::String(a.to_string())),
185 DynSolValue::Array(e) | DynSolValue::FixedArray(e) => {
186 Ok(Value::Array(e.into_iter().map(serialize_value_as_json).collect::<Result<_>>()?))
187 }
188 DynSolValue::CustomStruct { name: _, prop_names, tuple } => {
189 let values =
190 tuple.into_iter().map(serialize_value_as_json).collect::<Result<Vec<_>>>()?;
191 let map = prop_names.into_iter().zip(values).collect();
192
193 Ok(Value::Object(map))
194 }
195 DynSolValue::Tuple(values) => Ok(Value::Array(
196 values.into_iter().map(serialize_value_as_json).collect::<Result<_>>()?,
197 )),
198 DynSolValue::Function(_) => eyre::bail!("cannot serialize function pointer"),
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205 use alloy_primitives::{U256, address};
206
207 #[test]
208 fn parse_hex_uint() {
209 let ty = DynSolType::Uint(256);
210
211 let values = parse_tokens(std::iter::once((&ty, "100"))).unwrap();
212 assert_eq!(values, [DynSolValue::Uint(U256::from(100), 256)]);
213
214 let val: U256 = U256::from(100u64);
215 let hex_val = format!("0x{val:x}");
216 let values = parse_tokens(std::iter::once((&ty, hex_val.as_str()))).unwrap();
217 assert_eq!(values, [DynSolValue::Uint(U256::from(100), 256)]);
218 }
219
220 #[test]
221 fn format_addr() {
222 assert_eq!(
224 format_token(&DynSolValue::Address(address!(
225 "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
226 ))),
227 "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
228 );
229
230 assert_ne!(
232 format_token(&DynSolValue::Address(address!(
233 "0xFb6916095cA1Df60bb79ce92cE3EA74c37c5d359"
234 ))),
235 "0xFb6916095cA1Df60bb79ce92cE3EA74c37c5d359"
236 );
237 }
238}