Source code for erc7730.convert.calldata.v1.selector
"""
Conversion of an ERC-7730 descriptor to a calldata descriptor (for a single chain + selector).
"""
import hashlib
from typing import cast
from eth_typing import ChainId as EthChainId
from pydantic_string_url import HttpUrl
from erc7730.common.binary import from_hex
from erc7730.common.ledger import ledger_network_id
from erc7730.common.options import first_not_none
from erc7730.common.output import OutputAdder
from erc7730.convert.calldata.v1.abi import function_to_abi_tree
from erc7730.convert.calldata.v1.enum import convert_enums
from erc7730.convert.calldata.v1.field import convert_field
from erc7730.model.abi import Function
from erc7730.model.calldata.descriptor import (
CalldataDescriptor,
CalldataDescriptorV1,
)
from erc7730.model.calldata.v1.instruction import (
CalldataDescriptorInstructionTransactionInfoV1,
)
from erc7730.model.resolved.context import ResolvedDeployment
from erc7730.model.resolved.descriptor import ResolvedERC7730Descriptor
from erc7730.model.resolved.display import ResolvedFormat
from erc7730.model.types import Selector
[docs]
def convert_selector(
descriptor: ResolvedERC7730Descriptor,
deployment: ResolvedDeployment,
selector: Selector,
format: ResolvedFormat,
abi: Function,
source: HttpUrl | None,
out: OutputAdder,
) -> CalldataDescriptor | None:
"""
Generate output calldata descriptor for a single selector ("format" in ERC-7730 source descriptor).
If descriptor is invalid, None is returned. Errors are logged to the console.
:param descriptor: resolved source ERC-7730 descriptor
:param deployment: chain id / contract address for which the descriptor is generated
:param selector: function for which the descriptor is generated
:param format: ERC-7730 format for the selector
:param abi: ABI of the function
:param source: source of the descriptor file
:param out: error handler
:return: output calldata descriptors (1 per chain + selector)
"""
abi_tree = function_to_abi_tree(abi)
creator_legal_name: str | None = None
creator_url: str | None = None
deploy_date: str | None = None
if (owner_info := descriptor.metadata.info) is not None:
creator_legal_name = owner_info.legalName
creator_url = owner_info.url
deploy_date = owner_info.deploymentDate.strftime("%Y-%m-%dT%H:%M:%SZ") if owner_info.deploymentDate else None
enums = convert_enums(deployment, selector, descriptor.metadata.enums)
enums_by_id = {enum.enum_id: enum.id for enum in enums}
fields = []
for input_field in format.fields:
if (output_fields := convert_field(abi=abi_tree, field=input_field, enums=enums_by_id, out=out)) is None:
return None
fields.extend(output_fields)
hash = hashlib.sha3_256()
for field in fields:
hash.update(from_hex(field.descriptor))
transaction_info = CalldataDescriptorInstructionTransactionInfoV1(
chain_id=EthChainId(deployment.chainId),
address=deployment.address,
selector=selector,
hash=hash.digest().hex(),
operation_type=first_not_none(format.intent, format.id, selector), # type:ignore
creator_name=descriptor.metadata.owner,
creator_legal_name=creator_legal_name,
creator_url=creator_url,
contract_name=descriptor.context.id,
deploy_date=deploy_date,
)
return CalldataDescriptorV1(
source=source,
network=cast(str, ledger_network_id(deployment.chainId)),
chain_id=EthChainId(deployment.chainId),
address=deployment.address,
selector=selector,
transaction_info=transaction_info,
enums=enums,
fields=fields,
)