rain_metadata/solc/
mod.rs1use serde_json::Value;
2use strum::EnumString;
3use crate::error::Error;
4
5#[derive(Copy, Clone, EnumString, strum::Display)]
7#[strum(serialize_all = "kebab-case")]
8pub enum ArtifactComponent {
9 Abi,
10 Bytecode,
11 DeployedBytecode,
12}
13
14impl ArtifactComponent {
15 pub fn artifact_key(self) -> &'static str {
17 match self {
18 ArtifactComponent::Abi => "abi",
19 ArtifactComponent::Bytecode => "bytecode",
20 ArtifactComponent::DeployedBytecode => "deployedBytecode",
21 }
22 }
23}
24
25pub fn extract_artifact_component_json(
31 component: ArtifactComponent,
32 data: &[u8],
33) -> Result<Value, Error> {
34 let json = serde_json::from_str::<Value>(std::str::from_utf8(data)?)?;
35 let key = component.artifact_key();
36 json.get(key)
37 .cloned()
38 .ok_or_else(|| Error::InvalidInput(format!("artifact has no \"{}\" component", key)))
39}
40
41#[cfg(all(test, not(target_family = "wasm")))]
42mod tests {
43 use super::*;
44
45 fn artifact_json() -> Vec<u8> {
46 serde_json::json!({
47 "abi": [{ "type": "function", "name": "foo" }],
48 "bytecode": { "object": "0x6001" },
49 "deployedBytecode": { "object": "0x6002" }
50 })
51 .to_string()
52 .into_bytes()
53 }
54
55 #[test]
57 fn test_extract_each_component() {
58 let data = artifact_json();
59 assert_eq!(
60 extract_artifact_component_json(ArtifactComponent::Abi, &data).unwrap(),
61 serde_json::json!([{ "type": "function", "name": "foo" }])
62 );
63 assert_eq!(
64 extract_artifact_component_json(ArtifactComponent::Bytecode, &data).unwrap(),
65 serde_json::json!({ "object": "0x6001" })
66 );
67 assert_eq!(
68 extract_artifact_component_json(ArtifactComponent::DeployedBytecode, &data).unwrap(),
69 serde_json::json!({ "object": "0x6002" })
70 );
71 }
72
73 #[test]
76 fn test_artifact_key_per_component() {
77 assert_eq!(ArtifactComponent::Abi.artifact_key(), "abi");
78 assert_eq!(ArtifactComponent::Bytecode.artifact_key(), "bytecode");
79 assert_eq!(
80 ArtifactComponent::DeployedBytecode.artifact_key(),
81 "deployedBytecode"
82 );
83 }
84
85 #[test]
88 fn test_missing_component_errors() {
89 for (component, key) in [
90 (ArtifactComponent::Abi, "abi"),
91 (ArtifactComponent::Bytecode, "bytecode"),
92 (ArtifactComponent::DeployedBytecode, "deployedBytecode"),
93 ] {
94 let err = extract_artifact_component_json(component, b"{}").unwrap_err();
95 assert_eq!(
96 err.to_string(),
97 format!("invalid input: artifact has no \"{}\" component", key)
98 );
99 }
100 }
101
102 #[test]
105 fn test_missing_component_errors_beside_present_siblings() {
106 let data = br#"{"bytecode":{"object":"0x60"},"deployedBytecode":{"object":"0x60"}}"#;
107 assert!(extract_artifact_component_json(ArtifactComponent::Abi, data).is_err());
108 assert!(extract_artifact_component_json(ArtifactComponent::Bytecode, data).is_ok());
109 }
110
111 #[test]
114 fn test_explicit_null_component_is_returned() {
115 assert_eq!(
116 extract_artifact_component_json(ArtifactComponent::Abi, br#"{"abi":null}"#).unwrap(),
117 Value::Null
118 );
119 }
120
121 #[test]
123 fn test_non_object_artifact_errors() {
124 assert!(extract_artifact_component_json(ArtifactComponent::Abi, b"[]").is_err());
125 assert!(extract_artifact_component_json(ArtifactComponent::Abi, b"null").is_err());
126 assert!(extract_artifact_component_json(ArtifactComponent::Abi, br#""abi""#).is_err());
127 }
128
129 #[test]
131 fn test_invalid_input_errors() {
132 assert!(extract_artifact_component_json(ArtifactComponent::Abi, &[0xff, 0xfe]).is_err());
133 assert!(extract_artifact_component_json(ArtifactComponent::Abi, b"not json").is_err());
134 }
135}