neo_solidity/cli/standard_json/
standard_json_helpers.rs

1pub(crate) fn keccak256_hex(input: &str) -> String {
2    let mut hasher = Keccak256::new();
3    hasher.update(input.as_bytes());
4    let digest = hasher.finalize();
5    hex::encode(digest)
6}
7
8pub(crate) fn hex_prefixed(value: &str) -> String {
9    if value.starts_with("0x") || value.starts_with("0X") {
10        value.to_string()
11    } else {
12        format!("0x{value}")
13    }
14}
15
16fn canonical_param_type(ty: &str) -> String {
17    ty.split_whitespace().next().unwrap_or_default().to_string()
18}
19
20fn build_contract_file_map(sources: &[(String, String, String)]) -> HashMap<String, String> {
21    let mut map = HashMap::new();
22
23    for (file_name, content, _) in sources {
24        if let Ok(contracts) = parse_source(content) {
25            for contract in contracts {
26                map.entry(contract.name.clone())
27                    .or_insert_with(|| file_name.clone());
28            }
29        }
30    }
31
32    map
33}
34
35fn unsupported_settings_warning(settings: &Value) -> Option<Value> {
36    let unsupported_keys: Vec<_> = match settings {
37        Value::Null => return None,
38        Value::Object(map) if map.is_empty() => return None,
39        Value::Object(map) => map
40            .keys()
41            .filter(|k| k.as_str() != "optimizer")
42            .cloned()
43            .collect(),
44        _ => vec!["<non-object settings>".to_string()],
45    };
46
47    if unsupported_keys.is_empty() {
48        None
49    } else {
50        Some(json!({
51            "component": "neo-solidity",
52            "severity": "warning",
53            "type": "UnsupportedSettings",
54            "formattedMessage": format!(
55                "Standard JSON settings contain unsupported keys: {:?}",
56                unsupported_keys
57            ),
58            "message": "Standard JSON settings are present but not fully supported; unsupported keys were ignored.",
59        }))
60    }
61}
62
63fn read_optimizer_level(settings: &Value) -> Option<u8> {
64    let optimizer = match settings {
65        Value::Object(map) => map.get("optimizer"),
66        _ => None,
67    };
68
69    match optimizer {
70        Some(Value::Bool(enabled)) => {
71            if *enabled {
72                Some(3)
73            } else {
74                Some(0)
75            }
76        }
77        Some(Value::Object(opt_map)) => {
78            if let Some(Value::Bool(enabled)) = opt_map.get("enabled") {
79                if !enabled {
80                    return Some(0);
81                }
82            }
83            if let Some(Value::Number(level_num)) = opt_map.get("level") {
84                if let Some(level) = level_num.as_u64() {
85                    return Some((level as u8).min(3));
86                }
87            }
88            if let Some(Value::Number(runs)) = opt_map.get("runs") {
89                if let Some(runs_val) = runs.as_u64() {
90                    return Some(if runs_val > 200 { 3 } else { 2 });
91                }
92            }
93            Some(3)
94        }
95        _ => None,
96    }
97}
98