def _find_vyper_version(file: str) -> str: global _installed_vyper_versions if _installed_vyper_versions is None: _installed_vyper_versions = vvm.get_installed_vyper_versions() _installed_vyper_versions.append(_VYPER_VERSION) pragma_specs = _get_vyper_pragma_spec(file) version = pragma_specs.select(_installed_vyper_versions) if not version: global _available_vyper_versions if _available_vyper_versions is None: _available_vyper_versions = vvm.get_installable_vyper_versions() version = pragma_specs.select(_available_vyper_versions) if not version: raise InvalidVyperException( f"Invalid vyper version pragma: {pragma_specs}") lock = vvm.install.get_process_lock(f"locked${version}") with lock: try: _get_executable(version) except vvm.exceptions.VyperNotInstalled: vvm.install_vyper(version) if version not in _installed_vyper_versions: _installed_vyper_versions.append(version) return version
def _get_vyper_version_list() -> Tuple[List, List]: global AVAILABLE_VYPER_VERSIONS installed_versions = vvm.get_installed_vyper_versions() if AVAILABLE_VYPER_VERSIONS is None: try: AVAILABLE_VYPER_VERSIONS = vvm.get_installable_vyper_versions() except ConnectionError: if not installed_versions: raise ConnectionError( "Vyper not installed and cannot connect to GitHub") AVAILABLE_VYPER_VERSIONS = installed_versions return AVAILABLE_VYPER_VERSIONS, installed_versions
def pytest_collection(session): global VERSIONS if session.config.getoption("--vyper-versions"): VERSIONS = [ Version(i) for i in session.config.getoption("--vyper-versions").split(",") ] elif session.config.getoption("--no-install"): VERSIONS = vvm.get_installed_vyper_versions() else: try: VERSIONS = vvm.get_installable_vyper_versions() except ConnectionError: raise pytest.UsageError( "ConnectionError while attempting to get vyper versions.\n" "Use the --no-install flag to only run tests against already installed versions." ) for version in VERSIONS: vvm.install_vyper(version)
def download_all(max_workers): """Download all versions of solc and vyper.""" with spinner(): solc_versions = get_installable_solc_versions() vyper_versions = get_installable_vyper_versions() with ThreadPoolExecutor(max_workers=max_workers) as executor: futures = [ executor.submit(install_solc, version) for version in solc_versions ] futures.extend([ executor.submit(install_vyper, version) for version in vyper_versions ]) for _f in as_completed(futures): # TODO: check for errors pass print("All solc and vyper versions installed")
def available_versions(self) -> List[Version]: # NOTE: Package version should already be included in available versions return vvm.get_installable_vyper_versions()
def from_explorer( cls, address: str, as_proxy_for: Optional[str] = None, owner: Optional[AccountsType] = None, silent: bool = False, ) -> "Contract": """ Create a new `Contract` object with source code queried from a block explorer. Arguments --------- address : str Address where the contract is deployed. as_proxy_for : str, optional Address of the implementation contract, if `address` is a proxy contract. The generated object will send transactions to `address`, but use the ABI and NatSpec of `as_proxy_for`. This field is only required when the block explorer API does not provide an implementation address. owner : Account, optional Contract owner. If set, transactions without a `from` field will be performed using this account. """ address = _resolve_address(address) data = _fetch_from_explorer(address, "getsourcecode", silent) is_verified = bool(data["result"][0].get("SourceCode")) if is_verified: abi = json.loads(data["result"][0]["ABI"]) name = data["result"][0]["ContractName"] else: # if the source is not available, try to fetch only the ABI try: data_abi = _fetch_from_explorer(address, "getabi", True) except ValueError as exc: _unverified_addresses.add(address) raise exc abi = json.loads(data_abi["result"].strip()) name = "UnknownContractName" warnings.warn( f"{address}: Was able to fetch the ABI but not the source code. " "Some functionality will not be available.", BrownieCompilerWarning, ) if as_proxy_for is None and data["result"][0].get("Implementation"): try: # many proxy patterns use an `implementation()` function, so first we # try to determine the implementation address without trusting etherscan contract = cls.from_abi(name, address, abi) as_proxy_for = contract.implementation() except Exception: as_proxy_for = _resolve_address(data["result"][0]["Implementation"]) if as_proxy_for == address: as_proxy_for = None # if this is a proxy, fetch information for the implementation contract if as_proxy_for is not None: implementation_contract = Contract.from_explorer(as_proxy_for) abi = implementation_contract._build["abi"] if not is_verified: return cls.from_abi(name, address, abi, owner) compiler_str = data["result"][0]["CompilerVersion"] if compiler_str.startswith("vyper:"): try: version = to_vyper_version(compiler_str[6:]) is_compilable = version in get_installable_vyper_versions() except Exception: is_compilable = False else: try: version = Version(compiler_str.lstrip("v")).truncate() is_compilable = ( version >= Version("0.4.22") and version in solcx.get_installable_solc_versions() + solcx.get_installed_solc_versions() ) except Exception: is_compilable = False if not is_compilable: if not silent: warnings.warn( f"{address}: target compiler '{compiler_str}' cannot be installed or is not " "supported by Brownie. Some debugging functionality will not be available.", BrownieCompilerWarning, ) return cls.from_abi(name, address, abi, owner) optimizer = { "enabled": bool(int(data["result"][0]["OptimizationUsed"])), "runs": int(data["result"][0]["Runs"]), } evm_version = data["result"][0].get("EVMVersion", "Default") if evm_version == "Default": evm_version = None source_str = "\n".join(data["result"][0]["SourceCode"].splitlines()) if source_str.startswith("{{"): # source was verified using compiler standard JSON input_json = json.loads(source_str[1:-1]) sources = {k: v["content"] for k, v in input_json["sources"].items()} evm_version = input_json["settings"].get("evmVersion", evm_version) compiler.set_solc_version(str(version)) input_json.update( compiler.generate_input_json(sources, optimizer=optimizer, evm_version=evm_version) ) output_json = compiler.compile_from_input_json(input_json) build_json = compiler.generate_build_json(input_json, output_json) else: if source_str.startswith("{"): # source was submitted as multiple files sources = {k: v["content"] for k, v in json.loads(source_str).items()} else: # source was submitted as a single file if compiler_str.startswith("vyper"): path_str = f"{name}.vy" else: path_str = f"{name}-flattened.sol" sources = {path_str: source_str} build_json = compiler.compile_and_format( sources, solc_version=str(version), vyper_version=str(version), optimizer=optimizer, evm_version=evm_version, ) build_json = build_json[name] if as_proxy_for is not None: build_json.update(abi=abi, natspec=implementation_contract._build.get("natspec")) if not _verify_deployed_code( address, build_json["deployedBytecode"], build_json["language"] ): warnings.warn( f"{address}: Locally compiled and on-chain bytecode do not match!", BrownieCompilerWarning, ) del build_json["pcMap"] self = cls.__new__(cls) _ContractBase.__init__(self, None, build_json, sources) # type: ignore _DeployedContractBase.__init__(self, address, owner) _add_deployment(self) return self