1use crate::{
4 bytecode::{
5 Bytecode, BytecodeObject, CompactBytecode, CompactDeployedBytecode, DeployedBytecode,
6 },
7 serde_helpers, DevDoc, Evm, Ewasm, LosslessMetadata, Offsets, StorageLayout, UserDoc,
8};
9use alloy_json_abi::JsonAbi;
10use alloy_primitives::Bytes;
11use serde::{Deserialize, Serialize};
12use std::{borrow::Cow, collections::BTreeMap};
13
14#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
16#[serde(rename_all = "camelCase")]
17pub struct Contract {
18 pub abi: Option<JsonAbi>,
21 #[serde(
22 default,
23 skip_serializing_if = "Option::is_none",
24 with = "serde_helpers::json_string_opt"
25 )]
26 pub metadata: Option<LosslessMetadata>,
27 #[serde(default)]
28 pub userdoc: UserDoc,
29 #[serde(default)]
30 pub devdoc: DevDoc,
31 #[serde(default, skip_serializing_if = "Option::is_none")]
32 pub ir: Option<String>,
33 #[serde(default, skip_serializing_if = "StorageLayout::is_empty")]
34 pub storage_layout: StorageLayout,
35 #[serde(default, skip_serializing_if = "StorageLayout::is_empty")]
36 pub transient_storage_layout: StorageLayout,
37 #[serde(default, skip_serializing_if = "Option::is_none")]
39 pub evm: Option<Evm>,
40 #[serde(default, skip_serializing_if = "Option::is_none")]
42 pub ewasm: Option<Ewasm>,
43 #[serde(default, skip_serializing_if = "Option::is_none")]
44 pub ir_optimized: Option<String>,
45 #[serde(default, skip_serializing_if = "Option::is_none")]
46 pub ir_optimized_ast: Option<serde_json::Value>,
47}
48
49impl<'a> From<&'a Contract> for CompactContractBytecodeCow<'a> {
50 fn from(artifact: &'a Contract) -> Self {
51 let (bytecode, deployed_bytecode) = if let Some(evm) = &artifact.evm {
52 (
53 evm.bytecode.clone().map(Into::into).map(Cow::Owned),
54 evm.deployed_bytecode.clone().map(Into::into).map(Cow::Owned),
55 )
56 } else {
57 (None, None)
58 };
59 CompactContractBytecodeCow {
60 abi: artifact.abi.as_ref().map(Cow::Borrowed),
61 bytecode,
62 deployed_bytecode,
63 }
64 }
65}
66
67#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
72pub struct ContractBytecode {
73 pub abi: Option<JsonAbi>,
76 #[serde(default, skip_serializing_if = "Option::is_none")]
77 pub bytecode: Option<Bytecode>,
78 #[serde(default, skip_serializing_if = "Option::is_none")]
79 pub deployed_bytecode: Option<DeployedBytecode>,
80}
81
82impl ContractBytecode {
83 #[track_caller]
89 pub fn unwrap(self) -> ContractBytecodeSome {
90 ContractBytecodeSome {
91 abi: self.abi.unwrap(),
92 bytecode: self.bytecode.unwrap(),
93 deployed_bytecode: self.deployed_bytecode.unwrap(),
94 }
95 }
96
97 pub fn all_link_references(&self) -> BTreeMap<String, BTreeMap<String, Vec<Offsets>>> {
99 let mut links = BTreeMap::new();
100 if let Some(bcode) = &self.bytecode {
101 links.extend(bcode.link_references.clone());
102 }
103
104 if let Some(d_bcode) = &self.deployed_bytecode {
105 if let Some(bcode) = &d_bcode.bytecode {
106 links.extend(bcode.link_references.clone());
107 }
108 }
109 links
110 }
111}
112
113impl From<Contract> for ContractBytecode {
114 fn from(c: Contract) -> Self {
115 let (bytecode, deployed_bytecode) = if let Some(evm) = c.evm {
116 (evm.bytecode, evm.deployed_bytecode)
117 } else {
118 (None, None)
119 };
120
121 Self { abi: c.abi, bytecode, deployed_bytecode }
122 }
123}
124
125#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
130#[serde(rename_all = "camelCase")]
131pub struct CompactContractBytecode {
132 pub abi: Option<JsonAbi>,
135 #[serde(default, skip_serializing_if = "Option::is_none")]
136 pub bytecode: Option<CompactBytecode>,
137 #[serde(default, skip_serializing_if = "Option::is_none")]
138 pub deployed_bytecode: Option<CompactDeployedBytecode>,
139}
140
141impl CompactContractBytecode {
142 pub fn all_link_references(&self) -> BTreeMap<String, BTreeMap<String, Vec<Offsets>>> {
144 let mut links = BTreeMap::new();
145 if let Some(bcode) = &self.bytecode {
146 links.extend(bcode.link_references.clone());
147 }
148
149 if let Some(d_bcode) = &self.deployed_bytecode {
150 if let Some(bcode) = &d_bcode.bytecode {
151 links.extend(bcode.link_references.clone());
152 }
153 }
154 links
155 }
156}
157
158impl<'a> From<&'a CompactContractBytecode> for CompactContractBytecodeCow<'a> {
159 fn from(artifact: &'a CompactContractBytecode) -> Self {
160 CompactContractBytecodeCow {
161 abi: artifact.abi.as_ref().map(Cow::Borrowed),
162 bytecode: artifact.bytecode.as_ref().map(Cow::Borrowed),
163 deployed_bytecode: artifact.deployed_bytecode.as_ref().map(Cow::Borrowed),
164 }
165 }
166}
167
168impl From<Contract> for CompactContractBytecode {
169 fn from(c: Contract) -> Self {
170 let (bytecode, deployed_bytecode) = if let Some(evm) = c.evm {
171 let evm = evm.into_compact();
172 (evm.bytecode, evm.deployed_bytecode)
173 } else {
174 (None, None)
175 };
176
177 Self { abi: c.abi, bytecode, deployed_bytecode }
178 }
179}
180
181impl From<ContractBytecode> for CompactContractBytecode {
182 fn from(c: ContractBytecode) -> Self {
183 let (maybe_bcode, maybe_runtime) = match (c.bytecode, c.deployed_bytecode) {
184 (Some(bcode), Some(dbcode)) => (Some(bcode.into()), Some(dbcode.into())),
185 (None, Some(dbcode)) => (None, Some(dbcode.into())),
186 (Some(bcode), None) => (Some(bcode.into()), None),
187 (None, None) => (None, None),
188 };
189 Self { abi: c.abi, bytecode: maybe_bcode, deployed_bytecode: maybe_runtime }
190 }
191}
192
193impl From<CompactContractBytecode> for ContractBytecode {
194 fn from(c: CompactContractBytecode) -> Self {
195 let (maybe_bcode, maybe_runtime) = match (c.bytecode, c.deployed_bytecode) {
196 (Some(bcode), Some(dbcode)) => (Some(bcode.into()), Some(dbcode.into())),
197 (None, Some(dbcode)) => (None, Some(dbcode.into())),
198 (Some(bcode), None) => (Some(bcode.into()), None),
199 (None, None) => (None, None),
200 };
201 Self { abi: c.abi, bytecode: maybe_bcode, deployed_bytecode: maybe_runtime }
202 }
203}
204
205#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
207#[serde(rename_all = "camelCase")]
208pub struct CompactContractBytecodeCow<'a> {
209 pub abi: Option<Cow<'a, JsonAbi>>,
210 #[serde(default, skip_serializing_if = "Option::is_none")]
211 pub bytecode: Option<Cow<'a, CompactBytecode>>,
212 #[serde(default, skip_serializing_if = "Option::is_none")]
213 pub deployed_bytecode: Option<Cow<'a, CompactDeployedBytecode>>,
214}
215
216impl From<CompactContractBytecodeCow<'_>> for CompactContract {
217 fn from(value: CompactContractBytecodeCow<'_>) -> Self {
218 Self {
219 abi: value.abi.map(Cow::into_owned),
220 bin: value.bytecode.map(|bytecode| match bytecode {
221 Cow::Owned(bytecode) => bytecode.object,
222 Cow::Borrowed(bytecode) => bytecode.object.clone(),
223 }),
224 bin_runtime: value
225 .deployed_bytecode
226 .and_then(|bytecode| match bytecode {
227 Cow::Owned(bytecode) => bytecode.bytecode,
228 Cow::Borrowed(bytecode) => bytecode.bytecode.clone(),
229 })
230 .map(|bytecode| bytecode.object),
231 }
232 }
233}
234
235impl From<CompactContractBytecodeCow<'_>> for CompactContractBytecode {
236 fn from(value: CompactContractBytecodeCow<'_>) -> Self {
237 Self {
238 abi: value.abi.map(Cow::into_owned),
239 bytecode: value.bytecode.map(Cow::into_owned),
240 deployed_bytecode: value.deployed_bytecode.map(Cow::into_owned),
241 }
242 }
243}
244
245impl<'a> From<&'a CompactContractBytecodeCow<'_>> for CompactContractBytecodeCow<'a> {
246 fn from(value: &'a CompactContractBytecodeCow<'_>) -> Self {
247 Self {
248 abi: value.abi.as_ref().map(|x| Cow::Borrowed(&**x)),
249 bytecode: value.bytecode.as_ref().map(|x| Cow::Borrowed(&**x)),
250 deployed_bytecode: value.deployed_bytecode.as_ref().map(|x| Cow::Borrowed(&**x)),
251 }
252 }
253}
254
255#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
260pub struct ContractBytecodeSome {
261 pub abi: JsonAbi,
262 pub bytecode: Bytecode,
263 pub deployed_bytecode: DeployedBytecode,
264}
265
266impl TryFrom<ContractBytecode> for ContractBytecodeSome {
267 type Error = ContractBytecode;
268
269 fn try_from(value: ContractBytecode) -> Result<Self, Self::Error> {
270 if value.abi.is_none() || value.bytecode.is_none() || value.deployed_bytecode.is_none() {
271 return Err(value);
272 }
273 Ok(value.unwrap())
274 }
275}
276
277#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
279pub struct CompactContractSome {
280 pub abi: JsonAbi,
283 pub bin: BytecodeObject,
284 #[serde(rename = "bin-runtime")]
285 pub bin_runtime: BytecodeObject,
286}
287
288impl TryFrom<CompactContract> for CompactContractSome {
289 type Error = CompactContract;
290
291 fn try_from(value: CompactContract) -> Result<Self, Self::Error> {
292 if value.abi.is_none() || value.bin.is_none() || value.bin_runtime.is_none() {
293 return Err(value);
294 }
295 Ok(value.unwrap())
296 }
297}
298
299#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
303pub struct CompactContract {
304 pub abi: Option<JsonAbi>,
307 #[serde(default, skip_serializing_if = "Option::is_none")]
308 pub bin: Option<BytecodeObject>,
309 #[serde(default, rename = "bin-runtime", skip_serializing_if = "Option::is_none")]
310 pub bin_runtime: Option<BytecodeObject>,
311}
312
313impl CompactContract {
314 pub fn into_parts(self) -> (Option<JsonAbi>, Option<Bytes>, Option<Bytes>) {
316 (
317 self.abi,
318 self.bin.and_then(|bin| bin.into_bytes()),
319 self.bin_runtime.and_then(|bin| bin.into_bytes()),
320 )
321 }
322
323 pub fn into_parts_or_default(self) -> (JsonAbi, Bytes, Bytes) {
327 (
328 self.abi.unwrap_or_default(),
329 self.bin.and_then(|bin| bin.into_bytes()).unwrap_or_default(),
330 self.bin_runtime.and_then(|bin| bin.into_bytes()).unwrap_or_default(),
331 )
332 }
333
334 #[track_caller]
340 pub fn unwrap(self) -> CompactContractSome {
341 CompactContractSome {
342 abi: self.abi.unwrap(),
343 bin: self.bin.unwrap(),
344 bin_runtime: self.bin_runtime.unwrap(),
345 }
346 }
347
348 pub fn unwrap_or_default(self) -> CompactContractSome {
353 CompactContractSome {
354 abi: self.abi.unwrap_or_default(),
355 bin: self.bin.unwrap_or_default(),
356 bin_runtime: self.bin_runtime.unwrap_or_default(),
357 }
358 }
359}
360
361impl From<serde_json::Value> for CompactContract {
362 fn from(mut val: serde_json::Value) -> Self {
363 if let Some(map) = val.as_object_mut() {
364 let abi = map.remove("abi").and_then(|val| serde_json::from_value(val).ok());
365 let bin = map.remove("bin").and_then(|val| serde_json::from_value(val).ok());
366 let bin_runtime =
367 map.remove("bin-runtime").and_then(|val| serde_json::from_value(val).ok());
368 Self { abi, bin, bin_runtime }
369 } else {
370 Self::default()
371 }
372 }
373}
374
375impl<'a> From<&'a serde_json::Value> for CompactContractBytecodeCow<'a> {
376 fn from(artifact: &'a serde_json::Value) -> Self {
377 let c = CompactContractBytecode::from(artifact.clone());
378 CompactContractBytecodeCow {
379 abi: c.abi.map(Cow::Owned),
380 bytecode: c.bytecode.map(Cow::Owned),
381 deployed_bytecode: c.deployed_bytecode.map(Cow::Owned),
382 }
383 }
384}
385
386impl From<serde_json::Value> for CompactContractBytecode {
387 fn from(val: serde_json::Value) -> Self {
388 serde_json::from_value(val).unwrap_or_default()
389 }
390}
391
392impl From<ContractBytecode> for CompactContract {
393 fn from(c: ContractBytecode) -> Self {
394 let ContractBytecode { abi, bytecode, deployed_bytecode } = c;
395 Self {
396 abi,
397 bin: bytecode.map(|c| c.object),
398 bin_runtime: deployed_bytecode
399 .and_then(|deployed| deployed.bytecode.map(|code| code.object)),
400 }
401 }
402}
403
404impl From<CompactContractBytecode> for CompactContract {
405 fn from(c: CompactContractBytecode) -> Self {
406 let c: ContractBytecode = c.into();
407 c.into()
408 }
409}
410
411impl From<ContractBytecodeSome> for CompactContract {
412 fn from(c: ContractBytecodeSome) -> Self {
413 Self {
414 abi: Some(c.abi),
415 bin: Some(c.bytecode.object),
416 bin_runtime: c.deployed_bytecode.bytecode.map(|code| code.object),
417 }
418 }
419}
420
421impl From<Contract> for CompactContract {
422 fn from(c: Contract) -> Self {
423 ContractBytecode::from(c).into()
424 }
425}
426
427impl From<CompactContractSome> for CompactContract {
428 fn from(c: CompactContractSome) -> Self {
429 Self { abi: Some(c.abi), bin: Some(c.bin), bin_runtime: Some(c.bin_runtime) }
430 }
431}
432
433impl<'a> From<CompactContractRef<'a>> for CompactContract {
434 fn from(c: CompactContractRef<'a>) -> Self {
435 Self { abi: c.abi.cloned(), bin: c.bin.cloned(), bin_runtime: c.bin_runtime.cloned() }
436 }
437}
438
439impl<'a> From<CompactContractRefSome<'a>> for CompactContract {
440 fn from(c: CompactContractRefSome<'a>) -> Self {
441 Self {
442 abi: Some(c.abi.clone()),
443 bin: Some(c.bin.clone()),
444 bin_runtime: Some(c.bin_runtime.clone()),
445 }
446 }
447}
448
449#[derive(Clone, Copy, Debug, Serialize)]
451pub struct CompactContractRefSome<'a> {
452 pub abi: &'a JsonAbi,
453 pub bin: &'a BytecodeObject,
454 #[serde(rename = "bin-runtime")]
455 pub bin_runtime: &'a BytecodeObject,
456}
457
458impl CompactContractRefSome<'_> {
459 pub fn into_parts(self) -> (JsonAbi, Bytes, Bytes) {
463 CompactContract::from(self).into_parts_or_default()
464 }
465}
466
467impl<'a> TryFrom<CompactContractRef<'a>> for CompactContractRefSome<'a> {
468 type Error = CompactContractRef<'a>;
469
470 fn try_from(value: CompactContractRef<'a>) -> Result<Self, Self::Error> {
471 if value.abi.is_none() || value.bin.is_none() || value.bin_runtime.is_none() {
472 return Err(value);
473 }
474 Ok(value.unwrap())
475 }
476}
477
478#[derive(Clone, Copy, Debug, Serialize)]
480pub struct CompactContractRef<'a> {
481 pub abi: Option<&'a JsonAbi>,
482 #[serde(default, skip_serializing_if = "Option::is_none")]
483 pub bin: Option<&'a BytecodeObject>,
484 #[serde(default, rename = "bin-runtime", skip_serializing_if = "Option::is_none")]
485 pub bin_runtime: Option<&'a BytecodeObject>,
486}
487
488impl<'a> CompactContractRef<'a> {
489 pub fn into_parts(self) -> (Option<JsonAbi>, Option<Bytes>, Option<Bytes>) {
491 CompactContract::from(self).into_parts()
492 }
493
494 pub fn into_parts_or_default(self) -> (JsonAbi, Bytes, Bytes) {
498 CompactContract::from(self).into_parts_or_default()
499 }
500
501 pub fn bytecode(&self) -> Option<&Bytes> {
502 self.bin.as_ref().and_then(|bin| bin.as_bytes())
503 }
504
505 pub fn runtime_bytecode(&self) -> Option<&Bytes> {
506 self.bin_runtime.as_ref().and_then(|bin| bin.as_bytes())
507 }
508
509 #[track_caller]
515 pub fn unwrap(self) -> CompactContractRefSome<'a> {
516 CompactContractRefSome {
517 abi: self.abi.unwrap(),
518 bin: self.bin.unwrap(),
519 bin_runtime: self.bin_runtime.unwrap(),
520 }
521 }
522}
523
524impl<'a> From<&'a Contract> for CompactContractRef<'a> {
525 fn from(c: &'a Contract) -> Self {
526 let (bin, bin_runtime) = if let Some(evm) = &c.evm {
527 (
528 evm.bytecode.as_ref().map(|c| &c.object),
529 evm.deployed_bytecode
530 .as_ref()
531 .and_then(|deployed| deployed.bytecode.as_ref().map(|evm| &evm.object)),
532 )
533 } else {
534 (None, None)
535 };
536
537 Self { abi: c.abi.as_ref(), bin, bin_runtime }
538 }
539}