Source code for crytic_compile.platform.etherlime

"""
Etherlime platform. https://github.com/LimeChain/etherlime
"""

import os
import json
import logging
import subprocess
import glob
import re
from pathlib import Path
from typing import TYPE_CHECKING, Optional, List

from crytic_compile.platform.abstract_platform import AbstractPlatform
from crytic_compile.platform.types import Type
from crytic_compile.platform.exceptions import InvalidCompilation
from crytic_compile.utils.naming import convert_filename
from crytic_compile.compiler.compiler import CompilerVersion

# Cycle dependency
from crytic_compile.utils.natspec import Natspec

if TYPE_CHECKING:
    from crytic_compile import CryticCompile

LOGGER = logging.getLogger("CryticCompile")


[docs]class Etherlime(AbstractPlatform): """ Etherlime platform """ NAME = "Etherlime" PROJECT_URL = "https://github.com/LimeChain/etherlime" TYPE = Type.ETHERLIME
[docs] def compile(self, crytic_compile: "CryticCompile", **kwargs: str): """ Compile the target :param crytic_compile: :param target: :param kwargs: :return: """ etherlime_ignore_compile = kwargs.get("etherlime_ignore_compile", False) or kwargs.get( "ignore_compile", False ) build_directory = "build" compile_arguments = kwargs.get("etherlime_compile_arguments", None) if not etherlime_ignore_compile: cmd = ["etherlime", "compile", self._target, "deleteCompiledFiles=true"] if not kwargs.get("npx_disable", False): cmd = ["npx"] + cmd if compile_arguments: cmd += compile_arguments.split(" ") try: process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError as error: raise InvalidCompilation(error) stdout_bytes, stderr_bytes = process.communicate() stdout, stderr = ( stdout_bytes.decode(), stderr_bytes.decode(), ) # convert bytestrings to unicode strings LOGGER.info(stdout) if stderr: LOGGER.error(stderr) # similar to truffle if not os.path.isdir(os.path.join(self._target, build_directory)): raise InvalidCompilation( "No truffle build directory found, did you run `truffle compile`?" ) filenames = glob.glob(os.path.join(self._target, build_directory, "*.json")) version = None compiler = "solc-js" for file in filenames: with open(file, encoding="utf8") as file_desc: target_loaded = json.load(file_desc) if version is None: if "compiler" in target_loaded: if "version" in target_loaded["compiler"]: version = re.findall( r"\d+\.\d+\.\d+", target_loaded["compiler"]["version"] )[0] if not "ast" in target_loaded: continue filename_txt = target_loaded["ast"]["absolutePath"] filename = convert_filename(filename_txt, _relative_to_short, crytic_compile) crytic_compile.asts[filename.absolute] = target_loaded["ast"] crytic_compile.filenames.add(filename) contract_name = target_loaded["contractName"] crytic_compile.contracts_filenames[contract_name] = filename crytic_compile.contracts_names.add(contract_name) crytic_compile.abis[contract_name] = target_loaded["abi"] crytic_compile.bytecodes_init[contract_name] = target_loaded["bytecode"].replace( "0x", "" ) crytic_compile.bytecodes_runtime[contract_name] = target_loaded[ "deployedBytecode" ].replace("0x", "") crytic_compile.srcmaps_init[contract_name] = target_loaded["sourceMap"].split(";") crytic_compile.srcmaps_runtime[contract_name] = target_loaded[ "deployedSourceMap" ].split(";") userdoc = target_loaded.get("userdoc", {}) devdoc = target_loaded.get("devdoc", {}) natspec = Natspec(userdoc, devdoc) crytic_compile.natspec[contract_name] = natspec crytic_compile.compiler_version = CompilerVersion( compiler=compiler, version=version, optimized=_is_optimized(compile_arguments) )
[docs] @staticmethod def is_supported(target: str, **kwargs: str) -> bool: """ Check if the target is an etherlime project :param target: :return: """ etherlime_ignore = kwargs.get("etherlime_ignore", False) if etherlime_ignore: return False if os.path.isfile(os.path.join(target, "package.json")): with open("package.json", encoding="utf8") as file_desc: package = json.load(file_desc) if "dependencies" in package: return ( "etherlime-lib" in package["dependencies"] or "etherlime" in package["dependencies"] ) return False
[docs] def is_dependency(self, path: str) -> bool: """ Check if the path is a dependency :param path: :return: """ return "node_modules" in Path(path).parts
def _guessed_tests(self) -> List[str]: """ Guess the potential unit tests commands :return: """ return ["etherlime test"]
def _is_optimized(compile_arguments: Optional[str]) -> bool: """ Check if the optimization is enabled :param compile_arguments: :return: """ if compile_arguments: return "--run" in compile_arguments return False def _relative_to_short(relative: Path) -> Path: """ Translate relative to short :param relative: :return: """ short = relative try: short = short.relative_to(Path("contracts")) except ValueError: try: short = short.relative_to("node_modules") except ValueError: pass return short