We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`slither-flat` doesn't flatten dYdX solo contracts correctly
Hi There,

Thanks for building `slither-flat`! It seems to be a lot more forgivign than `soljitsu` or `truffle-flatten`. I'm struggling, however, with using it to flatten dYdX contracts.

**How to reproduce**

```bash
#!/usr/bin/bash

# Dependency: npm, nvm
# Better not to run this as a script

# Get the repository
echo "solo" > .gitignore
git clone https://github.com/dydxprotocol/solo.git
cd solo

# Install javascript dependencies
npm i keccakjs --save
npm i solium@^1.0.0 --save
npm i acorn --save
npm i

# Testing that everything installed correctly (make sure Docker is enabled at this point)
nvm use 10.16.2  # Need this version to compile contracts
npm test

# Install and run slither-flat
cd ..
pipenv install slither-analyzer
pipenv run slither-flat solo
```

**Issues**

I noticed two issues with these contracts:

1) Duplicate contracts

In particular, `ReentrancyGuard` appeared many times in different contract files (and multiple times per file)

2) Missing characters

In particular, `ReentrancyGuard` appeared as `ontract ReentrancyGuard` (missing a `c`)

3) Some contracts don't exist in their own file anymore

Contract `external/OnlySolo.sol` doesn't have a corresponding `OnlySolo.sol` file in the output, instead it's embedded inline with other contracts in multiple places. [perhaps this is intentional]

**Potential problems**

With `truffle-flatten` it flagged a circular dependency in the contracts, so perhaps this is related to the issue here.
`slither-flat` doesn't flatten dYdX solo contracts correctly
Hi There,

Thanks for building `slither-flat`! It seems to be a lot more forgivign than `soljitsu` or `truffle-flatten`. I'm struggling, however, with using it to flatten dYdX contracts.

**How to reproduce**

```bash
#!/usr/bin/bash

# Dependency: npm, nvm
# Better not to run this as a script

# Get the repository
echo "solo" > .gitignore
git clone https://github.com/dydxprotocol/solo.git
cd solo

# Install javascript dependencies
npm i keccakjs --save
npm i solium@^1.0.0 --save
npm i acorn --save
npm i

# Testing that everything installed correctly (make sure Docker is enabled at this point)
nvm use 10.16.2  # Need this version to compile contracts
npm test

# Install and run slither-flat
cd ..
pipenv install slither-analyzer
pipenv run slither-flat solo
```

**Issues**

I noticed two issues with these contracts:

1) Duplicate contracts

In particular, `ReentrancyGuard` appeared many times in different contract files (and multiple times per file)

2) Missing characters

In particular, `ReentrancyGuard` appeared as `ontract ReentrancyGuard` (missing a `c`)

3) Some contracts don't exist in their own file anymore

Contract `external/OnlySolo.sol` doesn't have a corresponding `OnlySolo.sol` file in the output, instead it's embedded inline with other contracts in multiple places. [perhaps this is intentional]

**Potential problems**

