def test_builder_raises_exception_if_selected_contract_type_missing_from_solc( owned_package): _, _, compiler_output = owned_package with pytest.raises(ManifestBuildingError): build( BASE_MANIFEST, contract_type("Owned", compiler_output, abi=True, natspec=True), )
def generate_basic_manifest(package_name: str, version: str, project_dir: Path) -> None: manifest = create_basic_manifest_from_solc_output(package_name, version, project_dir) builder_fns = (b.validate(), b.write_to_disk(project_dir)) b.build(manifest, *builder_fns) cli_logger.info( f"Manifest successfully created and written to {project_dir}/{manifest['version']}.json." )
def test_builder_with_manifest_validation(): with pytest.raises(ValidationError, match="_invalid_package_name"): build( {}, package_name("_invalid_package_name"), manifest_version("2"), version("1.0.0"), validate(), )
def test_to_disk_with_invalid_args_raises_exception(manifest_dir, write_to_disk_fn): with pytest.raises(ManifestBuildingError): build( {}, package_name("package"), manifest_version("2"), version("1.0.0"), write_to_disk_fn, )
def test_builder_with_invalid_uri(): with pytest.raises(ValidationError, match="is not a supported content-addressed URI"): build( {}, package_name("package"), version("1.0.0"), manifest_version("2"), build_dependency("package", "www.google.com"), )
def test_to_disk_uses_default_manifest_name(manifest_dir): build( {}, package_name("package"), manifest_version("2"), version("1.0.0"), write_to_disk(manifest_root_dir=manifest_dir), ) actual_manifest = (manifest_dir / "1.0.0.json").read_text() assert actual_manifest == MINIFIED_MANIFEST
def test_builder_to_disk_uses_default_cwd(manifest_dir, monkeypatch): monkeypatch.chdir(manifest_dir) build( {}, package_name("package"), manifest_version("2"), version("1.0.0"), write_to_disk(), ) actual_manifest = (manifest_dir / "1.0.0.json").read_text() assert actual_manifest == MINIFIED_MANIFEST
def test_builder_raises_exception_if_selected_contract_type_missing_from_solc( owned_package): _, _, compiler_output = owned_package with pytest.raises(ManifestBuildingError, match="runtimeBytecode not available"): build( BASE_MANIFEST, contract_type("Owned", compiler_output, abi=True, runtime_bytecode=True), )
def test_to_disk_writes_minified_manifest_as_default(manifest_dir): build( {}, package_name("package"), manifest_version("ethpm/3"), version("1.0.0"), write_to_disk(manifest_root_dir=manifest_dir, manifest_name="1.0.0.json"), validate(), ) actual_manifest = (manifest_dir / "1.0.0.json").read_text() assert actual_manifest == MINIFIED_MANIFEST
def test_builder_writes_manifest_to_disk(manifest_dir): build( {}, package_name("package"), manifest_version("2"), version("1.0.0"), write_to_disk(manifest_root_dir=manifest_dir, manifest_name="1.0.0.json", prettify=True), ) actual_manifest = (manifest_dir / "1.0.0.json").read_text() assert actual_manifest == PRETTY_MANIFEST
def twig_deployer(compiler, w3): # Return a Deployer containing all .vy contracts found sources = compiler.get_source_tree() contract_types = compiler.get_contract_types() pkg = b.build(b.init_manifest("twig", "1.0.0"), *sources, *contract_types, b.as_package(w3)) return Deployer(pkg)
def test_builder_simple_with_multi_meta_field(): manifest = build( BASE_MANIFEST, authors("some", "guy"), license("MIT"), description("description"), keywords("awesome", "package"), links(website="www", repository="github"), validate(), ) expected = assoc( BASE_MANIFEST, "meta", { "license": "MIT", "authors": ["some", "guy"], "description": "description", "keywords": ["awesome", "package"], "links": { "website": "www", "repository": "github" }, }, ) assert manifest == expected
def fetch_uri_contents(self, uri: URI, package_name: str, package_version: str) -> URI: manifest = build_etherscan_manifest(uri, package_name, package_version) ipfs_backend = get_ipfs_backend() ipfs_data = builder.build(manifest, builder.validate(), builder.pin_to_ipfs(backend=ipfs_backend)) return URI(f"ipfs://{ipfs_data[0]['Hash']}")
def test_builder_deployment_simple(w3): expected = json.dumps({ "package_name": "package", "version": "1.0.0", "manifest_version": "2", "deployments": { "blockchain://1234567890123456789012345678901234567890123456789012345678901234/block/1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef": { # noqa: E501 "Owned": { "contract_type": "Owned", "address": "0xd3CdA913deB6f67967B99D67aCDFa1712C293601", } } }, }) manifest = build( BASE_MANIFEST, deployment( block_uri= "blockchain://1234567890123456789012345678901234567890123456789012345678901234/block/1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", # noqa: E501 contract_instance="Owned", contract_type="Owned", address=to_canonical_address( "0xd3cda913deb6f67967b99d67acdfa1712c293601"), ), ) assert manifest == json.loads(expected)
def test_builder_with_alias_and_select_contract_types(owned_package_devdoc): _, _, compiler_output = owned_package_devdoc manifest = build( BASE_MANIFEST, contract_type( "Owned", compiler_output, alias="OwnedAlias", abi=True, natspec=True, deployment_bytecode=True, runtime_bytecode=True, compiler=True, ), validate(), ) contract_type_data = normalize_contract_type( compiler_output["Owned.sol"]["Owned"]) expected = assoc( BASE_MANIFEST, "contract_types", {"OwnedAlias": assoc(contract_type_data, "contract_type", "Owned")}, ) assert manifest == expected
def test_builder_deployment_type_complex(escrow_package): escrow, w3 = escrow_package escrow_dep_type = deployment_type( contract_instance="Escrow", contract_type="Escrow", deployment_bytecode={ "bytecode": "0x608060405234801561001057600080fd5b5060405160208061045383398101604081815291516002819055336000818152602081815285822084905583855294519294919390927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3506103d2806100816000396000f3006080604052600436106100775763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663095ea7b3811461007c57806318160ddd146100b457806323b872dd146100db57806370a0823114610105578063a9059cbb14610126578063dd62ed3e1461014a575b600080fd5b34801561008857600080fd5b506100a0600160a060020a0360043516602435610171565b604080519115158252519081900360200190f35b3480156100c057600080fd5b506100c96101d8565b60408051918252519081900360200190f35b3480156100e757600080fd5b506100a0600160a060020a03600435811690602435166044356101de565b34801561011157600080fd5b506100c9600160a060020a03600435166102c9565b34801561013257600080fd5b506100a0600160a060020a03600435166024356102e4565b34801561015657600080fd5b506100c9600160a060020a036004358116906024351661037b565b336000818152600160209081526040808320600160a060020a038716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a35060015b92915050565b60025481565b600160a060020a03831660009081526020819052604081205482118015906102295750600160a060020a03841660009081526001602090815260408083203384529091529020548211155b80156102355750600082115b156102be57600160a060020a0380841660008181526020818152604080832080548801905593881680835284832080548890039055600182528483203384528252918490208054879003905583518681529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35060016102c2565b5060005b9392505050565b600160a060020a031660009081526020819052604090205490565b3360009081526020819052604081205482118015906103035750600082115b15610373573360008181526020818152604080832080548790039055600160a060020a03871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a35060016101d2565b5060006101d2565b600160a060020a039182166000908152600160209081526040808320939094168252919091522054905600a165627a7a72305820cf9d6a3f751ca1e6b9bc2324e42633a4cde513d64c3e6cc32d6359629249e90200290000000000000000000000000000000000000000000000000000000000000001" # noqa: E501 }, runtime_bytecode={ "bytecode": "0x6080604052600436106100775763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663095ea7b3811461007c57806318160ddd146100b457806323b872dd146100db57806370a0823114610105578063a9059cbb14610126578063dd62ed3e1461014a575b600080fd5b34801561008857600080fd5b506100a0600160a060020a0360043516602435610171565b604080519115158252519081900360200190f35b3480156100c057600080fd5b506100c96101d8565b60408051918252519081900360200190f35b3480156100e757600080fd5b506100a0600160a060020a03600435811690602435166044356101de565b34801561011157600080fd5b506100c9600160a060020a03600435166102c9565b34801561013257600080fd5b506100a0600160a060020a03600435166024356102e4565b34801561015657600080fd5b506100c9600160a060020a036004358116906024351661037b565b336000818152600160209081526040808320600160a060020a038716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a35060015b92915050565b60025481565b600160a060020a03831660009081526020819052604081205482118015906102295750600160a060020a03841660009081526001602090815260408083203384529091529020548211155b80156102355750600082115b156102be57600160a060020a0380841660008181526020818152604080832080548801905593881680835284832080548890039055600182528483203384528252918490208054879003905583518681529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35060016102c2565b5060005b9392505050565b600160a060020a031660009081526020819052604090205490565b3360009081526020819052604081205482118015906103035750600082115b15610373573360008181526020818152604080832080548790039055600160a060020a03871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a35060016101d2565b5060006101d2565b600160a060020a039182166000908152600160209081526040808320939094168252919091522054905600a165627a7a72305820cf9d6a3f751ca1e6b9bc2324e42633a4cde513d64c3e6cc32d6359629249e9020029" # noqa: E501 }, compiler={ "name": "solc", "version": "0.4.24+commit.e67f0147.Emscripten.clang", "settings": { "optimize": True }, }, ) safesendlib_dep_type = deployment_type(contract_instance="SafeSendLib", contract_type="SafeSendLib") manifest = build( {}, package_name("escrow"), version("1.0.0"), manifest_version("ethpm/3"), escrow_dep_type( block_uri= "blockchain://1111111111111111111111111111111111111111111111111111111111111111/block/1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", # noqa: E501 address=escrow.deployments.get_instance("Escrow").address, ), # dep_type with block uri safesendlib_dep_type( block_uri= "blockchain://1111111111111111111111111111111111111111111111111111111111111111/block/1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", # noqa: E501 address=escrow.deployments.get_instance("SafeSendLib").address, ), # simple deployment deployment( block_uri= "blockchain://1234567890123456789012345678901234567890123456789012345678901234/block/1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", # noqa: E501 contract_instance="Escrow", contract_type="Escrow", address=escrow.deployments.get_instance("Escrow").address, ), # simple deployment deployment( block_uri= "blockchain://1234567890123456789012345678901234567890123456789012345678901234/block/1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", # noqa: E501 contract_instance="SafeSendLib", contract_type="SafeSendLib", address=escrow.deployments.get_instance("SafeSendLib").address, ), validate(), ) assert len(manifest["deployments"].keys()) == 2 assert len(list(manifest["deployments"].values())[0]) == 2 assert len(list(manifest["deployments"].values())[1]) == 2
def generate_custom_manifest(project_dir: Path) -> None: cli_logger.info(f"{bold_blue('Manifest Wizard')}") cli_logger.info("---------------") cli_logger.info("Create ethPM manifests for local projects.") contracts_dir = project_dir / "contracts" validate_solc_output(project_dir) solc_output_path = project_dir / SOLC_OUTPUT solc_output = json.loads(solc_output_path.read_text())["contracts"] builder_fns = ( gen_package_name(), gen_version(), gen_manifest_version(), gen_description(), gen_license(), gen_authors(), gen_keywords(), gen_links(), *gen_contract_types_and_sources(solc_output, contracts_dir), *gen_deployments(solc_output), # todo: *gen_build_dependencies(), # todo: ipfs pinning support gen_validate_manifest(), ) final_fns = (fn for fn in builder_fns if fn is not None) cli_logger.info( "Building your manifest. This could take a minute if you're pinning assets to IPFS." ) manifest = b.build({}, *final_fns) write_manifest_to_disk(manifest, project_dir)
def test_builder_with_standard_token_manifest(standard_token_package, dummy_ipfs_backend, monkeypatch): root, expected_manifest, compiler_output = standard_token_package ipfs_backend = get_ipfs_backend() monkeypatch.chdir(root) manifest = build( {}, package_name("standard-token"), manifest_version("ethpm/3"), version("1.0.0"), pin_source("StandardToken", compiler_output, ipfs_backend), pin_source("Token", compiler_output, ipfs_backend), contract_type("StandardToken", compiler_output, abi=True, devdoc=True, source_id=True), contract_type("Token", compiler_output, abi=True, devdoc=True, userdoc=True, source_id=True), validate(), ) assert manifest == expected_manifest
def check_manifest(manifest: Manifest) -> Dict[str, str]: generate_warnings = ( check_manifest_version(manifest), check_package_name(manifest), check_version(manifest), check_meta(manifest), check_sources(manifest), check_contract_types(manifest), ) return build({}, *generate_warnings)
def test_builder_simple_with_package(w3): package = build( {}, package_name("package"), manifest_version("2"), version("1.0.0"), as_package(w3), ) assert isinstance(package, Package) assert package.version == "1.0.0"
def test_builder_with_default_contract_types(owned_package): _, _, compiler_output = owned_package manifest = build(BASE_MANIFEST, contract_type("Owned", compiler_output), validate()) contract_type_data = normalize_contract_type( compiler_output["Owned.sol"]["Owned"]) expected = assoc(BASE_MANIFEST, "contract_types", {"Owned": contract_type_data}) assert manifest == expected
def check_meta(manifest: Manifest, warnings: Dict[str, str]) -> Dict[str, str]: if "meta" not in manifest or not manifest["meta"]: return assoc(warnings, "meta", WARNINGS["meta_missing"]) meta_validation = ( check_authors(manifest["meta"]), check_license(manifest["meta"]), check_description(manifest["meta"]), check_keywords(manifest["meta"]), check_links(manifest["meta"]), ) return build(warnings, *meta_validation)
def test_builder_with_single_build_dependency(): expected_build_dep = { "package": "ipfs://QmUYcVzTfSwJoigggMxeo2g5STWAgJdisQsqcXHws7b1FW" } expected = assoc_in(BASE_MANIFEST, ["build_dependencies"], expected_build_dep) actual = build( BASE_MANIFEST, build_dependency( "package", "ipfs://QmUYcVzTfSwJoigggMxeo2g5STWAgJdisQsqcXHws7b1FW"), ) assert actual == expected
def check_runtime_bytecode(contract_name: str, data: Dict[str, Any], warnings: Dict[str, str]) -> Dict[str, str]: if "runtime_bytecode" not in data or not data["runtime_bytecode"]: return assoc_in( warnings, ["contract_types", contract_name, "runtime_bytecode"], WARNINGS["runtime_bytecode_missing"].format(contract_name), ) return build( warnings, check_bytecode_object(contract_name, "runtime", data["runtime_bytecode"]), )
def get_simple_manifest(self, name: str, version: str) -> Manifest: composed_contract_types = self.get_contract_types() composed_inline_sources = self.get_source_tree() manifest = b.build( {}, b.package_name(name), b.version(version), b.manifest_version("2"), *composed_inline_sources, *composed_contract_types, b.validate(), ) return manifest
def test_builder_with_default_contract_types(owned_package): _, _, compiler_output = owned_package manifest = build(BASE_MANIFEST, contract_type("Owned", compiler_output), validate()) contract_type_data = normalize_contract_type( compiler_output["Owned.sol"]["Owned"], "Owned.sol") compilers_data = contract_type_data.pop('compiler') compilers_data["contractTypes"] = ["Owned"] expected_with_contract_type = assoc(BASE_MANIFEST, "contractTypes", {"Owned": contract_type_data}) expected = assoc(expected_with_contract_type, "compilers", [compilers_data]) assert manifest == expected
def check_contract_types(manifest: Manifest, warnings: Dict[str, str]) -> Dict[str, str]: if "contract_types" not in manifest or not manifest["contract_types"]: return assoc(warnings, "contract_types", WARNINGS["contract_type_missing"]) all_contract_type_validations = (( check_abi(contract_name, data), check_contract_type(contract_name, data), check_deployment_bytecode(contract_name, data), check_runtime_bytecode(contract_name, data), check_natspec(contract_name, data), check_compiler(contract_name, data), ) for contract_name, data in manifest["contract_types"].items()) return build(warnings, *sum(all_contract_type_validations, ()))
def test_builder_without_alias_and_with_select_contract_types(owned_package): _, _, compiler_output = owned_package manifest = build(BASE_MANIFEST, contract_type("Owned", compiler_output, abi=True), validate()) contract_type_data = normalize_contract_type( compiler_output["Owned.sol"]["Owned"]) selected_data = { k: v for k, v in contract_type_data.items() if k != "deployment_bytecode" } expected = assoc(BASE_MANIFEST, "contract_types", {"Owned": selected_data}) assert manifest == expected
def test_builder_with_multiple_build_dependencies(): expected_build_deps = { "escrow": "ipfs://QmPDwMHk8e1aMEZg3iKsUiPSkhHkywpGB3KHKM52RtGrkv", "package": "ipfs://QmUYcVzTfSwJoigggMxeo2g5STWAgJdisQsqcXHws7b1FW", } expected = assoc_in(BASE_MANIFEST, ["build_dependencies"], expected_build_deps) actual = build( BASE_MANIFEST, build_dependency( "package", "ipfs://QmUYcVzTfSwJoigggMxeo2g5STWAgJdisQsqcXHws7b1FW"), build_dependency( "escrow", "ipfs://QmPDwMHk8e1aMEZg3iKsUiPSkhHkywpGB3KHKM52RtGrkv"), ) assert actual == expected
def test_builder_pins_manifest_to_provided_ipfs_backend(backend): if not pytest.config.getoption("--integration"): pytest.skip("Not asked to run integration tests") minified_manifest_hash = "QmVwwpt2BAkmWQt4eNnswhWd6bYgLbnUQDMHdVMHotwiqz" (manifest, ) = b.build( {}, b.package_name("package"), b.manifest_version("2"), b.version("1.0.0"), b.pin_to_ipfs(backend=backend), ) assert manifest["Hash"] == minified_manifest_hash pinned_manifest = backend.fetch_uri_contents(manifest["Hash"]) assert ( pinned_manifest == b'{"manifest_version":"2","package_name":"package","version":"1.0.0"}')