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