1use crate::artifacts::{
4 bytecode::{
5 Bytecode, BytecodeObject, CompactBytecode, CompactDeployedBytecode, DeployedBytecode,
6 },
7 serde_helpers, DevDoc, Evm, Ewasm, LosslessAbi, LosslessMetadata, Offsets, StorageLayout,
8 UserDoc,
9};
10use ethers_core::{abi::Contract as Abi, types::Bytes};
11use serde::{Deserialize, Serialize};
12use std::{borrow::Cow, collections::BTreeMap};
13
14#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
16#[serde(rename_all = "camelCase")]
17pub struct Contract {
18 pub abi: Option<LosslessAbi>,
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 = "Option::is_none")]
37 pub evm: Option<Evm>,
38 #[serde(default, skip_serializing_if = "Option::is_none")]
40 pub ewasm: Option<Ewasm>,
41 #[serde(default, skip_serializing_if = "Option::is_none")]
42 pub ir_optimized: Option<String>,
43}
44
45impl<'a> From<&'a Contract> for CompactContractBytecodeCow<'a> {
46 fn from(artifact: &'a Contract) -> Self {
47 let (bytecode, deployed_bytecode) = if let Some(ref evm) = artifact.evm {
48 (
49 evm.bytecode.clone().map(Into::into).map(Cow::Owned),
50 evm.deployed_bytecode.clone().map(Into::into).map(Cow::Owned),
51 )
52 } else {
53 (None, None)
54 };
55 CompactContractBytecodeCow {
56 abi: artifact.abi.as_ref().map(|abi| Cow::Borrowed(&abi.abi)),
57 bytecode,
58 deployed_bytecode,
59 }
60 }
61}
62
63#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
68pub struct ContractBytecode {
69 pub abi: Option<Abi>,
72 #[serde(default, skip_serializing_if = "Option::is_none")]
73 pub bytecode: Option<Bytecode>,
74 #[serde(default, skip_serializing_if = "Option::is_none")]
75 pub deployed_bytecode: Option<DeployedBytecode>,
76}
77
78impl ContractBytecode {
79 pub fn unwrap(self) -> ContractBytecodeSome {
97 ContractBytecodeSome {
98 abi: self.abi.unwrap(),
99 bytecode: self.bytecode.unwrap(),
100 deployed_bytecode: self.deployed_bytecode.unwrap(),
101 }
102 }
103
104 pub fn all_link_references(&self) -> BTreeMap<String, BTreeMap<String, Vec<Offsets>>> {
106 let mut links = BTreeMap::new();
107 if let Some(bcode) = &self.bytecode {
108 links.extend(bcode.link_references.clone());
109 }
110
111 if let Some(d_bcode) = &self.deployed_bytecode {
112 if let Some(bcode) = &d_bcode.bytecode {
113 links.extend(bcode.link_references.clone());
114 }
115 }
116 links
117 }
118}
119
120impl From<Contract> for ContractBytecode {
121 fn from(c: Contract) -> Self {
122 let (bytecode, deployed_bytecode) = if let Some(evm) = c.evm {
123 (evm.bytecode, evm.deployed_bytecode)
124 } else {
125 (None, None)
126 };
127
128 Self { abi: c.abi.map(Into::into), bytecode, deployed_bytecode }
129 }
130}
131
132#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
137#[serde(rename_all = "camelCase")]
138pub struct CompactContractBytecode {
139 pub abi: Option<Abi>,
142 #[serde(default, skip_serializing_if = "Option::is_none")]
143 pub bytecode: Option<CompactBytecode>,
144 #[serde(default, skip_serializing_if = "Option::is_none")]
145 pub deployed_bytecode: Option<CompactDeployedBytecode>,
146}
147
148impl CompactContractBytecode {
149 pub fn all_link_references(&self) -> BTreeMap<String, BTreeMap<String, Vec<Offsets>>> {
151 let mut links = BTreeMap::new();
152 if let Some(bcode) = &self.bytecode {
153 links.extend(bcode.link_references.clone());
154 }
155
156 if let Some(d_bcode) = &self.deployed_bytecode {
157 if let Some(bcode) = &d_bcode.bytecode {
158 links.extend(bcode.link_references.clone());
159 }
160 }
161 links
162 }
163}
164
165impl<'a> From<&'a CompactContractBytecode> for CompactContractBytecodeCow<'a> {
166 fn from(artifact: &'a CompactContractBytecode) -> Self {
167 CompactContractBytecodeCow {
168 abi: artifact.abi.as_ref().map(Cow::Borrowed),
169 bytecode: artifact.bytecode.as_ref().map(Cow::Borrowed),
170 deployed_bytecode: artifact.deployed_bytecode.as_ref().map(Cow::Borrowed),
171 }
172 }
173}
174
175impl From<Contract> for CompactContractBytecode {
176 fn from(c: Contract) -> Self {
177 let (bytecode, deployed_bytecode) = if let Some(evm) = c.evm {
178 let evm = evm.into_compact();
179 (evm.bytecode, evm.deployed_bytecode)
180 } else {
181 (None, None)
182 };
183
184 Self { abi: c.abi.map(Into::into), bytecode, deployed_bytecode }
185 }
186}
187
188impl From<ContractBytecode> for CompactContractBytecode {
189 fn from(c: ContractBytecode) -> Self {
190 let (maybe_bcode, maybe_runtime) = match (c.bytecode, c.deployed_bytecode) {
191 (Some(bcode), Some(dbcode)) => (Some(bcode.into()), Some(dbcode.into())),
192 (None, Some(dbcode)) => (None, Some(dbcode.into())),
193 (Some(bcode), None) => (Some(bcode.into()), None),
194 (None, None) => (None, None),
195 };
196 Self { abi: c.abi, bytecode: maybe_bcode, deployed_bytecode: maybe_runtime }
197 }
198}
199
200impl From<CompactContractBytecode> for ContractBytecode {
201 fn from(c: CompactContractBytecode) -> Self {
202 let (maybe_bcode, maybe_runtime) = match (c.bytecode, c.deployed_bytecode) {
203 (Some(bcode), Some(dbcode)) => (Some(bcode.into()), Some(dbcode.into())),
204 (None, Some(dbcode)) => (None, Some(dbcode.into())),
205 (Some(bcode), None) => (Some(bcode.into()), None),
206 (None, None) => (None, None),
207 };
208 Self { abi: c.abi, bytecode: maybe_bcode, deployed_bytecode: maybe_runtime }
209 }
210}
211
212#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
214#[serde(rename_all = "camelCase")]
215pub struct CompactContractBytecodeCow<'a> {
216 pub abi: Option<Cow<'a, Abi>>,
217 #[serde(default, skip_serializing_if = "Option::is_none")]
218 pub bytecode: Option<Cow<'a, CompactBytecode>>,
219 #[serde(default, skip_serializing_if = "Option::is_none")]
220 pub deployed_bytecode: Option<Cow<'a, CompactDeployedBytecode>>,
221}
222
223#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
228pub struct ContractBytecodeSome {
229 pub abi: Abi,
230 pub bytecode: Bytecode,
231 pub deployed_bytecode: DeployedBytecode,
232}
233
234impl TryFrom<ContractBytecode> for ContractBytecodeSome {
235 type Error = ContractBytecode;
236
237 fn try_from(value: ContractBytecode) -> Result<Self, Self::Error> {
238 if value.abi.is_none() || value.bytecode.is_none() || value.deployed_bytecode.is_none() {
239 return Err(value)
240 }
241 Ok(value.unwrap())
242 }
243}
244
245#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)]
247pub struct CompactContractSome {
248 pub abi: Abi,
251 pub bin: BytecodeObject,
252 #[serde(rename = "bin-runtime")]
253 pub bin_runtime: BytecodeObject,
254}
255
256impl TryFrom<CompactContract> for CompactContractSome {
257 type Error = CompactContract;
258
259 fn try_from(value: CompactContract) -> Result<Self, Self::Error> {
260 if value.abi.is_none() || value.bin.is_none() || value.bin_runtime.is_none() {
261 return Err(value)
262 }
263 Ok(value.unwrap())
264 }
265}
266
267#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)]
271pub struct CompactContract {
272 pub abi: Option<Abi>,
275 #[serde(default, skip_serializing_if = "Option::is_none")]
276 pub bin: Option<BytecodeObject>,
277 #[serde(default, rename = "bin-runtime", skip_serializing_if = "Option::is_none")]
278 pub bin_runtime: Option<BytecodeObject>,
279}
280
281impl CompactContract {
282 pub fn into_parts(self) -> (Option<Abi>, Option<Bytes>, Option<Bytes>) {
284 (
285 self.abi,
286 self.bin.and_then(|bin| bin.into_bytes()),
287 self.bin_runtime.and_then(|bin| bin.into_bytes()),
288 )
289 }
290
291 pub fn into_parts_or_default(self) -> (Abi, Bytes, Bytes) {
295 (
296 self.abi.unwrap_or_default(),
297 self.bin.and_then(|bin| bin.into_bytes()).unwrap_or_default(),
298 self.bin_runtime.and_then(|bin| bin.into_bytes()).unwrap_or_default(),
299 )
300 }
301
302 pub fn unwrap(self) -> CompactContractSome {
320 CompactContractSome {
321 abi: self.abi.unwrap(),
322 bin: self.bin.unwrap(),
323 bin_runtime: self.bin_runtime.unwrap(),
324 }
325 }
326
327 pub fn unwrap_or_default(self) -> CompactContractSome {
332 CompactContractSome {
333 abi: self.abi.unwrap_or_default(),
334 bin: self.bin.unwrap_or_default(),
335 bin_runtime: self.bin_runtime.unwrap_or_default(),
336 }
337 }
338}
339
340impl From<serde_json::Value> for CompactContract {
341 fn from(mut val: serde_json::Value) -> Self {
342 if let Some(map) = val.as_object_mut() {
343 let abi = map.remove("abi").and_then(|val| serde_json::from_value(val).ok());
344 let bin = map.remove("bin").and_then(|val| serde_json::from_value(val).ok());
345 let bin_runtime =
346 map.remove("bin-runtime").and_then(|val| serde_json::from_value(val).ok());
347 Self { abi, bin, bin_runtime }
348 } else {
349 CompactContract::default()
350 }
351 }
352}
353
354impl<'a> From<&'a serde_json::Value> for CompactContractBytecodeCow<'a> {
355 fn from(artifact: &'a serde_json::Value) -> Self {
356 let c = CompactContractBytecode::from(artifact.clone());
357 CompactContractBytecodeCow {
358 abi: c.abi.map(Cow::Owned),
359 bytecode: c.bytecode.map(Cow::Owned),
360 deployed_bytecode: c.deployed_bytecode.map(Cow::Owned),
361 }
362 }
363}
364
365impl From<serde_json::Value> for CompactContractBytecode {
366 fn from(val: serde_json::Value) -> Self {
367 serde_json::from_value(val).unwrap_or_default()
368 }
369}
370
371impl From<ContractBytecode> for CompactContract {
372 fn from(c: ContractBytecode) -> Self {
373 let ContractBytecode { abi, bytecode, deployed_bytecode } = c;
374 Self {
375 abi,
376 bin: bytecode.map(|c| c.object),
377 bin_runtime: deployed_bytecode
378 .and_then(|deployed| deployed.bytecode.map(|code| code.object)),
379 }
380 }
381}
382
383impl From<CompactContractBytecode> for CompactContract {
384 fn from(c: CompactContractBytecode) -> Self {
385 let c: ContractBytecode = c.into();
386 c.into()
387 }
388}
389
390impl From<ContractBytecodeSome> for CompactContract {
391 fn from(c: ContractBytecodeSome) -> Self {
392 Self {
393 abi: Some(c.abi),
394 bin: Some(c.bytecode.object),
395 bin_runtime: c.deployed_bytecode.bytecode.map(|code| code.object),
396 }
397 }
398}
399
400impl From<Contract> for CompactContract {
401 fn from(c: Contract) -> Self {
402 ContractBytecode::from(c).into()
403 }
404}
405
406impl From<CompactContractSome> for CompactContract {
407 fn from(c: CompactContractSome) -> Self {
408 Self { abi: Some(c.abi), bin: Some(c.bin), bin_runtime: Some(c.bin_runtime) }
409 }
410}
411
412impl<'a> From<CompactContractRef<'a>> for CompactContract {
413 fn from(c: CompactContractRef<'a>) -> Self {
414 Self { abi: c.abi.cloned(), bin: c.bin.cloned(), bin_runtime: c.bin_runtime.cloned() }
415 }
416}
417
418impl<'a> From<CompactContractRefSome<'a>> for CompactContract {
419 fn from(c: CompactContractRefSome<'a>) -> Self {
420 Self {
421 abi: Some(c.abi.clone()),
422 bin: Some(c.bin.clone()),
423 bin_runtime: Some(c.bin_runtime.clone()),
424 }
425 }
426}
427
428#[derive(Copy, Clone, Debug, Serialize)]
430pub struct CompactContractRefSome<'a> {
431 pub abi: &'a Abi,
432 pub bin: &'a BytecodeObject,
433 #[serde(rename = "bin-runtime")]
434 pub bin_runtime: &'a BytecodeObject,
435}
436
437impl<'a> CompactContractRefSome<'a> {
438 pub fn into_parts(self) -> (Abi, Bytes, Bytes) {
442 CompactContract::from(self).into_parts_or_default()
443 }
444}
445
446impl<'a> TryFrom<CompactContractRef<'a>> for CompactContractRefSome<'a> {
447 type Error = CompactContractRef<'a>;
448
449 fn try_from(value: CompactContractRef<'a>) -> Result<Self, Self::Error> {
450 if value.abi.is_none() || value.bin.is_none() || value.bin_runtime.is_none() {
451 return Err(value)
452 }
453 Ok(value.unwrap())
454 }
455}
456
457#[derive(Copy, Clone, Debug, Serialize)]
459pub struct CompactContractRef<'a> {
460 pub abi: Option<&'a Abi>,
461 #[serde(default, skip_serializing_if = "Option::is_none")]
462 pub bin: Option<&'a BytecodeObject>,
463 #[serde(default, rename = "bin-runtime", skip_serializing_if = "Option::is_none")]
464 pub bin_runtime: Option<&'a BytecodeObject>,
465}
466
467impl<'a> CompactContractRef<'a> {
468 pub fn into_parts(self) -> (Option<Abi>, Option<Bytes>, Option<Bytes>) {
470 CompactContract::from(self).into_parts()
471 }
472
473 pub fn into_parts_or_default(self) -> (Abi, Bytes, Bytes) {
477 CompactContract::from(self).into_parts_or_default()
478 }
479
480 pub fn bytecode(&self) -> Option<&Bytes> {
481 self.bin.as_ref().and_then(|bin| bin.as_bytes())
482 }
483
484 pub fn runtime_bytecode(&self) -> Option<&Bytes> {
485 self.bin_runtime.as_ref().and_then(|bin| bin.as_bytes())
486 }
487
488 pub fn unwrap(self) -> CompactContractRefSome<'a> {
506 CompactContractRefSome {
507 abi: self.abi.unwrap(),
508 bin: self.bin.unwrap(),
509 bin_runtime: self.bin_runtime.unwrap(),
510 }
511 }
512}
513
514impl<'a> From<&'a Contract> for CompactContractRef<'a> {
515 fn from(c: &'a Contract) -> Self {
516 let (bin, bin_runtime) = if let Some(ref evm) = c.evm {
517 (
518 evm.bytecode.as_ref().map(|c| &c.object),
519 evm.deployed_bytecode
520 .as_ref()
521 .and_then(|deployed| deployed.bytecode.as_ref().map(|evm| &evm.object)),
522 )
523 } else {
524 (None, None)
525 };
526
527 Self { abi: c.abi.as_ref().map(|abi| &abi.abi), bin, bin_runtime }
528 }
529}