Repository: gakonst/ethers-rs
Pull request #812 (2022-01-19 03:17:21)

chore(deps): bump ethabi from `5781964` to `c622438`
Bumps [ethabi](https://github.com/rust-ethereum/ethabi) from `5781964` to `c622438`.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/rust-ethereum/ethabi/commit/c622438f9fd2ac2f9b3c38ecb1ca760c069d9ec2"><code>c622438</code></a> add ether units parsing to lenient uint tokenizer (<a href="https://github-redirect.dependabot.com/rust-ethereum/ethabi/issues/255">#255</a>)</li>
<li>See full diff in <a href="https://github.com/rust-ethereum/ethabi/compare/5781964ae40a7e16fafe7d1bfcc39cb17989e3c5...c622438f9fd2ac2f9b3c38ecb1ca760c069d9ec2">compare view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c3be326d..10f1d6fb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -34,6 +34,8 @@
 
 ### Unreleased
 
+- Fix duplicate files during flattening
+  [#813](https://github.com/gakonst/ethers-rs/pull/813)
 - Add ability to flatten file imports
   [#774](https://github.com/gakonst/ethers-rs/pull/774)
 - Add dependency graph and resolve all imported libraryfiles
diff --git a/Cargo.lock b/Cargo.lock
index 149018a1..6ce2f2c1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1051,10 +1051,12 @@ dependencies = [
 [[package]]
 name = "ethabi"
 version = "16.0.0"
-source = "git+https://github.com/rust-ethereum/ethabi?branch=master#5781964ae40a7e16fafe7d1bfcc39cb17989e3c5"
+source = "git+https://github.com/rust-ethereum/ethabi?branch=master#c622438f9fd2ac2f9b3c38ecb1ca760c069d9ec2"
 dependencies = [
  "ethereum-types",
  "hex",
+ "once_cell",
+ "regex",
  "serde",
  "serde_json",
  "sha3",
diff --git a/ethers-solc/src/config.rs b/ethers-solc/src/config.rs
index 8ed92257..6308fdf2 100644
--- a/ethers-solc/src/config.rs
+++ b/ethers-solc/src/config.rs
@@ -176,7 +176,7 @@ impl ProjectPathsConfig {
     pub fn flatten(&self, target: &Path) -> Result<String> {
         tracing::trace!("flattening file");
         let graph = Graph::resolve(self)?;
-        self.flatten_node(target, &graph, false, false)
+        self.flatten_node(target, &graph, &mut vec![], false, false)
     }
 
     /// Flattens a single node from the dependency graph
@@ -184,6 +184,7 @@ impl ProjectPathsConfig {
         &self,
         target: &Path,
         graph: &Graph,
+        imported: &mut Vec<usize>,
         strip_version_pragma: bool,
         strip_license: bool,
     ) -> Result<String> {
@@ -193,6 +194,11 @@ impl ProjectPathsConfig {
         let target_index = graph.files().get(target).ok_or_else(|| {
             SolcError::msg(format!("cannot resolve file at \"{:?}\"", target.display()))
         })?;
+
+        if imported.iter().any(|&idx| idx == *target_index) {
+            return Ok(String::new())
+        }
+
         let target_node = graph.node(*target_index);
 
         let mut imports = target_node.imports().clone();
@@ -219,7 +225,7 @@ impl ProjectPathsConfig {
 
         for import in imports.iter() {
             let import_path = self.resolve_import(target_dir, import.data())?;
-            let import_content = self.flatten_node(&import_path, graph, true, true)?;
+            let import_content = self.flatten_node(&import_path, graph, imported, true, true)?;
             let import_content = import_content.trim().as_bytes().to_owned();
             let import_content_len = import_content.len() as isize;
             let (start, end) = import.loc_by_offset(offset);
@@ -230,6 +236,7 @@ impl ProjectPathsConfig {
         let result = String::from_utf8(content).map_err(|err| {
             SolcError::msg(format!("failed to convert extended bytes to string: {}", err))
         })?;
+        imported.push(*target_index);
 
         Ok(result)
     }


Test patch:
diff --git a/ethers-solc/test-data/flatten-sample/contracts/Bar.sol b/ethers-solc/test-data/flatten-sample/contracts/Bar.sol
new file mode 100644
index 00000000..5cb19aba
--- /dev/null
+++ b/ethers-solc/test-data/flatten-sample/contracts/Bar.sol
@@ -0,0 +1,4 @@
+//SPDX-License-Identifier: Unlicense
+pragma solidity >=0.6.0;
+
+contract Bar {}
diff --git a/ethers-solc/test-data/flatten-sample/contracts/Foo.sol b/ethers-solc/test-data/flatten-sample/contracts/Foo.sol
new file mode 100644
index 00000000..f9cf562d
--- /dev/null
+++ b/ethers-solc/test-data/flatten-sample/contracts/Foo.sol
@@ -0,0 +1,6 @@
+//SPDX-License-Identifier: Unlicense
+pragma solidity >=0.6.0;
+
+import { Bar } from './Bar.sol';
+
+contract Foo {}
diff --git a/ethers-solc/test-data/flatten-sample/contracts/FooBar.sol b/ethers-solc/test-data/flatten-sample/contracts/FooBar.sol
new file mode 100644
index 00000000..eda3b10b
--- /dev/null
+++ b/ethers-solc/test-data/flatten-sample/contracts/FooBar.sol
@@ -0,0 +1,7 @@
+//SPDX-License-Identifier: Unlicense
+pragma solidity >=0.6.0;
+
+import { Bar } from './Bar.sol';
+import { Foo } from './Foo.sol';
+
+contract FooBar {}
diff --git a/ethers-solc/tests/project.rs b/ethers-solc/tests/project.rs
index 2a9a91c8..0025c77e 100644
--- a/ethers-solc/tests/project.rs
+++ b/ethers-solc/tests/project.rs
@@ -360,3 +360,20 @@ fn can_flatten_file_in_dapp_sample() {
     assert!(result.find("contract Dapp").is_some());
     assert!(result.find("contract DappTest").is_some());
 }
+
+#[test]
+fn can_flatten_file_with_duplicates() {
+    let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test-data/flatten-sample");
+    let paths = ProjectPathsConfig::builder().sources(root.join("contracts"));
+    let project = TempProject::<MinimalCombinedArtifacts>::new(paths).unwrap();
+
+    let target = root.join("contracts/FooBar.sol");
+
+    let result = project.flatten(&target);
+    assert!(result.is_ok());
+
+    let result = result.unwrap();
+    assert!(result.matches("contract Foo {").collect::<Vec<_>>().len() == 1);
+    assert!(result.matches("contract Bar {").collect::<Vec<_>>().len() == 1);
+    assert!(result.matches("contract FooBar {").collect::<Vec<_>>().len() == 1);
+}