With `truffle-flatten` it flagged a circular dependency in the contracts, so perhaps this is related to the issue here.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `slither/tools/flattening/flattening.py`
Content:
```
1 from pathlib import Path
2 import re
3 import logging
4 from collections import namedtuple
5 
6 from slither.core.declarations import SolidityFunction
7 from slither.exceptions import SlitherException
8 from slither.core.solidity_types.user_defined_type import UserDefinedType
9 from slither.core.declarations.structure import Structure
10 from slither.core.declarations.enum import Enum
11 from slither.core.declarations.contract import Contract
12 from slither.slithir.operations import NewContract, TypeConversion, SolidityCall
13 
14 logger = logging.getLogger("Slither-flattening")
15 
16 # index: where to start
17 # patch_type:
18 #   - public_to_external: public to external (external-to-public)
19 #   - calldata_to_memory: calldata to memory (external-to-public)
20 #   - line_removal: remove the line (remove-assert)
21 Patch = namedtuple('PatchExternal', ['index', 'patch_type'])
22 
23 class Flattening:
24     DEFAULT_EXPORT_PATH = Path('crytic-export/flattening')
25 
26     def __init__(self, slither, external_to_public=False, remove_assert=False, private_to_internal=False):
27         self._source_codes = {}
28         self._slither = slither
29         self._external_to_public = external_to_public
30         self._remove_assert = remove_assert
31         self._use_abi_encoder_v2 = False
32         self._private_to_internal = private_to_internal
33 
34         self._check_abi_encoder_v2()
35 
36         for contract in slither.contracts:
37             self._get_source_code(contract)
38 
39     def _check_abi_encoder_v2(self):
40         for p in self._slither.pragma_directives:
41             if 'ABIEncoderV2' in str(p.directive):
42                 self._use_abi_encoder_v2 = True
43                 return
44 
45     def _get_source_code(self, contract):
46         src_mapping = contract.source_mapping
47         content = self._slither.source_code[src_mapping['filename_absolute']]
48         start = src_mapping['start']
49         end = src_mapping['start'] + src_mapping['length']
50 
51         to_patch = []
52         # interface must use external
53         if self._external_to_public and contract.contract_kind != "interface":
54             for f in contract.functions_declared:
55                 # fallback must be external
56                 if f.is_fallback or f.is_constructor_variables:
57                     continue
58                 if f.visibility == 'external':
59                     attributes_start = (f.parameters_src.source_mapping['start'] +
60                                         f.parameters_src.source_mapping['length'])
61                     attributes_end = f.returns_src.source_mapping['start']
62                     attributes = content[attributes_start:attributes_end]
63                     regex = re.search(r'((\sexternal)\s+)|(\sexternal)$|(\)external)$', attributes)
64                     if regex:
65                         to_patch.append(Patch(attributes_start + regex.span()[0] + 1, 'public_to_external'))
66                     else:
67                         raise SlitherException(f'External keyword not found {f.name} {attributes}')
68 
69                     for var in f.parameters:
70                         if var.location == "calldata":
71                             calldata_start = var.source_mapping['start']
72                             calldata_end = calldata_start + var.source_mapping['length']
73                             calldata_idx = content[calldata_start:calldata_end].find(' calldata ')
74                             to_patch.append(Patch(calldata_start + calldata_idx + 1, 'calldata_to_memory'))
75 
76         if self._private_to_internal:
77             for variable in contract.state_variables_declared:
78                 if variable.visibility == 'private':
79                     print(variable.source_mapping)
80                     attributes_start = variable.source_mapping['start']
81                     attributes_end = attributes_start + variable.source_mapping['length']
82                     attributes = content[attributes_start:attributes_end]
83                     print(attributes)
84                     regex = re.search(r' private ', attributes)
85                     if regex:
86                         to_patch.append(Patch(attributes_start + regex.span()[0] + 1, 'private_to_internal'))
87                     else:
88                         raise SlitherException(f'private keyword not found {v.name} {attributes}')
89 
90         if self._remove_assert:
91             for function in contract.functions_and_modifiers_declared:
92                 for node in function.nodes:
93                     for ir in node.irs:
94                         if isinstance(ir, SolidityCall) and ir.function == SolidityFunction('assert(bool)'):
95                             to_patch.append(Patch(node.source_mapping['start'], 'line_removal'))
96                             logger.info(f'Code commented: {node.expression} ({node.source_mapping_str})')
97 
98         to_patch.sort(key=lambda x: x.index, reverse=True)
99 
100         content = content[start:end]
101         for patch in to_patch:
102             patch_type = patch.patch_type
103             index = patch.index
104             index = index - start
105             if patch_type == 'public_to_external':
106                 content = content[:index] + 'public' + content[index + len('external'):]
107             if patch_type == 'private_to_internal':
108                 content = content[:index] + 'internal' + content[index + len('private'):]
109             elif patch_type == 'calldata_to_memory':
110                 content = content[:index] + 'memory' + content[index + len('calldata'):]
111             else:
112                 assert patch_type == 'line_removal'
113                 content = content[:index] + ' // ' + content[index:]
114 
115         self._source_codes[contract] = content
116 
117     def _export_from_type(self, t, contract, exported, list_contract):
118         if isinstance(t, UserDefinedType):
119             if isinstance(t.type, (Enum, Structure)):
120                 if t.type.contract != contract and not t.type.contract in exported:
121                     self._export_contract(t.type.contract, exported, list_contract)
122             else:
123                 assert isinstance(t.type, Contract)
124                 if t.type != contract and not t.type in exported:
125                     self._export_contract(t.type, exported, list_contract)
126 
127     def _export_contract(self, contract, exported, list_contract):
128         if contract.name in exported:
129             return
130         exported.add(contract.name)
131         for inherited in contract.inheritance:
132             self._export_contract(inherited, exported, list_contract)
133 
134         # Find all the external contracts called
135         externals = contract.all_library_calls + contract.all_high_level_calls
136         # externals is a list of (contract, function)
137         # We also filter call to itself to avoid infilite loop
138         externals = list(set([e[0] for e in externals if e[0] != contract]))
139 
140         for inherited in externals:
141             self._export_contract(inherited, exported, list_contract)
142 
143         # Find all the external contracts use as a base type
144         local_vars = []
145         for f in contract.functions_declared:
146             local_vars += f.variables
147 
148         for v in contract.variables + local_vars:
149             self._export_from_type(v.type, contract, exported, list_contract)
150 
151         # Find all convert and "new" operation that can lead to use an external contract
152         for f in contract.functions_declared:
153             for ir in f.slithir_operations:
154                 if isinstance(ir, NewContract):
155                     if ir.contract_created != contract and not ir.contract_created in exported:
156                         self._export_contract(ir.contract_created, exported, list_contract)
157                 if isinstance(ir, TypeConversion):
158                     self._export_from_type(ir.type, contract, exported, list_contract)
159         list_contract.append(self._source_codes[contract])
160 
161     def _export(self, contract, ret):
162         self._export_contract(contract, set(), ret)
163         path = Path(self.DEFAULT_EXPORT_PATH, f'{contract.name}.sol')
164         logger.info(f'Export {path}')
165         with open(path, 'w') as f:
166             if self._slither.solc_version:
167                 f.write(f'pragma solidity {self._slither.solc_version};\n')
168             if self._use_abi_encoder_v2:
169                 f.write('pragma experimental ABIEncoderV2;\n')
170             f.write('\n'.join(ret))
171             f.write('\n')
172 
173     def export(self, target=None):
174 
175         if not self.DEFAULT_EXPORT_PATH.exists():
176             self.DEFAULT_EXPORT_PATH.mkdir(parents=True)
177 
178         if target is None:
179             for contract in self._slither.contracts_derived:
180                 ret = []
181                 self._export(contract, ret)
182         else:
183             contract = self._slither.get_contract_from_name(target)
184             if contract is None:
185                 logger.error(f'{target} not found')
186             else:
187                 ret = []
188                 self._export(contract, ret)
189
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/slither/tools/flattening/flattening.py b/slither/tools/flattening/flattening.py
--- a/slither/tools/flattening/flattening.py
+++ b/slither/tools/flattening/flattening.py
@@ -4,6 +4,7 @@
 from collections import namedtuple
 
 from slither.core.declarations import SolidityFunction
+from slither.core.solidity_types import MappingType, ArrayType
 from slither.exceptions import SlitherException
 from slither.core.solidity_types.user_defined_type import UserDefinedType
 from slither.core.declarations.structure import Structure
@@ -20,6 +21,7 @@
 #   - line_removal: remove the line (remove-assert)
 Patch = namedtuple('PatchExternal', ['index', 'patch_type'])
 
+
 class Flattening:
     DEFAULT_EXPORT_PATH = Path('crytic-export/flattening')
 
@@ -44,7 +46,7 @@
 
     def _get_source_code(self, contract):
         src_mapping = contract.source_mapping
-        content = self._slither.source_code[src_mapping['filename_absolute']]
+        content = self._slither.source_code[src_mapping['filename_absolute']].encode('utf8')
         start = src_mapping['start']
         end = src_mapping['start'] + src_mapping['length']
 
@@ -112,17 +114,22 @@
                 assert patch_type == 'line_removal'
                 content = content[:index] + ' // ' + content[index:]
 
-        self._source_codes[contract] = content
+        self._source_codes[contract] = content.decode('utf8')
 
     def _export_from_type(self, t, contract, exported, list_contract):
         if isinstance(t, UserDefinedType):
             if isinstance(t.type, (Enum, Structure)):
-                if t.type.contract != contract and not t.type.contract in exported:
+                if t.type.contract != contract and t.type.contract not in exported:
                     self._export_contract(t.type.contract, exported, list_contract)
             else:
                 assert isinstance(t.type, Contract)
-                if t.type != contract and not t.type in exported:
+                if t.type != contract and t.type not in exported:
                     self._export_contract(t.type, exported, list_contract)
+        elif isinstance(t, MappingType):
+            self._export_from_type(t.type_from, contract, exported, list_contract)
+            self._export_from_type(t.type_to, contract, exported, list_contract)
+        elif isinstance(t, ArrayType):
+            self._export_from_type(t.type, contract, exported, list_contract)
 
     def _export_contract(self, contract, exported, list_contract):
         if contract.name in exported:
@@ -148,6 +155,10 @@
         for v in contract.variables + local_vars:
             self._export_from_type(v.type, contract, exported, list_contract)
 
+        for s in contract.structures:
+            for elem in s.elems.values():
+                self._export_from_type(elem.type, contract, exported, list_contract)
+
         # Find all convert and "new" operation that can lead to use an external contract
         for f in contract.functions_declared:
             for ir in f.slithir_operations:

{"golden_diff": "diff --git a/slither/tools/flattening/flattening.py b/slither/tools/flattening/flattening.py\n--- a/slither/tools/flattening/flattening.py\n+++ b/slither/tools/flattening/flattening.py\n@@ -4,6 +4,7 @@\n from collections import namedtuple\n \n from slither.core.declarations import SolidityFunction\n+from slither.core.solidity_types import MappingType, ArrayType\n from slither.exceptions import SlitherException\n from slither.core.solidity_types.user_defined_type import UserDefinedType\n from slither.core.declarations.structure import Structure\n@@ -20,6 +21,7 @@\n #   - line_removal: remove the line (remove-assert)\n Patch = namedtuple('PatchExternal', ['index', 'patch_type'])\n \n+\n class Flattening:\n     DEFAULT_EXPORT_PATH = Path('crytic-export/flattening')\n \n@@ -44,7 +46,7 @@\n \n     def _get_source_code(self, contract):\n         src_mapping = contract.source_mapping\n-        content = self._slither.source_code[src_mapping['filename_absolute']]\n+        content = self._slither.source_code[src_mapping['filename_absolute']].encode('utf8')\n         start = src_mapping['start']\n         end = src_mapping['start'] + src_mapping['length']\n \n@@ -112,17 +114,22 @@\n                 assert patch_type == 'line_removal'\n                 content = content[:index] + ' // ' + content[index:]\n \n-        self._source_codes[contract] = content\n+        self._source_codes[contract] = content.decode('utf8')\n \n     def _export_from_type(self, t, contract, exported, list_contract):\n         if isinstance(t, UserDefinedType):\n             if isinstance(t.type, (Enum, Structure)):\n-                if t.type.contract != contract and not t.type.contract in exported:\n+                if t.type.contract != contract and t.type.contract not in exported:\n                     self._export_contract(t.type.contract, exported, list_contract)\n             else:\n                 assert isinstance(t.type, Contract)\n-                if t.type != contract and not t.type in exported:\n+                if t.type != contract and t.type not in exported:\n                     self._export_contract(t.type, exported, list_contract)\n+        elif isinstance(t, MappingType):\n+            self._export_from_type(t.type_from, contract, exported, list_contract)\n+            self._export_from_type(t.type_to, contract, exported, list_contract)\n+        elif isinstance(t, ArrayType):\n+            self._export_from_type(t.type, contract, exported, list_contract)\n \n     def _export_contract(self, contract, exported, list_contract):\n         if contract.name in exported:\n@@ -148,6 +155,10 @@\n         for v in contract.variables + local_vars:\n             self._export_from_type(v.type, contract, exported, list_contract)\n \n+        for s in contract.structures:\n+            for elem in s.elems.values():\n+                self._export_from_type(elem.type, contract, exported, list_contract)\n+\n         # Find all convert and \"new\" operation that can lead to use an external contract\n         for f in contract.functions_declared:\n             for ir in f.slithir_operations:\n", "issue": "`slither-flat` doesn't flatten dYdX solo contracts correctly\nHi There,\r\n\r\nThanks for building `slither-flat`! It seems to be a lot more forgivign than `soljitsu` or `truffle-flatten`. I'm struggling, however, with using it to flatten dYdX contracts.\r\n\r\n**How to reproduce**\r\n\r\n```bash\r\n#!/usr/bin/bash\r\n\r\n# Dependency: npm, nvm\r\n# Better not to run this as a script\r\n\r\n# Get the repository\r\necho \"solo\" > .gitignore\r\ngit clone https://github.com/dydxprotocol/solo.git\r\ncd solo\r\n\r\n# Install javascript dependencies\r\nnpm i keccakjs --save\r\nnpm i solium@^1.0.0 --save\r\nnpm i acorn --save\r\nnpm i\r\n\r\n# Testing that everything installed correctly (make sure Docker is enabled at this point)\r\nnvm use 10.16.2  # Need this version to compile contracts\r\nnpm test\r\n\r\n# Install and run slither-flat\r\ncd ..\r\npipenv install slither-analyzer\r\npipenv run slither-flat solo\r\n```\r\n\r\n**Issues**\r\n\r\nI noticed two issues with these contracts:\r\n\r\n1) Duplicate contracts\r\n\r\nIn particular, `ReentrancyGuard` appeared many times in different contract files (and multiple times per file)\r\n\r\n2) Missing characters\r\n\r\nIn particular, `ReentrancyGuard` appeared as `ontract ReentrancyGuard` (missing a `c`)\r\n\r\n3) Some contracts don't exist in their own file anymore\r\n\r\nContract `external/OnlySolo.sol` doesn't have a corresponding `OnlySolo.sol` file in the output, instead it's embedded inline with other contracts in multiple places. [perhaps this is intentional]\r\n\r\n**Potential problems**\r\n\r\nWith `truffle-flatten` it flagged a circular dependency in the contracts, so perhaps this is related to the issue here.\n`slither-flat` doesn't flatten dYdX solo contracts correctly\nHi There,\r\n\r\nThanks for building `slither-flat`! It seems to be a lot more forgivign than `soljitsu` or `truffle-flatten`. I'm struggling, however, with using it to flatten dYdX contracts.\r\n\r\n**How to reproduce**\r\n\r\n```bash\r\n#!/usr/bin/bash\r\n\r\n# Dependency: npm, nvm\r\n# Better not to run this as a script\r\n\r\n# Get the repository\r\necho \"solo\" > .gitignore\r\ngit clone https://github.com/dydxprotocol/solo.git\r\ncd solo\r\n\r\n# Install javascript dependencies\r\nnpm i keccakjs --save\r\nnpm i solium@^1.0.0 --save\r\nnpm i acorn --save\r\nnpm i\r\n\r\n# Testing that everything installed correctly (make sure Docker is enabled at this point)\r\nnvm use 10.16.2  # Need this version to compile contracts\r\nnpm test\r\n\r\n# Install and run slither-flat\r\ncd ..\r\npipenv install slither-analyzer\r\npipenv run slither-flat solo\r\n```\r\n\r\n**Issues**\r\n\r\nI noticed two issues with these contracts:\r\n\r\n1) Duplicate contracts\r\n\r\nIn particular, `ReentrancyGuard` appeared many times in different contract files (and multiple times per file)\r\n\r\n2) Missing characters\r\n\r\nIn particular, `ReentrancyGuard` appeared as `ontract ReentrancyGuard` (missing a `c`)\r\n\r\n3) Some contracts don't exist in their own file anymore\r\n\r\nContract `external/OnlySolo.sol` doesn't have a corresponding `OnlySolo.sol` file in the output, instead it's embedded inline with other contracts in multiple places. [perhaps this is intentional]\r\n\r\n**Potential problems**\r\n\r\nWith `truffle-flatten` it flagged a circular dependency in the contracts, so perhaps this is related to the issue here.\n", "before_files": [{"content": "from pathlib import Path\nimport re\nimport logging\nfrom collections import namedtuple\n\nfrom slither.core.declarations import SolidityFunction\nfrom slither.exceptions import SlitherException\nfrom slither.core.solidity_types.user_defined_type import UserDefinedType\nfrom slither.core.declarations.structure import Structure\nfrom slither.core.declarations.enum import Enum\nfrom slither.core.declarations.contract import Contract\nfrom slither.slithir.operations import NewContract, TypeConversion, SolidityCall\n\nlogger = logging.getLogger(\"Slither-flattening\")\n\n# index: where to start\n# patch_type:\n#   - public_to_external: public to external (external-to-public)\n#   - calldata_to_memory: calldata to memory (external-to-public)\n#   - line_removal: remove the line (remove-assert)\nPatch = namedtuple('PatchExternal', ['index', 'patch_type'])\n\nclass Flattening:\n    DEFAULT_EXPORT_PATH = Path('crytic-export/flattening')\n\n    def __init__(self, slither, external_to_public=False, remove_assert=False, private_to_internal=False):\n        self._source_codes = {}\n        self._slither = slither\n        self._external_to_public = external_to_public\n        self._remove_assert = remove_assert\n        self._use_abi_encoder_v2 = False\n        self._private_to_internal = private_to_internal\n\n        self._check_abi_encoder_v2()\n\n        for contract in slither.contracts:\n            self._get_source_code(contract)\n\n    def _check_abi_encoder_v2(self):\n        for p in self._slither.pragma_directives:\n            if 'ABIEncoderV2' in str(p.directive):\n                self._use_abi_encoder_v2 = True\n                return\n\n    def _get_source_code(self, contract):\n        src_mapping = contract.source_mapping\n        content = self._slither.source_code[src_mapping['filename_absolute']]\n        start = src_mapping['start']\n        end = src_mapping['start'] + src_mapping['length']\n\n        to_patch = []\n        # interface must use external\n        if self._external_to_public and contract.contract_kind != \"interface\":\n            for f in contract.functions_declared:\n                # fallback must be external\n                if f.is_fallback or f.is_constructor_variables:\n                    continue\n                if f.visibility == 'external':\n                    attributes_start = (f.parameters_src.source_mapping['start'] +\n                                        f.parameters_src.source_mapping['length'])\n                    attributes_end = f.returns_src.source_mapping['start']\n                    attributes = content[attributes_start:attributes_end]\n                    regex = re.search(r'((\\sexternal)\\s+)|(\\sexternal)$|(\\)external)$', attributes)\n                    if regex:\n                        to_patch.append(Patch(attributes_start + regex.span()[0] + 1, 'public_to_external'))\n                    else:\n                        raise SlitherException(f'External keyword not found {f.name} {attributes}')\n\n                    for var in f.parameters:\n                        if var.location == \"calldata\":\n                            calldata_start = var.source_mapping['start']\n                            calldata_end = calldata_start + var.source_mapping['length']\n                            calldata_idx = content[calldata_start:calldata_end].find(' calldata ')\n                            to_patch.append(Patch(calldata_start + calldata_idx + 1, 'calldata_to_memory'))\n\n        if self._private_to_internal:\n            for variable in contract.state_variables_declared:\n                if variable.visibility == 'private':\n                    print(variable.source_mapping)\n                    attributes_start = variable.source_mapping['start']\n                    attributes_end = attributes_start + variable.source_mapping['length']\n                    attributes = content[attributes_start:attributes_end]\n                    print(attributes)\n                    regex = re.search(r' private ', attributes)\n                    if regex:\n                        to_patch.append(Patch(attributes_start + regex.span()[0] + 1, 'private_to_internal'))\n                    else:\n                        raise SlitherException(f'private keyword not found {v.name} {attributes}')\n\n        if self._remove_assert:\n            for function in contract.functions_and_modifiers_declared:\n                for node in function.nodes:\n                    for ir in node.irs:\n                        if isinstance(ir, SolidityCall) and ir.function == SolidityFunction('assert(bool)'):\n                            to_patch.append(Patch(node.source_mapping['start'], 'line_removal'))\n                            logger.info(f'Code commented: {node.expression} ({node.source_mapping_str})')\n\n        to_patch.sort(key=lambda x: x.index, reverse=True)\n\n        content = content[start:end]\n        for patch in to_patch:\n            patch_type = patch.patch_type\n            index = patch.index\n            index = index - start\n            if patch_type == 'public_to_external':\n                content = content[:index] + 'public' + content[index + len('external'):]\n            if patch_type == 'private_to_internal':\n                content = content[:index] + 'internal' + content[index + len('private'):]\n            elif patch_type == 'calldata_to_memory':\n                content = content[:index] + 'memory' + content[index + len('calldata'):]\n            else:\n                assert patch_type == 'line_removal'\n                content = content[:index] + ' // ' + content[index:]\n\n        self._source_codes[contract] = content\n\n    def _export_from_type(self, t, contract, exported, list_contract):\n        if isinstance(t, UserDefinedType):\n            if isinstance(t.type, (Enum, Structure)):\n                if t.type.contract != contract and not t.type.contract in exported:\n                    self._export_contract(t.type.contract, exported, list_contract)\n            else:\n                assert isinstance(t.type, Contract)\n                if t.type != contract and not t.type in exported:\n                    self._export_contract(t.type, exported, list_contract)\n\n    def _export_contract(self, contract, exported, list_contract):\n        if contract.name in exported:\n            return\n        exported.add(contract.name)\n        for inherited in contract.inheritance:\n            self._export_contract(inherited, exported, list_contract)\n\n        # Find all the external contracts called\n        externals = contract.all_library_calls + contract.all_high_level_calls\n        # externals is a list of (contract, function)\n        # We also filter call to itself to avoid infilite loop\n        externals = list(set([e[0] for e in externals if e[0] != contract]))\n\n        for inherited in externals:\n            self._export_contract(inherited, exported, list_contract)\n\n        # Find all the external contracts use as a base type\n        local_vars = []\n        for f in contract.functions_declared:\n            local_vars += f.variables\n\n        for v in contract.variables + local_vars:\n            self._export_from_type(v.type, contract, exported, list_contract)\n\n        # Find all convert and \"new\" operation that can lead to use an external contract\n        for f in contract.functions_declared:\n            for ir in f.slithir_operations:\n                if isinstance(ir, NewContract):\n                    if ir.contract_created != contract and not ir.contract_created in exported:\n                        self._export_contract(ir.contract_created, exported, list_contract)\n                if isinstance(ir, TypeConversion):\n                    self._export_from_type(ir.type, contract, exported, list_contract)\n        list_contract.append(self._source_codes[contract])\n\n    def _export(self, contract, ret):\n        self._export_contract(contract, set(), ret)\n        path = Path(self.DEFAULT_EXPORT_PATH, f'{contract.name}.sol')\n        logger.info(f'Export {path}')\n        with open(path, 'w') as f:\n            if self._slither.solc_version:\n                f.write(f'pragma solidity {self._slither.solc_version};\\n')\n            if self._use_abi_encoder_v2:\n                f.write('pragma experimental ABIEncoderV2;\\n')\n            f.write('\\n'.join(ret))\n            f.write('\\n')\n\n    def export(self, target=None):\n\n        if not self.DEFAULT_EXPORT_PATH.exists():\n            self.DEFAULT_EXPORT_PATH.mkdir(parents=True)\n\n        if target is None:\n            for contract in self._slither.contracts_derived:\n                ret = []\n                self._export(contract, ret)\n        else:\n            contract = self._slither.get_contract_from_name(target)\n            if contract is None:\n                logger.error(f'{target} not found')\n            else:\n                ret = []\n                self._export(contract, ret)\n", "path": "slither/tools/flattening/flattening.py"}], "after_files": [{"content": "from pathlib import Path\nimport re\nimport logging\nfrom collections import namedtuple\n\nfrom slither.core.declarations import SolidityFunction\nfrom slither.core.solidity_types import MappingType, ArrayType\nfrom slither.exceptions import SlitherException\nfrom slither.core.solidity_types.user_defined_type import UserDefinedType\nfrom slither.core.declarations.structure import Structure\nfrom slither.core.declarations.enum import Enum\nfrom slither.core.declarations.contract import Contract\nfrom slither.slithir.operations import NewContract, TypeConversion, SolidityCall\n\nlogger = logging.getLogger(\"Slither-flattening\")\n\n# index: where to start\n# patch_type:\n#   - public_to_external: public to external (external-to-public)\n#   - calldata_to_memory: calldata to memory (external-to-public)\n#   - line_removal: remove the line (remove-assert)\nPatch = namedtuple('PatchExternal', ['index', 'patch_type'])\n\n\nclass Flattening:\n    DEFAULT_EXPORT_PATH = Path('crytic-export/flattening')\n\n    def __init__(self, slither, external_to_public=False, remove_assert=False, private_to_internal=False):\n        self._source_codes = {}\n        self._slither = slither\n        self._external_to_public = external_to_public\n        self._remove_assert = remove_assert\n        self._use_abi_encoder_v2 = False\n        self._private_to_internal = private_to_internal\n\n        self._check_abi_encoder_v2()\n\n        for contract in slither.contracts:\n            self._get_source_code(contract)\n\n    def _check_abi_encoder_v2(self):\n        for p in self._slither.pragma_directives:\n            if 'ABIEncoderV2' in str(p.directive):\n                self._use_abi_encoder_v2 = True\n                return\n\n    def _get_source_code(self, contract):\n        src_mapping = contract.source_mapping\n        content = self._slither.source_code[src_mapping['filename_absolute']].encode('utf8')\n        start = src_mapping['start']\n        end = src_mapping['start'] + src_mapping['length']\n\n        to_patch = []\n        # interface must use external\n        if self._external_to_public and contract.contract_kind != \"interface\":\n            for f in contract.functions_declared:\n                # fallback must be external\n                if f.is_fallback or f.is_constructor_variables:\n                    continue\n                if f.visibility == 'external':\n                    attributes_start = (f.parameters_src.source_mapping['start'] +\n                                        f.parameters_src.source_mapping['length'])\n                    attributes_end = f.returns_src.source_mapping['start']\n                    attributes = content[attributes_start:attributes_end]\n                    regex = re.search(r'((\\sexternal)\\s+)|(\\sexternal)$|(\\)external)$', attributes)\n                    if regex:\n                        to_patch.append(Patch(attributes_start + regex.span()[0] + 1, 'public_to_external'))\n                    else:\n                        raise SlitherException(f'External keyword not found {f.name} {attributes}')\n\n                    for var in f.parameters:\n                        if var.location == \"calldata\":\n                            calldata_start = var.source_mapping['start']\n                            calldata_end = calldata_start + var.source_mapping['length']\n                            calldata_idx = content[calldata_start:calldata_end].find(' calldata ')\n                            to_patch.append(Patch(calldata_start + calldata_idx + 1, 'calldata_to_memory'))\n\n        if self._private_to_internal:\n            for variable in contract.state_variables_declared:\n                if variable.visibility == 'private':\n                    print(variable.source_mapping)\n                    attributes_start = variable.source_mapping['start']\n                    attributes_end = attributes_start + variable.source_mapping['length']\n                    attributes = content[attributes_start:attributes_end]\n                    print(attributes)\n                    regex = re.search(r' private ', attributes)\n                    if regex:\n                        to_patch.append(Patch(attributes_start + regex.span()[0] + 1, 'private_to_internal'))\n                    else:\n                        raise SlitherException(f'private keyword not found {v.name} {attributes}')\n\n        if self._remove_assert:\n            for function in contract.functions_and_modifiers_declared:\n                for node in function.nodes:\n                    for ir in node.irs:\n                        if isinstance(ir, SolidityCall) and ir.function == SolidityFunction('assert(bool)'):\n                            to_patch.append(Patch(node.source_mapping['start'], 'line_removal'))\n                            logger.info(f'Code commented: {node.expression} ({node.source_mapping_str})')\n\n        to_patch.sort(key=lambda x: x.index, reverse=True)\n\n        content = content[start:end]\n        for patch in to_patch:\n            patch_type = patch.patch_type\n            index = patch.index\n            index = index - start\n            if patch_type == 'public_to_external':\n                content = content[:index] + 'public' + content[index + len('external'):]\n            if patch_type == 'private_to_internal':\n                content = content[:index] + 'internal' + content[index + len('private'):]\n            elif patch_type == 'calldata_to_memory':\n                content = content[:index] + 'memory' + content[index + len('calldata'):]\n            else:\n                assert patch_type == 'line_removal'\n                content = content[:index] + ' // ' + content[index:]\n\n        self._source_codes[contract] = content.decode('utf8')\n\n    def _export_from_type(self, t, contract, exported, list_contract):\n        if isinstance(t, UserDefinedType):\n            if isinstance(t.type, (Enum, Structure)):\n                if t.type.contract != contract and t.type.contract not in exported:\n                    self._export_contract(t.type.contract, exported, list_contract)\n            else:\n                assert isinstance(t.type, Contract)\n                if t.type != contract and t.type not in exported:\n                    self._export_contract(t.type, exported, list_contract)\n        elif isinstance(t, MappingType):\n            self._export_from_type(t.type_from, contract, exported, list_contract)\n            self._export_from_type(t.type_to, contract, exported, list_contract)\n        elif isinstance(t, ArrayType):\n            self._export_from_type(t.type, contract, exported, list_contract)\n\n    def _export_contract(self, contract, exported, list_contract):\n        if contract.name in exported:\n            return\n        exported.add(contract.name)\n        for inherited in contract.inheritance:\n            self._export_contract(inherited, exported, list_contract)\n\n        # Find all the external contracts called\n        externals = contract.all_library_calls + contract.all_high_level_calls\n        # externals is a list of (contract, function)\n        # We also filter call to itself to avoid infilite loop\n        externals = list(set([e[0] for e in externals if e[0] != contract]))\n\n        for inherited in externals:\n            self._export_contract(inherited, exported, list_contract)\n\n        # Find all the external contracts use as a base type\n        local_vars = []\n        for f in contract.functions_declared:\n            local_vars += f.variables\n\n        for v in contract.variables + local_vars:\n            self._export_from_type(v.type, contract, exported, list_contract)\n\n        for s in contract.structures:\n            for elem in s.elems.values():\n                self._export_from_type(elem.type, contract, exported, list_contract)\n\n        # Find all convert and \"new\" operation that can lead to use an external contract\n        for f in contract.functions_declared:\n            for ir in f.slithir_operations:\n                if isinstance(ir, NewContract):\n                    if ir.contract_created != contract and not ir.contract_created in exported:\n                        self._export_contract(ir.contract_created, exported, list_contract)\n                if isinstance(ir, TypeConversion):\n                    self._export_from_type(ir.type, contract, exported, list_contract)\n        list_contract.append(self._source_codes[contract])\n\n    def _export(self, contract, ret):\n        self._export_contract(contract, set(), ret)\n        path = Path(self.DEFAULT_EXPORT_PATH, f'{contract.name}.sol')\n        logger.info(f'Export {path}')\n        with open(path, 'w') as f:\n            if self._slither.solc_version:\n                f.write(f'pragma solidity {self._slither.solc_version};\\n')\n            if self._use_abi_encoder_v2:\n                f.write('pragma experimental ABIEncoderV2;\\n')\n            f.write('\\n'.join(ret))\n            f.write('\\n')\n\n    def export(self, target=None):\n\n        if not self.DEFAULT_EXPORT_PATH.exists():\n            self.DEFAULT_EXPORT_PATH.mkdir(parents=True)\n\n        if target is None:\n            for contract in self._slither.contracts_derived:\n                ret = []\n                self._export(contract, ret)\n        else:\n            contract = self._slither.get_contract_from_name(target)\n            if contract is None:\n                logger.error(f'{target} not found')\n            else:\n                ret = []\n                self._export(contract, ret)\n", "path": "slither/tools/flattening/flattening.py"}]}