|
| 1 | +import os |
| 2 | +import json |
| 3 | +import logging |
| 4 | +import glob |
| 5 | + |
| 6 | + |
| 7 | +import subprocess |
| 8 | + |
| 9 | +from .types import Type |
| 10 | +from ..utils.naming import extract_filename, extract_name, combine_filename_name |
| 11 | + |
| 12 | +logger = logging.getLogger("CryticCompile") |
| 13 | + |
| 14 | + |
| 15 | +def compile(crytic_compile, target, **kwargs): |
| 16 | + crytic_compile.type = Type.DAPP |
| 17 | + dapp_ignore_compile = kwargs.get('dapp_ignore_compile', False) |
| 18 | + dir = os.path.join(target, "out") |
| 19 | + |
| 20 | + if not dapp_ignore_compile: |
| 21 | + _run_dapp() |
| 22 | + |
| 23 | + files = glob.glob(dir + '/**/*.sol.json', recursive=True) |
| 24 | + for file in files: |
| 25 | + with open(file) as f: |
| 26 | + targets_json = json.load(f) |
| 27 | + for original_contract_name, info in targets_json["contracts"].items(): |
| 28 | + contract_name = extract_name(original_contract_name) |
| 29 | + contract_filename = extract_filename(original_contract_name) |
| 30 | + crytic_compile.contracts_name.add(contract_name) |
| 31 | + crytic_compile.contracts_filenames[contract_name] = contract_filename |
| 32 | + crytic_compile.abis[contract_name] = json.loads(info['abi']) |
| 33 | + crytic_compile.init_bytecodes[contract_name] = info['bin'] |
| 34 | + crytic_compile.runtime_bytecodes[contract_name] = info['bin-runtime'] |
| 35 | + |
| 36 | + for path, info in targets_json["sources"].items(): |
| 37 | + crytic_compile.filenames.add(path) |
| 38 | + crytic_compile.asts[path] = info['AST'] |
| 39 | + |
| 40 | + |
| 41 | +def export(crytic_compile, **kwargs): |
| 42 | + export_dir = kwargs.get('export_dir', 'crytic-export') |
| 43 | + if not os.path.exists(export_dir): |
| 44 | + os.makedirs(export_dir) |
| 45 | + path = os.path.join(export_dir, "combined_solc.json") |
| 46 | + |
| 47 | + with open(path, 'w') as f: |
| 48 | + contracts = dict() |
| 49 | + for contract_name in crytic_compile.contracts_name: |
| 50 | + abi = str(crytic_compile.abi(contract_name)) |
| 51 | + abi = abi.replace('\'', '\"') |
| 52 | + abi = abi.replace('True', 'true') |
| 53 | + abi = abi.replace('False', 'false') |
| 54 | + abi = abi.replace(' ', '') |
| 55 | + exported_name = combine_filename_name(crytic_compile.contracts_filenames[contract_name], contract_name) |
| 56 | + contracts[exported_name] = { |
| 57 | + 'srcmap': '', |
| 58 | + 'srcmap-runtime': '', |
| 59 | + 'abi': abi, |
| 60 | + 'bin': crytic_compile.init_bytecode(contract_name), |
| 61 | + 'bin-runtime': crytic_compile.runtime_bytecode(contract_name) |
| 62 | + } |
| 63 | + |
| 64 | + sources = {filename : {"AST": ast} for (filename, ast) in crytic_compile.asts.items()} |
| 65 | + sourceList = crytic_compile.filenames |
| 66 | + |
| 67 | + output = {'sources' : sources, |
| 68 | + 'sourceList' : sourceList, |
| 69 | + 'contracts': contracts} |
| 70 | + |
| 71 | + json.dump(output, f) |
| 72 | + |
| 73 | +def is_dapp(target): |
| 74 | + """ |
| 75 | + Heuristic used: check if "dapp build" is present in Makefile |
| 76 | + :param target: |
| 77 | + :return: |
| 78 | + """ |
| 79 | + makefile = os.path.join(target, "Makefile") |
| 80 | + if os.path.isfile(makefile): |
| 81 | + with open(makefile) as f: |
| 82 | + txt = f.read() |
| 83 | + return "dapp build" in txt |
| 84 | + return False |
| 85 | + |
| 86 | +def _run_dapp(): |
| 87 | + cmd = ["dapp", "build"] |
| 88 | + |
| 89 | + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| 90 | + _, _ = process.communicate() |
0 commit comments