diff --git a/wake/compiler/compiler.py b/wake/compiler/compiler.py index de90b9db..7ee56bb3 100644 --- a/wake/compiler/compiler.py +++ b/wake/compiler/compiler.py @@ -82,6 +82,7 @@ from .exceptions import CompilationError, CompilationResolveError from .solc_frontend import ( SolcFrontend, + SolcInputMetadataSettings, SolcInputOptimizerDetailsSettings, SolcInputOptimizerSettings, SolcInputOptimizerYulDetailsSettings, @@ -621,6 +622,11 @@ def create_build_settings( simple_counter_for_loop_unchecked_increment=solc_settings.optimizer.details.simple_counter_for_loop_unchecked_increment, ), ) + settings.metadata = SolcInputMetadataSettings( + append_CBOR=solc_settings.metadata.append_CBOR, + use_literal_content=solc_settings.metadata.use_literal_content, + bytecode_hash=solc_settings.metadata.bytecode_hash, + ) if ( solc_settings.optimizer.details.yul_details.stack_allocation is not None diff --git a/wake/compiler/solc_frontend/input_data_model.py b/wake/compiler/solc_frontend/input_data_model.py index 89a60c40..5ef3ce4d 100644 --- a/wake/compiler/solc_frontend/input_data_model.py +++ b/wake/compiler/solc_frontend/input_data_model.py @@ -130,6 +130,7 @@ def _to_camel(s: str) -> str: class SolcInputModel(BaseModel): model_config = ConfigDict( alias_generator=_to_camel, + populate_by_name=True, extra="allow", protected_namespaces=(), ) @@ -206,6 +207,7 @@ class SolcInputDebugSettings(SolcInputModel): class SolcInputMetadataSettings(SolcInputModel): + append_CBOR: Optional[bool] = Field(None, alias="appendCBOR") use_literal_content: Optional[bool] = None bytecode_hash: Optional[MetadataBytecodeHashEnum] = None diff --git a/wake/config/data_model.py b/wake/config/data_model.py index 085d4f3a..f5afc758 100644 --- a/wake/config/data_model.py +++ b/wake/config/data_model.py @@ -94,6 +94,18 @@ class SolcOptimizerConfig(WakeConfigModel): ) +class MetadataBytecodeHashEnum(StrEnum): + NONE = "none" + IPFS = "ipfs" + BZZR1 = "bzzr1" + + +class SolcMetadataConfig(WakeConfigModel): + append_CBOR: Optional[bool] = None + use_literal_content: Optional[bool] = None + bytecode_hash: Optional[MetadataBytecodeHashEnum] = None + + def convert_remapping(v): if isinstance(v, SolcRemapping): return v @@ -159,6 +171,10 @@ class SolcConfig(WakeConfigModel): """ Use new IR-based compiler pipeline. """ + metadata: SolcMetadataConfig = Field(default_factory=SolcMetadataConfig) + """ + Metadata config options. + """ _normalize_paths = field_validator("allow_paths", "include_paths", "exclude_paths", mode="before")(normalize_paths) @@ -173,6 +189,7 @@ class SubprojectConfig(WakeConfigModel): evm_version: Optional[EvmVersionEnum] = None optimizer: SolcOptimizerConfig = Field(default_factory=SolcOptimizerConfig) via_IR: Optional[bool] = None + metadata: SolcMetadataConfig = Field(default_factory=SolcMetadataConfig) _normalize_paths = field_validator("paths", mode="before")(normalize_paths) diff --git a/wake/development/core.py b/wake/development/core.py index fa0033f2..a19c0b3d 100644 --- a/wake/development/core.py +++ b/wake/development/core.py @@ -2851,7 +2851,8 @@ def get_fqn_from_address( addr: Address, block_number: Union[int, str], chain: Chain ) -> Optional[str]: code = chain.chain_interface.get_code(str(addr), block_number) - metadata = code[-53:] + metadata_length = int.from_bytes(code[-2:], "big") + metadata = code[-metadata_length - 2 : -2] if metadata in contracts_by_metadata: return contracts_by_metadata[metadata] else: diff --git a/wake/development/pytypes_generator.py b/wake/development/pytypes_generator.py index 31ae3f56..a87fe8ab 100644 --- a/wake/development/pytypes_generator.py +++ b/wake/development/pytypes_generator.py @@ -55,7 +55,7 @@ ) from wake.ir.enums import ContractKind, FunctionKind, StateMutability, Visibility from wake.ir.reference_resolver import ReferenceResolver -from wake.utils import get_package_version +from wake.utils import get_package_version, is_relative_to from .constants import DEFAULT_IMPORTS, INIT_CONTENT, TAB_WIDTH @@ -552,11 +552,31 @@ def generate_contract_template( index, ) - if len(compilation_info.evm.deployed_bytecode.object) > 0: + config = next( + ( + config + for config in self.__config.subproject.values() + if any( + is_relative_to(contract.source_unit.file, p) for p in config.paths + ) + ), + self.__config.compiler.solc, + ) + + if ( + len(compilation_info.evm.deployed_bytecode.object) > 0 + and config.metadata.append_CBOR != False + and config.metadata.bytecode_hash != "none" + ): + metadata_length = int.from_bytes( + bytes.fromhex(compilation_info.evm.deployed_bytecode.object[-4:]), + "big", + ) metadata = bytes.fromhex( - compilation_info.evm.deployed_bytecode.object[-106:] + compilation_info.evm.deployed_bytecode.object[ + -metadata_length * 2 - 4 : -4 + ] ) - assert len(metadata) == 53 assert metadata not in self.__contracts_by_metadata_index self.__contracts_by_metadata_index[metadata] = fqn