//! This crate provides compiler helpers for all supported Solidity targets: //! - Ethereum solc compiler //! - Polkadot revive resolc compiler //! - Polkadot revive Wasm compiler mod constants; use std::{ collections::HashMap, hash::Hash, path::{Path, PathBuf}, }; use alloy::json_abi::JsonAbi; use alloy_primitives::Address; use semver::Version; use serde::{Deserialize, Serialize}; use revive_common::EVMVersion; use revive_dt_common::cached_fs::read_to_string; use revive_dt_common::types::VersionOrRequirement; use revive_dt_config::Arguments; // Re-export this as it's a part of the compiler interface. pub use revive_dt_common::types::{Mode, ModeOptimizerSetting, ModePipeline}; pub mod revive_js; pub mod revive_resolc; pub mod solc; /// A common interface for all supported Solidity compilers. pub trait SolidityCompiler { /// Extra options specific to the compiler. type Options: Default + PartialEq + Eq + Hash; /// The low-level compiler interface. fn build( &self, input: CompilerInput, additional_options: Self::Options, ) -> impl Future>; fn new(solc_executable: PathBuf) -> Self; fn get_compiler_executable( config: &Arguments, version: impl Into, ) -> impl Future>; fn version(&self) -> impl Future>; /// Does the compiler support the provided mode and version settings? fn supports_mode( compiler_version: &Version, optimize_setting: ModeOptimizerSetting, pipeline: ModePipeline, ) -> bool; } /// The generic compilation input configuration. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CompilerInput { pub pipeline: Option, pub optimization: Option, pub evm_version: Option, pub allow_paths: Vec, pub base_path: Option, pub sources: HashMap, pub libraries: HashMap>, pub revert_string_handling: Option, } /// The generic compilation output configuration. #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct CompilerOutput { /// The compiled contracts. The bytecode of the contract is kept as a string incase linking is /// required and the compiled source has placeholders. pub contracts: HashMap>, } /// A generic builder style interface for configuring the supported compiler options. pub struct Compiler { input: CompilerInput, additional_options: T::Options, } impl Default for Compiler { fn default() -> Self { Self::new() } } impl Compiler where T: SolidityCompiler, { pub fn new() -> Self { Self { input: CompilerInput { pipeline: Default::default(), optimization: Default::default(), evm_version: Default::default(), allow_paths: Default::default(), base_path: Default::default(), sources: Default::default(), libraries: Default::default(), revert_string_handling: Default::default(), }, additional_options: T::Options::default(), } } pub fn with_optimization(mut self, value: impl Into>) -> Self { self.input.optimization = value.into(); self } pub fn with_pipeline(mut self, value: impl Into>) -> Self { self.input.pipeline = value.into(); self } pub fn with_evm_version(mut self, version: impl Into>) -> Self { self.input.evm_version = version.into(); self } pub fn with_allow_path(mut self, path: impl AsRef) -> Self { self.input.allow_paths.push(path.as_ref().into()); self } pub fn with_base_path(mut self, path: impl Into>) -> Self { self.input.base_path = path.into(); self } pub fn with_source(mut self, path: impl AsRef) -> anyhow::Result { self.input .sources .insert(path.as_ref().to_path_buf(), read_to_string(path.as_ref())?); Ok(self) } pub fn with_library( mut self, path: impl AsRef, name: impl AsRef, address: Address, ) -> Self { self.input .libraries .entry(path.as_ref().to_path_buf()) .or_default() .insert(name.as_ref().into(), address); self } pub fn with_revert_string_handling( mut self, revert_string_handling: impl Into>, ) -> Self { self.input.revert_string_handling = revert_string_handling.into(); self } pub fn with_additional_options(mut self, options: impl Into) -> Self { self.additional_options = options.into(); self } pub fn then(self, callback: impl FnOnce(Self) -> Self) -> Self { callback(self) } pub fn try_then(self, callback: impl FnOnce(Self) -> Result) -> Result { callback(self) } pub async fn try_build( self, compiler_path: impl AsRef, ) -> anyhow::Result { T::new(compiler_path.as_ref().to_path_buf()) .build(self.input, self.additional_options) .await } pub fn input(&self) -> CompilerInput { self.input.clone() } } /// Defines how the compiler should handle revert strings. #[derive( Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize, )] pub enum RevertString { #[default] Default, Debug, Strip, VerboseDebug, }