1use std::{
4 fs::read_dir,
5 io::Error,
6 path::PathBuf,
7};
8
9use crate::vyper_errors::VyperErrors;
10
11#[derive(Clone, Debug, Eq, PartialEq)]
21pub struct Blueprint {
22 pub erc_version: u8,
23 pub preamble_data: Option<Vec<u8>>,
24 pub initcode: Vec<u8>,
25}
26
27pub fn parse_blueprint(bytecode: &[u8]) -> Result<Blueprint, VyperErrors> {
28 if bytecode.is_empty() {
29 Err(VyperErrors::BlueprintError("Empty Bytecode".to_owned()))?
30 }
31 if &bytecode[0..2] != b"\xFE\x71" {
32 Err(VyperErrors::BlueprintError("Not a blueprint!".to_owned()))?
33 }
34
35 let erc_version = (&bytecode[2] & 0b11111100) >> 2;
36 let n_length_bytes = &bytecode[2] & 0b11;
37
38 if n_length_bytes == 0b11 {
39 Err(VyperErrors::BlueprintError("Reserved bits are set".to_owned()))?
40 }
41
42 let size_temp = bytecode[3..(3 + n_length_bytes as usize)].to_vec();
43 let data_length = match size_temp.len() {
44 0 => 0,
45 _ => {
46 let size: String = hex::encode(&size_temp);
47 match u32::from_str_radix(&size, size_temp.len() as u32 * 8u32) {
48 Ok(num) => num,
49 Err(e) => Err(VyperErrors::IntParseError(e))?,
50 }
51 }
52 };
53
54 let preamble_data: Option<Vec<u8>> = match data_length {
55 0 => None,
56 _ => {
57 let data_start = 3 + n_length_bytes as usize;
58 Some(bytecode[data_start..data_start + data_length as usize].to_vec())
59 }
60 };
61
62 let initcode =
63 bytecode[3 + n_length_bytes as usize + data_length as usize..].to_vec();
64 match initcode.is_empty() {
65 true => {
66 Err(VyperErrors::BlueprintError("Empty Initcode!".to_owned()))?
67 }
68 false => Ok(Blueprint{erc_version, preamble_data, initcode}),
69 }
70}
71
72pub async fn scan_workspace(root: PathBuf) -> Result<Vec<PathBuf>, Error> {
75 let cwd = root.clone();
76 let h1 = tokio::spawn(async move { get_contracts_in_dir(cwd) });
77 let hh_ape = root.join("contracts");
78 let h2 = tokio::spawn(async move { get_contracts_in_dir(hh_ape) });
79 let foundry = root.join("src");
80 let h3 = tokio::spawn(async move { get_contracts_in_dir(foundry) });
81 let mut res = Vec::new();
82 for i in [h1, h2, h3].into_iter() {
83 let result = match i.await {
84 Ok(Ok(x)) => x,
85 _ => Vec::new(),
86 };
87 res.push(result)
88 }
89 Ok(res.into_iter().flatten().collect::<Vec<PathBuf>>())
90}
91
92pub fn get_contracts_in_dir(dir: PathBuf) -> Result<Vec<PathBuf>, Error> {
95 let files = read_dir(dir)?;
96 let contracts = files.into_iter().try_fold(
97 Vec::new(),
98 |mut acc, x| -> Result<Vec<PathBuf>, Error> {
99 let file = x?;
100 if file.path().ends_with(".vy") {
101 acc.push(file.path())
102 }
103 Ok(acc)
104 },
105 )?;
106 Ok(contracts)
107}