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