Source code for erc7730.lint.lint_validate_abi

from typing import final, override

from erc7730.common import client
from erc7730.common.abi import compute_signature, get_functions
from erc7730.common.output import OutputAdder
from erc7730.lint import ERC7730Linter
from erc7730.model.resolved.context import ResolvedContractContext, ResolvedEIP712Context
from erc7730.model.resolved.descriptor import ResolvedERC7730Descriptor


[docs] @final class ValidateABILinter(ERC7730Linter): """ - resolves the ABI from the descriptor (URL or provided) - resolves the ABI from *scan (given chainId and address of descriptor) - => compares the two ABIs """
[docs] @override def lint(self, descriptor: ResolvedERC7730Descriptor, out: OutputAdder) -> None: if isinstance(descriptor.context, ResolvedEIP712Context): return self._validate_eip712_schemas(descriptor.context, out) if isinstance(descriptor.context, ResolvedContractContext): return self._validate_contract_abis(descriptor.context, out) raise ValueError("Invalid context type")
@classmethod def _validate_eip712_schemas(cls, context: ResolvedEIP712Context, out: OutputAdder) -> None: pass # not implemented @classmethod def _validate_contract_abis(cls, context: ResolvedContractContext, out: OutputAdder) -> None: if not isinstance(context.contract.abi, list): raise ValueError("Contract ABIs should have been resolved") if (deployments := context.contract.deployments) is None: return for deployment in deployments: try: if (abis := client.get_contract_abis(deployment.chainId, deployment.address)) is None: continue except Exception as e: out.warning( title="Could not fetch ABI", message=f"Fetching reference ABI for chain id {deployment.chainId} failed, descriptor ABIs will " f"not be validated: {e}", ) continue reference_abis = get_functions(abis) descriptor_abis = get_functions(context.contract.abi) url = client.get_contract_explorer_url(deployment.chainId, deployment.address) if reference_abis.proxy: return out.info( title="Proxy contract", message=f"Contract {url} is likely to be a proxy, validation of descriptor ABIs skipped", ) for selector, abi in descriptor_abis.functions.items(): if selector not in reference_abis.functions: out.warning( title="Extra function", message=f"Function {compute_signature(abi)} (selector: {selector}) defined in descriptor ABIs " f"does not exist in reference ABI (see {url})", ) elif descriptor_abis.functions[selector] != reference_abis.functions[selector]: out.warning( title="Function mismatch", message=f"Function {compute_signature(abi)} (selector: {selector}) defined in descriptor ABIs " f"does not match reference ABI (see {url})", )