foundry_compilers_artifacts_vyper/
settings.rs

1use foundry_compilers_artifacts_solc::{
2    output_selection::OutputSelection, serde_helpers, EvmVersion,
3};
4use semver::Version;
5use serde::{Deserialize, Serialize};
6use std::{
7    collections::BTreeSet,
8    path::{Path, PathBuf},
9};
10
11pub const VYPER_SEARCH_PATHS: Version = VYPER_0_4;
12pub const VYPER_BERLIN: Version = Version::new(0, 3, 0);
13pub const VYPER_PARIS: Version = Version::new(0, 3, 7);
14pub const VYPER_SHANGHAI: Version = Version::new(0, 3, 8);
15pub const VYPER_CANCUN: Version = Version::new(0, 3, 8);
16pub const VYPER_PRAGUE: Version = Version::new(0, 4, 3);
17
18const VYPER_0_4: Version = Version::new(0, 4, 0);
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
21#[serde(rename_all = "lowercase")]
22pub enum VyperOptimizationMode {
23    Gas,
24    Codesize,
25    None,
26}
27
28#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
29#[serde(rename_all = "camelCase")]
30pub struct VyperSettings {
31    #[serde(
32        default,
33        with = "serde_helpers::display_from_str_opt",
34        skip_serializing_if = "Option::is_none"
35    )]
36    pub evm_version: Option<EvmVersion>,
37    /// Optimization mode
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub optimize: Option<VyperOptimizationMode>,
40    /// Whether or not the bytecode should include Vyper's signature
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub bytecode_metadata: Option<bool>,
43    pub output_selection: OutputSelection,
44    #[serde(rename = "search_paths", skip_serializing_if = "Option::is_none")]
45    pub search_paths: Option<BTreeSet<PathBuf>>,
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub experimental_codegen: Option<bool>,
48}
49
50impl VyperSettings {
51    pub fn strip_prefix(&mut self, base: &Path) {
52        self.output_selection = OutputSelection(
53            std::mem::take(&mut self.output_selection.0)
54                .into_iter()
55                .map(|(file, selection)| {
56                    (
57                        Path::new(&file)
58                            .strip_prefix(base)
59                            .map(|p| p.display().to_string())
60                            .unwrap_or(file),
61                        selection,
62                    )
63                })
64                .collect(),
65        );
66        self.search_paths = self.search_paths.as_ref().map(|paths| {
67            paths.iter().map(|p| p.strip_prefix(base).unwrap_or(p.as_path()).into()).collect()
68        });
69    }
70
71    /// Sanitize the output selection.
72    #[allow(clippy::collapsible_if)]
73    pub fn sanitize_output_selection(&mut self, version: &Version) {
74        self.output_selection.0.values_mut().for_each(|selection| {
75            selection.values_mut().for_each(|selection| {
76                // During caching we prune output selection for some of the sources, however, Vyper
77                // will reject `[]` as an output selection, so we are adding "abi" as a default
78                // output selection which is cheap to be produced.
79                if selection.is_empty() {
80                    selection.push("abi".to_string())
81                }
82
83                // Unsupported selections.
84                #[rustfmt::skip]
85                selection.retain(|selection| {
86                    if *version < VYPER_0_4 {
87                        if matches!(
88                            selection.as_str(),
89                            | "evm.bytecode.sourceMap" | "evm.deployedBytecode.sourceMap"
90                        ) {
91                            return false;
92                        }
93                    }
94
95                    if matches!(
96                        selection.as_str(),
97                        | "evm.bytecode.sourceMap" | "evm.deployedBytecode.sourceMap"
98                        // https://github.com/vyperlang/vyper/issues/4389
99                        | "evm.bytecode.linkReferences" | "evm.deployedBytecode.linkReferences"
100                        | "evm.deployedBytecode.immutableReferences"
101                    ) {
102                        return false;
103                    }
104
105                    true
106                });
107            })
108        });
109    }
110
111    /// Sanitize the settings based on the compiler version.
112    pub fn sanitize(&mut self, version: &Version) {
113        if version < &VYPER_SEARCH_PATHS {
114            self.search_paths = None;
115        }
116
117        self.sanitize_output_selection(version);
118        self.normalize_evm_version(version);
119    }
120
121    /// Sanitize the settings based on the compiler version.
122    pub fn sanitized(mut self, version: &Version) -> Self {
123        self.sanitize(version);
124        self
125    }
126
127    /// Adjusts the EVM version based on the compiler version.
128    pub fn normalize_evm_version(&mut self, version: &Version) {
129        if let Some(evm_version) = &mut self.evm_version {
130            *evm_version = if *evm_version >= EvmVersion::Prague && *version >= VYPER_PRAGUE {
131                EvmVersion::Prague
132            } else if *evm_version >= EvmVersion::Cancun && *version >= VYPER_CANCUN {
133                EvmVersion::Cancun
134            } else if *evm_version >= EvmVersion::Shanghai && *version >= VYPER_SHANGHAI {
135                EvmVersion::Shanghai
136            } else if *evm_version >= EvmVersion::Paris && *version >= VYPER_PARIS {
137                EvmVersion::Paris
138            } else if *evm_version >= EvmVersion::Berlin && *version >= VYPER_BERLIN {
139                EvmVersion::Berlin
140            } else {
141                *evm_version
142            };
143        }
144    }
145}