diff --git a/ethers-solc/src/artifacts/mod.rs b/ethers-solc/src/artifacts/mod.rs index 0d5038a4..39f54b0e 100644 --- a/ethers-solc/src/artifacts/mod.rs +++ b/ethers-solc/src/artifacts/mod.rs @@ -52,13 +52,25 @@ pub struct CompilerInput { impl CompilerInput { /// Reads all contracts found under the path - pub fn new(path: impl AsRef) -> Result { + pub fn new(path: impl AsRef) -> Result, SolcIoError> { Source::read_all_from(path.as_ref()).map(Self::with_sources) } /// Creates a new Compiler input with default settings and the given sources - pub fn with_sources(sources: Sources) -> Self { - Self { language: "Solidity".to_string(), sources, settings: Default::default() } + pub fn with_sources(sources: Sources) -> Vec { + let mut solidity_sources = BTreeMap::new(); + let mut yul_sources = BTreeMap::new(); + for (path, source) in sources { + if path.extension() == Some(std::ffi::OsStr::new("yul")) { + yul_sources.insert(path, source); + } else { + solidity_sources.insert(path, source); + } + } + vec![ + Self { language: "Solidity".to_string(), sources: solidity_sources, settings: Default::default() }, + Self { language: "Yul".to_string(), sources: yul_sources, settings: Default::default() } + ] } /// Sets the settings for compilation @@ -99,12 +111,6 @@ impl CompilerInput { } } -impl Default for CompilerInput { - fn default() -> Self { - Self::with_sources(Default::default()) - } -} - #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Settings { diff --git a/ethers-solc/src/compile/project.rs b/ethers-solc/src/compile/project.rs index 6e1a9ac7..a145e0b7 100644 --- a/ethers-solc/src/compile/project.rs +++ b/ethers-solc/src/compile/project.rs @@ -337,24 +337,23 @@ fn compile_sequential( solc.args ); - let input = CompilerInput::with_sources(sources) - .settings(settings.clone()) - .normalize_evm_version(&version) - .with_remappings(paths.remappings.clone()); - - tracing::trace!( - "calling solc `{}` with {} sources {:?}", - version, - input.sources.len(), - input.sources.keys() - ); - - report::solc_spawn(&solc, &version, &input); - let output = solc.compile_exact(&input)?; - report::solc_success(&solc, &version, &output); - tracing::trace!("compiled input, output has error: {}", output.has_error()); - - aggregated.extend(version, output); + for input in CompilerInput::with_sources(sources) { + let input = input + .settings(settings.clone()) + .normalize_evm_version(&version) + .with_remappings(paths.remappings.clone()); + tracing::trace!( + "calling solc `{}` with {} sources {:?}", + version, + input.sources.len(), + input.sources.keys() + ); + report::solc_spawn(&solc, &version, &input); + let output = solc.compile_exact(&input)?; + report::solc_success(&solc, &version, &output); + tracing::trace!("compiled input, output has error: {}", output.has_error()); + aggregated.extend(version.clone(), output); + } } Ok(aggregated) } @@ -379,13 +378,14 @@ fn compile_parallel( // nothing to compile continue } + for input in CompilerInput::with_sources(sources) { + let job = input + .settings(settings.clone()) + .normalize_evm_version(&version) + .with_remappings(paths.remappings.clone()); - let job = CompilerInput::with_sources(sources) - .settings(settings.clone()) - .normalize_evm_version(&version) - .with_remappings(paths.remappings.clone()); - - jobs.push((solc, version, job)) + jobs.push((solc.clone(), version.clone(), job)) + } } // start a rayon threadpool that will execute all `Solc::compile()` processes diff --git a/ethers-solc/src/utils.rs b/ethers-solc/src/utils.rs index c15a2697..b8e7f714 100644 --- a/ethers-solc/src/utils.rs +++ b/ethers-solc/src/utils.rs @@ -67,7 +67,7 @@ pub fn source_files(root: impl AsRef) -> Vec { .into_iter() .filter_map(Result::ok) .filter(|e| e.file_type().is_file()) - .filter(|e| e.path().extension().map(|ext| ext == "sol").unwrap_or_default()) + .filter(|e| e.path().extension().map(|ext| (ext == "sol") || (ext == "yul")).unwrap_or_default()) .map(|e| e.path().into()) .collect() } diff --git a/ethers-solc/test-data/yul-sample/Dapp.sol b/ethers-solc/test-data/yul-sample/Dapp.sol new file mode 100644 index 00000000..762db2c3 --- /dev/null +++ b/ethers-solc/test-data/yul-sample/Dapp.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.6.6; + +contract Dapp { + + function modified() public {} +} diff --git a/ethers-solc/test-data/yul-sample/SimpleStore.yul b/ethers-solc/test-data/yul-sample/SimpleStore.yul new file mode 100644 index 00000000..4226605b --- /dev/null +++ b/ethers-solc/test-data/yul-sample/SimpleStore.yul @@ -0,0 +1,11 @@ +object "SimpleStore" { + code { + datacopy(0, dataoffset("Runtime"), datasize("Runtime")) + return(0, datasize("Runtime")) + } + object "Runtime" { + code { + calldatacopy(0, 0, 36) // write calldata to memory + } + } +} \ No newline at end of file diff --git a/ethers-solc/tests/project.rs b/ethers-solc/tests/project.rs index 4777c041..bf5d3c39 100644 --- a/ethers-solc/tests/project.rs +++ b/ethers-solc/tests/project.rs @@ -92,6 +92,35 @@ fn can_compile_dapp_sample() { assert_eq!(cache, updated_cache); } +#[test] +fn can_compile_yul_sample() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/yul-sample"); + let paths = ProjectPathsConfig::builder().sources(root); + let project = TempProject::::new(paths).unwrap(); + + let compiled = project.compile().unwrap(); + dbg!(compiled.clone()); + assert!(compiled.find("Dapp").is_some()); + assert!(!compiled.has_compiler_errors()); + + // nothing to compile + let compiled = project.compile().unwrap(); + assert!(compiled.find("Dapp").is_some()); + assert!(compiled.is_unchanged()); + + let cache = SolFilesCache::read(project.cache_path()).unwrap(); + + // delete artifacts + std::fs::remove_dir_all(&project.paths().artifacts).unwrap(); + let compiled = project.compile().unwrap(); + assert!(compiled.find("Dapp").is_some()); + assert!(!compiled.is_unchanged()); + + let updated_cache = SolFilesCache::read(project.cache_path()).unwrap(); + assert_eq!(cache, updated_cache); +} + + #[test] fn can_compile_configured() { let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/dapp-sample");